x86_64栈帧
//============================================================================ // Name : test.cpp // Author : // Version : // Copyright : Your copyright notice // Description : Hello World in C++, Ansi-style //============================================================================ #include <stdio.h> int func(int a, int b, int c, int d, int e, int f, int g, int h) { int sum = a + b + c + d + e + f + g + h; return sum; } long ip; void getip(void) { long bp; __asm__ __volatile__("pop %0; pop %1; push %1; push %0" :"=r"(bp), "=r"(ip):); return ; } double sumf(float i, double j) { double ij = i + j; return ij; } int sum(int i, int j) { int ss = i + j; return ss; } void asmex() { __asm__ __volatile__( "push %%rbp;mov %%rsp,%%rbp;mov %%edi,-0x14(%%rbp);mov %%esi,-0x18(%%rbp);" "mov -0x18(%%rbp),%%eax;" "mov -0x14(%%rbp),%%edx;" "add %%edx,%%eax;" "mov %%eax,-0x4(%%rbp);" "mov -0x4(%%rbp),%%eax;" "pop %%rbp;" "retq;": ); } int (*ssum)(int , int); int main() { // ssum = 0x00000000004005aa; //00000000004005aa: push %rbp // int i = 1, j = 2, sum = 0; // sum = ssum(i, j); // printf("sum is %d\n", sum); float f1 = 10.2; double d2 = 11.1; printf("sum is f1 %f\n", f1 + d2); //int a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8; //int ss = func(a, b, c, d, e, f, g, h); //printf("sum is: %d\n", ss); //int input = 111, result; //long ip = 0; //__asm__ __volatile__("movl %1,%0; ":"=r"(result):"m"(input)); //__asm__ __volatile__("push %%rbp; pop %%rbp; " :"=r"(ip):); //printf("result is: %d\n", result); getip(); /* * "mov -0x18(%%rbp),%%eax" "mov -0x14(%%rbp),%%edx" "add %%edx,%%eax" "mov %%eax,-0x4(%%rbp)" "mov -0x4(%%rbp),%%eax" "pop %%rbp" "retq" */ int ss = 3; printf("ip is %d\n", ip); return 0; }
将汇编语言代码的地址直接赋给c语言的函数,查看栈帧调用过程.
我试验了多个参数的情况,发现一般规则为, 当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。当参数为 7 个以上时, 前 6 个与前面一样, 但后面的依次从 "右向左" 放入栈中。
例如:
CODE
(1) 参数个数少于7个:
f (a, b, c, d, e, f);
a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%r8, f->%r9
g (a, b)
a->%rdi, b->%rsi
有趣的是, 实际上将参数放入寄存器的语句是从右到左处理参数表的, 这点与32位的时候一致.
CODE
2) 参数个数大于 7 个的时候
H(a, b, c, d, e, f, g);
a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%rax
g->8(%esp)
f->(%esp)
call H
易失寄存器:
%rax, %rcx, %rdx, %rsi, %rdi, %r8, %r9 为易失寄存器, 被调用者不必恢复它们的值。
显然,这里出现的寄存器大多用于参数传递了, 值被改掉也无妨。而 %rax, %rdx 常用于
数值计算, %rcx 常用于循环计数,它们的值是经常改变的。其它的寄存器为非易失的,也
就是 rbp, rbx, rsp, r10~r15 的值如果在汇编模块中被改变了,在退出该模块时,必须将
其恢复。