如何编写将自身操作码首字节存入al寄存器的汇编指令?
解决读取自身操作码到al的问题
你原来的代码mov al,byte[0100];的问题在于依赖固定内存地址,DOS下程序的加载地址不是固定的(即使是.com程序默认从CS:100h开始,硬编码地址依然不可靠),而且没有定位到当前指令的地址。
在iapx88(8088)架构下,无法直接访问IP(指令指针)寄存器,所以要获取当前指令的地址,得用call指令的特性间接实现:call执行时会把下一条指令的地址压入栈,我们弹出这个地址后,减去当前call指令的长度,就能得到call指令自身的起始地址,再读取该地址的字节到al。
可行代码示例(适用于DosBox下的NASM .com程序)
org 100h ; .com程序的起始地址,DOS会加载到CS:100h start: call get_self_addr ; 这条指令的操作码第一个字节是0E8h,长度为3字节 get_self_addr: pop ax ; ax现在是get_self_addr标签的地址(即call指令的下一条指令地址) sub ax, 3 ; 减去call指令的长度3,得到call指令自身的起始地址 mov al, byte [ax] ; 读取call指令的第一个操作码字节到al ; 可选:验证结果,将al的值以十六进制输出 mov ah, 0Eh mov dl, al shr dl, 4 add dl, '0' cmp dl, '9' jbe print_high add dl, 7 print_high: int 10h mov dl, al and dl, 0Fh add dl, '0' cmp dl, '9' jbe print_low add dl, 7 print_low: int 10h mov ah, 4Ch int 21h ; 退出程序
代码解释
call get_self_addr:执行时先把下一条指令(pop ax)的地址压栈,然后跳转到get_self_addr标签。pop ax:将栈中保存的地址弹出到ax,此时ax等于get_self_addr的地址,也就是call指令的下一条指令地址。sub ax,3:8088中call near指令是3字节长度,减去3就得到了call指令自身的起始地址。mov al, byte [ax]:读取该地址的第一个字节(也就是call指令的操作码0E8h)存入al。
如果需要读取其他指令的自身操作码,只需要调整sub ax的数值(对应指令的字节长度)即可。
内容的提问来源于stack exchange,提问作者user19963011
相关产品推荐
相关产品推荐

