我想知道我是否可以在8086程序集中操作(读取和更改)指令指针(IP)的值。
例如,
说IP当前正在存储0200h
。我想阅读这个值并将其更改为其他内容,例如4020h
。我怎么能这样做?
答案 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寄存器编码将带走一个通用的整数寄存器。
您可以直接使用IP
或jmp
撰写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
。这适用于可执行文件或动态库中,即使库在不同的地址加载,代码和数据之间的距离也是不变的。