ARMv7汇编代码分析

为了分析ARMv7架构寄存器的使用,利用C程序生成ARMv7汇编,并分析之。

1、C源程序代码如下(为了简化,函数功能很简单):

# cat  callfunc.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
	int input=10;
	int tmp,result;
	tmp = func1(input);
	result = func2(tmp);
	printf("result = %d \n", result);
	return 0;
}

int func1(int a)
{
	a++;
	return a;
}

int func2(int b)
{
	b=b*b;
	return b;
}

2、交叉编译生成ARM汇编代码:

# arm-none-linux-gnueabi-gcc -march=armv7-a  callfunc.c  -S -o callfunc.asm

生成ARMv7的汇编代码如下:

	.arch armv7-a
	.fpu softvfp
	.eabi_attribute 20, 1
	.eabi_attribute 21, 1
	.eabi_attribute 23, 3
	.eabi_attribute 24, 1
	.eabi_attribute 25, 1
	.eabi_attribute 26, 2
	.eabi_attribute 30, 6
	.eabi_attribute 34, 1
	.eabi_attribute 18, 4
	.file	"callfunc.c"
	.section	.rodata
	.align	2	;2^2,即4字节对齐;以"."开头的是伪指令,具有编译器相关,平台无关性;
.LC0:
	.ascii	"result = %d \012\000"
	.text
	.align	2
	.global	main	;全局函数声明,相当于C语言中的extern
	.type	main, %function
main:
	.fnstart	;函数开始标志
	@ args = 0, pretend = 0, frame = 16		;@标志注释,由编译器添加
	@ frame_needed = 1, uses_anonymous_args = 0

	stmfd	sp!, {fp, lr}				;fp=r11=0,lr=0x40291664
																			;分别存储fp,lr到sp,sp-4;sp0=sp-4;fp(R11)桢指针 ;
				;关于fp:通常在C程序编译过程中,所有函数的局部变量被分配在一个连续的存储区中,
				;一般这个存储区是在堆栈中,这个连续的存储区称为这个函数的存储“帧”,它是通过一个指针访问的。
				;寄存器 fp (桢指针)应当是零或者是指向栈回溯结构的列表中的最后一个结构,
				;提供了一种追溯程序的方式,来反向跟踪调用的函数。	
				;即:其作用是用来回溯,从代码中也可以看出来,fp只是起标签作用,理论上不使用fp也不会影响程序执行
	.save {fp, lr}		;关于.save:其作用与以下.setfp、.pad等的伪指令作用类似,对相应汇编指令产生注释。
				;具体注释内容见网页(http://sourceware.org/binutils/docs/as/ARM-Directives.html)
	.setfp fp, sp, #4
	add	fp, sp, #4														;sp=0xbe88f3e0,fp=0xbe88f3e4
	.pad #16
	sub	sp, sp, #16														;sp=0xbe88f3d0
	mov	r3, #10																;r3=10
	str	r3, [fp, #-8]													;r3->fp-8即sp-4
	ldr	r0, [fp, #-8]													;r3->r0
	bl	func1			;jump to func1
	str	r0, [fp, #-12]		;r0->fp-12
	ldr	r0, [fp, #-12]
	bl	func2
	str	r0, [fp, #-16]
	movw	r3, #:lower16:.LC0
	movt	r3, #:upper16:.LC0      ;movw和movt的作用为:r3 = (movt #:upper16:.LC0 << 16) | (movw #:lower16:.LC0)).
					;以上两句的作用就是输出.LC0段的.ascii那一行的内容,即打印那个result = %d \012\000	
	mov	r0, r3
	ldr	r1, [fp, #-16]
	bl	printf																;打印r0、r1中内容
	mov	r3, #0
	mov	r0, r3
	sub	sp, fp, #4
	ldmfd	sp!, {fp, pc}
	.fnend
	.size	main, .-main
	.align	2
	.global	func1
	.type	func1, %function
func1:
	.fnstart
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	@ link register save eliminated.
	str	fp, [sp, #-4]!	     ;r11(fp)入栈;sp=0xbe88f3d0-4=0xbe88f3cc,r11=0xbe88f3e4;fp(即r11)存储到sp-4(0x)的地址中
	.save {fp}													
	.setfp fp, sp, #0
	add	fp, sp, #0														;fp=0xbe88f3cc
	.pad #12
	sub	sp, sp, #12														;sp=0xbe88f3c0
	str	r0, [fp, #-8]			;r0存储到fp-8指向的地址处
	ldr	r3, [fp, #-8]
	add	r3, r3, #1
	str	r3, [fp, #-8]
	ldr	r3, [fp, #-8]
	mov	r0, r3
	add	sp, fp, #0
	ldmfd	sp!, {fp}														;r11(fp)出栈
	bx	lr
	.fnend
	.size	func1, .-func1
	.align	2
	.global	func2
	.type	func2, %function
func2:
	.fnstart
	@ args = 0, pretend = 0, frame = 8
	@ frame_needed = 1, uses_anonymous_args = 0
	@ link register save eliminated.
	str	fp, [sp, #-4]!
	.save {fp}
	.setfp fp, sp, #0
	add	fp, sp, #0
	.pad #12
	sub	sp, sp, #12
	str	r0, [fp, #-8]
	ldr	r3, [fp, #-8]													;r0->r3
	ldr	r2, [fp, #-8]													;r0->r2
	mul	r3, r2, r3	 													;r2*r3->r3
	str	r3, [fp, #-8]
	ldr	r3, [fp, #-8]
	mov	r0, r3		;r3->r0
	add	sp, fp, #0
	ldmfd	sp!, {fp};sp->fp ;pop fp
	bx	lr
	.fnend
	.size	func2, .-func2
	.ident	"GCC: (Sourcery CodeBench Lite 2011.09-70) 4.6.1"
	.section	.note.GNU-stack,"",%progbits


分析内容见代码注释

注意:

1、编译器默认用来传输参数的寄存器是r0~r3,参数超过四个就要用到栈。
2、bl printf:该命令是打印命令,默认打印r0开始的寄存器内容,测试过参数超过4个时候,打印时r0存储打印格式,r1-r3存储要打印的数,剩下的参数需要其他寄存器存储,但是printf如何实现打印多出来的几个寄存器的,目前暂不清楚。欢迎补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值