是否可以在8086汇编中操作指令指针?

时间:2017-11-15 07:46:47

标签: assembly x86-16

我想知道我是否可以在8086程序集中操作(读取和更改)指令指针(IP)的值。

例如,

说IP当前正在存储0200h。我想阅读这个值并将其更改为其他内容,例如4020h。我怎么能这样做?

2 个答案:

答案 0 :(得分:5)

如果要将指令指针设置为已知值,例如十六进制值4020h,则可以直接跳转到该地址:

jmp 4020h

或者,如果某个内存位置myVariable保存了您想要存储在IP中的值,则可以进行间接跳转:

jmp [myVariable]

jmp(间接或直接)的结果修改指令指针。

读取指令指针是有问题的。 Linux上的位置无关代码曾经使用一组代码来工作:

 call getIP

 :getIP
 mov bx, [sp] ; Read the return address into BX.
 ret

有关其他阅读IP的方法,请参阅Stack Overflow: reading IP

答案 1 :(得分:3)

相关:Reading program counter directly(我在那里更新了接受的答案,没有吸吮,覆盖32位与64位,因为它是用于读取IP的规范Q& A.没有提到写IP,因为这是一种概念上理解的事情:编写IP是一种跳跃,但是你的代码可能在不知道加载的位置的情况下运行,因此用例完全不同。)

同样接近重复:Why can't you set the instruction pointer directly?询问为什么RIP / EIP / IP没有直接暴露用于与AX等整数寄存器一起使用的指令。 (即为什么add IP, AX不能作为间接跳转。)TL:DR:像ARM do 这样的一些ISA将程序计数器暴露为整数寄存器之一,但x86只有很少的寄存器和在机器代码中使用一个IP寄存器编码将带走一个通用的整数寄存器。

您可以直接使用IPjmp撰写call,但只能通过call推送它来阅读。

(技术上call不是阅读IP的唯一选项。您可以使用int或其他一些中断,让中断处理程序查看{{1但是,这与iret的想法相同,只是更复杂,更慢。)

在位置相关代码中,每条指令的地址在链接时都是已知的。您可以将任何标签的地址用作直接常量或寻址模式的一部分。 e.g。

call

或者

mov ax, $         ; ax = address of the start of the MOV instruction (NASM syntax)
  

说IP当前正在存储mov ax, label ; or MASM: mov ax, OFFSET label label: 我想读取此值&将其更改为其他名称0200h。我怎么能这样做?

4020h

汇编程序将根据当前IP确定要使用的call 4020h位移。 (或者,如果您希望以位置无关的方式跳转到固定的rel16值(相对于4020h的偏移量),则可以将call ax放入寄存器和IP中,以便仍然不是一个绝对地址。为此你需要一个cs,并且可以使用far call绝对直接地址作为直接地址。)

旧值(+调用指令的长度)将位于堆栈上,ptr16:16处的代码可以使用4020h弹出它(或弹回到使用pop)的IP,或使用ret加载。

一般情况下,避免错误匹配的mov / call。 (即不仅仅将ret返回地址放入寄存器并返回pop)。这将导致分支错误预测,因为您使返回地址预测器堆栈失衡。 (http://agner.org/optimize/Return address prediction stack buffer vs stack-stored return address?

在比PIII更新的CPU上,jmp / call next_insn效率很高,因为call rel32=0 is special-cased and doesn't break the return-address predictor stack。请参阅Reading program counter directly

@ mksteve建议调用pop ax / mov bx, [sp]而不仅仅是ret / call next_instruction的函数,这对早期的英特尔P6系列CPU(如PPro)来说是好的。但请注意pop bx不是有效的16位寻址模式,所以这在16位中更加笨重。如果您真的想在16位代码中执行此操作,[sp] / pop ax / push ax可能会更少。

在64位代码中,您可以更直接地读取RIP的当前值:ret。这更常用于静态数据的位置无关寻址。例如lea rax, [rip]lea rax, [rel my_table]将告诉汇编程序+链接器确定用于到达所需符号的add dword [rel global_counter], 2。这适用于可执行文件或动态库中,即使库在不同的地址加载,代码和数据之间的距离也是不变的。