调用约定

8086 CPU寄存器

均为16位。

寄存器名AXBXCXDXSPBPSIDIDSESSSCSIP
作用通用寄存器栈区段地址寄存器   数据地址寄存器 栈区偏移地址寄存器段地址寄存器偏移地址寄存器

内存寻址

  • 两个寄存器操作只能相加,不能相减,例如

mov ebx, [esi+eax] ; 有效

mov ebx, [esi - eax] ; 无效,不能做减法

  • 最多只有两个寄存器参与地址计算

调用约定(Calling Convention)

调用约定是极为重要的部分。它关系到子函数调用的规则:如何调用及如何返回

有很多种调用约定,以C语言调用约定为例:

C语言调用约定(C Calling Convention)

  • 强依赖硬件提供的支持
  • 基于push, pop, call, ret等指令
  • 参数通过栈传递,子过程用到的变量也放在栈上

调用约定通常可分为两个方面:调用方规则(Caller Rules)和被调方规则(Callee Ruler)。

调用方规则(Caller Rules)

C语言调用约定规定,在子过程(函数)调用之前,调用方应该:

  • 保存应由调用方保存的寄存器(caller-saved registers):EAX, ECX, EDX。

这几个寄存器可能会被被调用方(callee)修改,所以先保存它们,以便调用结 束后恢复栈的状态。

  • 将需要传给子过程的参数入栈(push onto stack)

参数按逆序 push 入栈(最后一个参数先入栈)。由于栈是向下生长的,第一个参数 会被存储在最低地址(这个特性使得变长参数列表成为可能)。此处存疑

  • 使用 call 指令,调用子过程(函数)

call 先将返回地址 push 到栈上,然后开始执行子过程代码。子过程代码需要遵守的 callee rules。

子过程返回后(call 执行结束之后),被调用方会将返回值放到 EAX 寄存器,调用方 可以从中读取。为恢复机器状态,调用方需要做:

 

  1. 从栈上删除传递的参数

    栈恢复到准备发起调用之前的状态。

  2. 恢复由调用方保存的寄存器(EAXECXEDX)—— 从栈上 pop 出来

    调用方可以认为,除这三个之外,其他寄存器的值没有被修改过。

 

被调方规则(Callee Ruler)

  1. 将寄存器 EBP 的值入栈,然后 copy ESP to EBP

    push ebp
    mov  ebp, esp
    
  2. 在栈上为局部变量分配空间

    栈自顶向下生长,故随着变量的分配,栈顶指针不断减小。

  3. 保存应有被调用方保存(callee-saved)的寄存器 —— 将他们压入栈。包括 EBXEDIESI

以上工作完成,就可以执行子过程的代码了。当子过程返回后,必须做以下工作:

  1. 将返回值保存在 EAX

  2. 恢复应由被调用方保存的寄存器(EDIESI) —— 从栈上 pop 出来

  3. 释放局部变量

  4. 恢复调用方 base pointer EBP —— 从栈上 pop 出来

  5. 最后,执行 ret,返回给调用方 (caller)

http://arthurchiao.art/blog/x86-asm-guide-zh/

http://www.cs.virginia.edu/~evans/cs216/guides/x86.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值