获取一条机器指令的内存操作数的地址
平台:linux
问题: 现在确定了一条机器指令地址,比如地址是7515 <main+75>, 通过gdb可以很容易的确定其汇编语句(ATT风格的)是:movl $0xa,-0x14(%ebp),这样内存操作数的地址很容易获取。但是在不知道汇编语句的情况下(只是知道指令的地址),读取出来指令为:0x0aec45c7,从0x0aec45c7中显然无法获取内存操作数的地址,是否可以通过该指令的一次执行,获取其操作的内存操作数的地址,也就是上面的: %ebp-0x14,如果可以,简单说下思路吧。
现在采用的方式是将机器码转换到汇编码,由汇编码获取信息,比较繁琐,征一个稍微简单一些的方法。
再加一个,变长指令集里,怎么知道当前要取的指令的长度-.-,体系结构忘得差不多了。。。
语句a=0.5; b=a;对b进行赋值操作的时候汇编语句是这样的,eax里存放b的地址,-0x8(%ebp)存放的是a的数值0.5:
经历栈到ecx,ecx到xmm0,xmm0到eax,为什么要经过xmm0,求扫盲-_-!。
Answers
对于第一个问题:有指令的地址,取出该地址对应的机器码就可以知道 内存 操作数的地址。机器码由“操作码+[操作数1]+[操作数2]”等等形式组成,可以参考:http://www.soft6.com/v9/2007/jckf_0810/49684.html
内存操作数表示为”相对偏移“或”绝对偏移”地址,
如call [xxx]对应机器码:FF 15 18 62 44 00,FF 15为call []的指令形式即操作码,18 62 44 00(0x446218)是一个绝对偏移地址,整条指令的意思是调用0x446218地址保存的地址(函数)。
又如jnz xxx对应机器码:75 0C,75是jnz对应的操作码,0C是相对偏移地址,即当EFLAG的Z标志位为0时跳转到当前jnz xxx地址+0xC+0x2(jnz xxx指令长度)的位置执行。
第二个问题:获得指令长度有一个反汇编引擎的工具可以得到,到网上下载lDasm.c、lDasm.h的类,然后调用SizeOfCode(cPtr, &pOpcode)函数获得指令长度。或者看我以前在德问发的贴有提到。
至于“a=0.5; b=a;”实现为“经历栈到ecx,ecx到xmm0,xmm0到eax”可能是因为你编译的版本是Debug版本的,Debug版为了方便调试和下断点编译成这样,Release版可能就直接赋值了。