x86_64栈帧结构

时间:2022-08-09 02:55:22

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 的值如果在汇编模块中被改变了,在退出该模块时,必须将
其恢复。