首先介绍下堆栈使用的基础知识。
一般ARM栈分配在高地址,然后往低地址方向增长。函数调用的过程一般使用A0-A3作为保护现场,如果参数太多,则要用到堆栈来存储参数,入栈的顺序则和编译器有关系。。。
过程调用标准
1.寄存器使用规则
R0-R3 调用后无需恢复之前的内容
R4-R11保存局部变量的值
R12 临时栈指针,记作IP,
R13 数据栈指针,记作SP。
R14 链接寄存器,保存子程序的返回地址
R15 程序计数器
2. 数据栈的使用规则
一般采用FD,满递减的方式
3. 参数传递规则
参数少于4个用R0-R3。参数多于4个采用数据栈。最后一个参数先入栈。
下面看一个VC++6.0中压栈顺序的约定,主要通过关键字__cdecl __stdcall __fastcall thiscall来实现.
关键字 堆栈清除 入栈数序
__cdecl 调用者 从右到左
__stdcall 函数自身 从右到左
__fastcall 函数自身 从右到左 优先使用ECX,EDX
thiscall 函数自身 从右到左 优先使用ECX传递this指针。
所以用__cdecl声明的函数可以实现可变参数的功能。
可变参数的使用
typedef char *va_list;
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
#define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND))))
va_list arg_ptr; //参数列表的指针
va_start(arg_ptr, i); //参数列表指针指向第一个参数
s=va_arg(arg_ptr,char*); //取一个char*的参数出来
va_end(arg_ptr); //释放参数列表指针。
static char sprint_buf[1024];
int printf(char *fmt, ...)
{
va_list args;
int n;
va_start(args, fmt);
n = vsprintf(sprint_buf, fmt, args);
va_end(args);
write(stdout, sprint_buf, n);
return n;
}
阅读(2361) | 评论(0) | 转发(1) |