当前位置: 首页 > news >正文

arm64函数源码和汇编解析(objdump)

简单无参数的例子: 

gcc -g a.c

objdump -d a.out

 get_xx函数:

0000000000400634 <get_xx>:400634:	a9be7bfd 	stp	x29, x30, [sp, #-32]!  //stp指令将x29,x30保存在sp-32地址,后面的!,是完成后将sp-32的地址值给sp。意味着sp向地地址移动400638:	910003fd 	mov	x29, sp          //将sp的值保存到x29寄存器。40063c:	d2800100 	mov	x0, #0x8                   	// #8400640:	97ffffac 	bl	4004f0 <malloc@plt>       //调malloc函数,返回的地址保存到x0寄存器。也就是get_xx返回的地址。400644:	f9000fe0 	str	x0, [sp, #24]     // 将get_xx函数返回的地址p,放入sp+24位置。  因为后面会用到这个地址,因此需要保存在这。       400648:	f9400fe0 	ldr	x0, [sp, #24]     //从sp+24位置取出地址p40064c:	52800141 	mov	w1, #0xa        //将0xa也就是10,放入w1寄存器。400650:	b9000001 	str	w1, [x0]         //将w1寄存器的值,放入x0寄存器的地址,结构体中的a变量在结构体的起始位置 ,因此刚好设置p->a400654:	f9400fe0 	ldr	x0, [sp, #24]     //从sp+24位置取出地址p, 前面把x0存入sp+24就是这个目的。400658:	528000a1 	mov	w1, #0x5        //同理将5保存到w1,为了下一步设置p->b           	// #540065c:	b9000401 	str	w1, [x0, #4]      //将w1 存入x0偏移4字节的位置,结构体成员b在结构体中偏移4字节。400660:	f9400fe0 	ldr	x0, [sp, #24]     //最后取出指针p到x0400664:	a8c27bfd 	ldp	x29, x30, [sp], #32  //将在sp所在的地址的值给x29,x30寄存器,并且sp的值=sp+32 。刚好还原函数开始时的sp。400668:	d65f03c0 	ret                  //返回,将x30保存的下一条指令给pc

main函数:

000000000040066c <main>:40066c:	a9be7bfd 	stp	x29, x30, [sp, #-32]!400670:	910003fd 	mov	x29, sp400674:	97fffff0 	bl	400634 <get_xx>  //bl指令将下一条指令的地址保存到lr(x30)寄存器,ret的时候会将其设置到pc以继续执行400678:	f9000fe0 	str	x0, [sp, #24]    //参考get_xx 说明,将函数返回的地址px保存40067c:	f9400fe0 	ldr	x0, [sp, #24]    //参考get_xx 说明,将函数返回的地址px保存400680:	b9400001 	ldr	w1, [x0]       //将px指针的4字节内容放入w1。由于a只占4字节,后面的内容不拷贝400684:	f9400fe0 	ldr	x0, [sp, #24]    //重新取出px指针400688:	b9400400 	ldr	w0, [x0, #4]   //在x0+4字节的地址取出b。放入w040068c:	4b000020 	sub	w0, w1, w0   //减法 w0=w1-w0 ,即p->a - p->b400690:	b90017e0 	str	w0, [sp, #20]   //保存结果400694:	b94017e0 	ldr	w0, [sp, #20]   //取出结果400698:	a8c27bfd 	ldp	x29, x30, [sp], #32  //还原x29,x30,sp40069c:	d65f03c0 	ret                //返回

Arm64的所有函数,一开始都是这两句:

400634: a9be7bfd stp x29, x30, [sp, #-32]!  //stp指令将x29,x30保存在sp-32地址,后面的!,是完成后将sp-32的地址值给sp。意味着sp向地地址移动

400638: 910003fd mov x29, sp          //将sp的值保存到x29寄存器。

最后都有这一句:

400698: a8c27bfd ldp x29, x30, [sp], #32  //还原x29,x30,sp

因此函数调用都过stp和ldp来配对使用,保存和恢复某些寄存器:

每次函数都会开辟自己的栈。这个栈的大小根据函数的本地变量或者参数来决定。

带参数的例子,

带5个参数的函数get_xx: 

汇编代码: 


0000000000400684 <get_xx>:400684:	a9bc7bfd 	stp	x29, x30, [sp, #-64]!       //开辟的栈空间加大值64字节,用来存储参数。400688:	910003fd 	mov	x29, sp40068c:	b9002fe0 	str	w0, [sp, #44]            //其中w0-w4为5个参数,分别存储。400690:	b9002be1 	str	w1, [sp, #40]400694:	b90027e2 	str	w2, [sp, #36]400698:	b90023e3 	str	w3, [sp, #32]40069c:	b9001fe4 	str	w4, [sp, #28]4006a0:	d2800100 	mov	x0, #0x8                   	// #84006a4:	97ffffa3 	bl	400530 <malloc@plt>4006a8:	f9001fe0 	str	x0, [sp, #56]4006ac:	f9401fe0 	ldr	x0, [sp, #56]4006b0:	52800141 	mov	w1, #0xa                   	// #104006b4:	b9000001 	str	w1, [x0]4006b8:	f9401fe0 	ldr	x0, [sp, #56]4006bc:	528000a1 	mov	w1, #0x5                   	// #54006c0:	b9000401 	str	w1, [x0, #4]4006c4:	b9402fe0 	ldr	w0, [sp, #44]4006c8:	7100001f 	cmp	w0, #0x04006cc:	54000081 	b.ne	4006dc <get_xx+0x58>  // b.any4006d0:	d2955760 	mov	x0, #0xaabb                	// #437074006d4:	f9001fe0 	str	x0, [sp, #56]4006d8:	14000002 	b	4006e0 <get_xx+0x5c>4006dc:	d503201f 	nop4006e0:	f9401fe0 	ldr	x0, [sp, #56]4006e4:	a8c47bfd 	ldp	x29, x30, [sp], #644006e8:	d65f03c0 	ret00000000004006ec <main>:4006ec:	a9bd7bfd 	stp	x29, x30, [sp, #-48]!4006f0:	910003fd 	mov	x29, sp4006f4:	b9001fe0 	str	w0, [sp, #28]4006f8:	f9000be1 	str	x1, [sp, #16]4006fc:	b9401fe0 	ldr	w0, [sp, #28]400700:	7100081f 	cmp	w0, #0x2400704:	1a9fd7e0 	cset	w0, gt400708:	12001c00 	and	w0, w0, #0xff40070c:	b9002fe0 	str	w0, [sp, #44]400710:	52800084 	mov	w4, #0x4                   	// #4  在调用get_xx函数之前准备参数,并依次存储在w0-w4这5个寄存器中400714:	52800063 	mov	w3, #0x3                   	// #3400718:	52800042 	mov	w2, #0x2                   	// #240071c:	52800021 	mov	w1, #0x1                   	// #1400720:	b9402fe0 	ldr	w0, [sp, #44]400724:	97ffffd8 	bl	400684 <get_xx>400728:	f90013e0 	str	x0, [sp, #32]40072c:	f94013e0 	ldr	x0, [sp, #32]400730:	aa0003e1 	mov	x1, x0400734:	90000000 	adrp	x0, 400000 <_init-0x4f0>400738:	911fe000 	add	x0, x0, #0x7f840073c:	97ffff8d 	bl	400570 <printf@plt>400740:	52800000 	mov	w0, #0x0                   	// #0400744:	a8c37bfd 	ldp	x29, x30, [sp], #48400748:	d65f03c0 	ret40074c:	00000000 	.inst	0x00000000 ; undefined

参考指令:

03_ARMv8指令集介绍加载与存储指令 - Carlos·Wei - 博客园

ARM的六大类指令集---LDR、LDRB、LDRH、STR、STRB、STRH - blogernice - 博客园

https://blog.csdn.net/wmzjzwlzs/article/details/124513127


http://www.mrgr.cn/news/82665.html

相关文章:

  • 在Vue3项目中使用svg-sprite-loader
  • 【Unity3D】基于UGUI——简易版 UI框架
  • 一篇小短文,理解动态规划问题 DP (Dynamic Programming)
  • 【跨域】解决SpringBoot和openresty跨域问题
  • ESP8266+STM32+阿里云保姆级教程(AT指令+MQTT)
  • javaEE-网络原理-1初识
  • 线上go内存泄漏分析实战
  • Java100道面试题
  • 网站常用功能模块-鉴权
  • 【Rust自学】10.6. 生命周期 Pt.2:生命周期的语法与例子
  • 后台管理系统用户退出登录方案实现
  • 4进货+后台事务
  • Kubernetes Gateway API-3-TLS配置
  • 如何在 Hive SQL 中处理复杂的数据类型?
  • 安卓触摸对焦
  • 如何操作github,gitee,gitcode三个git平台建立镜像仓库机制,这样便于维护项目只需要维护一个平台仓库地址的即可-优雅草央千澈
  • 如何使用 Ansys OptiSlang 同时运行多个参数化设计研究
  • 当今世界如何减少暴戾之气和矛盾纷争
  • 【Rust自学】10.5. 生命周期 Pt.1:生命周期的定义与意义、借用检查器与泛型生命周期
  • Linux 基础七 内存
  • 修改secure-file-priv参数-mysql5.7.26限制不允许导入或导出的解决方法
  • GNU链接器简介-2
  • Ubuntu 下载安装 Consul1.17.1
  • Branch-Solve-Merge Improves Large Language Model Evaluation and Generation
  • 高中数学部分基础知识
  • 【51单片机零基础-chapter4:LED数码管】