汇编 --- 过程调用 和 过程返回

读书笔记《x86 从实模式到保护模式》

16位相对近调用

特点

被调用的目标过程位于当前代码段内,而非另一个不同的代码段,所以只需要提供偏移地址

模式

call near proc_1

near指代这个调用是近调用,这个关键字是可缺省的,不指定则默认为near的近调用

proc_1来自程序中的某个标号,编译阶段proc_1被替换为其所在的汇编地址

解释

这个指令是三字节的指令:

操作码占一个字节,0XE8

操作数占两个字节,为什么?因为一个段的大小为2^16(还记得段要放在16字节对齐的地方),近调用的目标过程只会在这个段内,所以其操作数最大只有两个字节

编译阶段计算这个操作数的过程:proc_1所在的汇编地址减去这条call指令所在的汇编地址再减去3  计算出的值会替换掉proc_1  从而机器码变为:0xE8 计算出的值

addr(proc1) - addr(instruction) - 3 = val(operator)

当程序执行过程中CS:IP指向了这条指令,发现操作码为0xE8,处理器就知道这是个过程调用的命令,随即将后面的值拿过来加上当前IP的内容,再加上3就得到了一个新的偏移地址

这个地址当然要放入IP让CS:IP能够跳转过去的,但这个动作之前会把IP当前值保存到栈中,最后采用计算出的值替换IP中的内容。

由于计算过程中是两个汇编地址的相减,如果proc_1在这条call指令之前,那么计算出的操作数就是正的,反之则是负数。所以这个操作数是有符号数,其值当然也就是不是0~2^16-1

而是-(2^16)/2 ~ (2^16)/2

16位间接绝对近调用

特点

这种调用过程和16位相对近调用相似,区别在于相对和绝对。相对是计算偏移值,而绝对则是给出了过程所在的绝对汇编地址。过程同样是限制在本段中,不跨段调用。

模式

call cx
call [0x3000]
call [bx]
call [bx+si+0x02]

解释

由于绝对调用需要给出绝对地址,CS段寄存器不变,都是在一个段,IP是要替换的,现将IP寄存器压栈,用操作数替换IP,随后跳转到操作数所在的汇编地址上运行。

间接体现在操作数的获取必须要先访问地址如上面的0x3000取出地址上的值,也就是偏移地址,才能进行跳转

16位直接远调用

特点

和16位间接绝对近调用相似,直接一词说明可以直接给出跳转地址了,远调用说明不仅IP需要提供,CS也需要。

模式

call 0x2000:0x1000

16位间接绝对远调用

特点

间接:跳转地址是间接给出的

绝对:不需要计算偏移

远:可以跨段调用

模式

call far [0x2000]
call far [proc_1]
call far [bx]
call far [bx+si]

....


proc_1 dw 0x0102,0x2000

解释

间接远调用必须加上far关键字

指令中仅仅需要给出保存过程所在绝对汇编地址的标识所在的偏移地址

proc_1所在的汇编地址上保存了两个字:0x0102和0x2000   这就是要跳转的proc_1过程所在的汇编地址

过程返回

过程返回只有两种:

ret和retf

ret负责过程结束将之前压入栈的IP值恢复到IP寄存器

retf要稍微复杂一点,得恢复CS和IP

### RISC-V 架构过程调用指令集规范 在RISC-V架构中,过程调用通常遵循特定的调用约定ABI(应用程序二进制接口)。这些规定确保不同编译器生成的代码可以相互协作。对于过程调用而言,主要涉及寄存器分配、参数传递以及返回地址处理等方面。 #### 寄存器使用规则 - **整数寄存器** - `x1` (ra): 返回地址,在函数调用时保存下一条指令的位置[^1]。 - `x2-x7`: 可用于临时存储或作为参数传递给子程序。 - `x8-x9`, `x18-x27`: 调用者保存型寄存器,如果被修改则需由调用方恢复其原始值。 - **浮点寄存器** - 类似于整数寄存器,存在相应的浮点版本如`f0-f7`用于传递浮点参数;而`f8-f9`,`f18-f27`则是调用者保存型浮点寄存器[^2]。 #### 参数传递方式 当执行过程调用时: - 前六个整数/指针类型的参数通过寄存器`a0-a5`(即`x10-x15`)传送; - 对于超过六个以上的额外参数,则依次放入栈空间内,并调整堆栈指针(sp)。 ```assembly jal ra, function # Jump and Link to the target function address stored in 'function', saving PC+4 into register 'ra' ``` 此汇编语句展示了如何利用JAL(Jump And Link)指令实现跳转至目标函数的同时将当前PC(程序计数器)+偏移量写入指定寄存器(ra),以便稍后能够从中读取并继续执行后续代码。 #### 函数返回机制 一旦完成工作,子程序会把结果放在预定义位置——通常是第一个参数寄存器(`a0`)里边。接着再借助ret(return from trap or exception)指令回到之前记录下来的断点处,也就是父级调用者的上下文中去。 ```assembly ret # Return from subroutine by jumping back to the address saved earlier in 'ra' using JALR instruction internally. ``` 上述命令实际上内部实现了基于链接寄存器的内容间接寻址跳跃动作,从而完成了控制权交还的操作流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值