GCC内联汇编实现一个整型数组相加
经过我不懈努力,各种查阅网上资料,终于弄明白一些AT&T汇编。总结如下:
- AT&T汇编和Intel汇编语法上存在很多的差异,比如
add eax,ebx
在Intel汇编中相加结果保存在eax中,而在AT&T汇编中相加结果保存在ebx中。 - 在AT&T汇编中,有立即数参与语句,立即数必须放在前面。
- 网上很多关于esi和edi描述是有问题的,其实esi和edi是串处理寄存器,注意是串并不是字符串。
还有很多细节问题我记不太清,如果真想学,自己亲身经历比别人一味灌输知识要来的快。
废话少说,直接进入正题。
题目要求:用objdum -d sum.o反汇编sum.o,在main.c中通过汇编调用sum。其中sum.c和main.c源代码如下:
/*
sum.c
*/
int sum(int N,int arr[]){
int s = 0;
int i;
for(i = 0;i < N;i++)
s += arr[i];
return s;
}
/*
main.c
*/
int sum(int N,int arr[]);
int main(int argc,char *argv[]){
int i;
int temarr[argc];
temarr[0] = 0;
for(i = 1;i < argc; i++)
temarr[i] = atoi(argv[i]);
printf("Total is %d
",sum(argc,temarr));
return 0;
}
仔细分析这个题目,它的本意是用汇编语言实现sum.c然后在main中调用。其实题目本身是有误解的,objdum出来的汇编代码由于是系统反汇编出来的,所以很多地址尤其跳转地址都是当时环境中给出的,并不能直接当成sum.c的汇编程序来用,所以最开始很长时间都花在了如何修改反汇编出来的代码,使之能正常运行,因为毕竟AT&T汇编对我来说还是比较陌生的,只知其大体框架,而不懂其中的细节,就想编出带循环的汇编代码确实有难度。后来修改无果打算自己写,没想到一个上午就搞定了。sum.c的汇编代码如下(我的电脑为64位,所以寄存器首字母为r):
int sum(int N,int arr[]){
int s = 0;
asm volatile(
"mov $0x0,%%rax;
" //rax清零
"mov %%rax,%%rbx;
" //rbx清零
"start_loop: sub $0x1,%%rcx;
" //开始循环;rcx减一(rcx为计数器)
"cmp $0x0,%%rcx;
" //rcx是否减到比零小
"jl loop_exit;
" //如果rcx比零小,则退出循环
"mov (%%rsi,%%rcx,4),%%rbx;
" //取出rsi中的数放到rbx中,注意是从后往前取
"add %%rbx,%%rax;
" //相加结果放入rax中
"jmp start_loop;
" //继续循环
"loop_exit:"
:"=a"(s) //返回值放入s中
:"S"(arr),"c"(N) //数组传入rsi,长度放入rcx
:"memory"
);
return s;
}
完美!