modrm.mod==0,modrm.rm=4,sib.base==5,sib.index==4在sib.scale不同时有何特别之处?
binutils2.18
objdump 在生成disp时使用了如下代码,没看明白scale!=0是啥意思?
OP_E()
{
....
havedisp = havebase //排除(modrm.mod==0且modrm.rm==5)或(modrm.mod==0且modrm.rm==4且sib.base==5)
|| (havesib //排除modrm.mod==0且modrm.rm==5
&& (index != 4 //排除modrm.mod==0且modrm.rm==4且sib.base==5且sib.index==4
|| scale != 0));//mod_bit64????多余???
if (!intel_syntax)
if (modrm.mod != 0 || (base & 7) == 5)//肯定有dispxx
{
if (havedisp || riprel)//是disp
print_displacement (scratchbuf, disp);// mov -0x4(%ebx),%eax
else//是地址
print_operand_value (scratchbuf, 1, disp);// 8048248: ff 35 f4 94 04 08 pushl 0x80494f4 [内存地址]
oappend (scratchbuf);
if (riprel)
{
set_op (disp, 1);
oappend ("(%rip)");
}
}
...}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
你所问的是 x86/x64 指令体系中最复杂的一个寻址模式:wink:
正好问的是 register id 为 100 和 101 时的情形
100(4)= esp
101(5)= ebp
它的复杂性产生于我所说的两大原则,详见我的网站上的一篇文档:http://www.mouseos.com/x64/modrm_sib_rule.html
基于这两个原则:
当 modrm.r/m = 4 时,它引导出 SIB 字节,那么:
(1)当 sib.index = 4 即 sib.index = esp 时:sib 寻址模式为 [base],即:寄存器间接寻址
此时,如果,sib.base = ebp(5) 时, 与 modrm = 00-XXX-101(modrm.mod = 0 & modrm.r/m = 5)时的寻址是一样的。
因此,又依赖于 modrm.mod 是多少
回到你提的问题来:
>> modrm.mod==0,modrm.rm=4,sib.base==5,sib.index==4在sib.scale不同时有何特别之处?
这时,scale 是被忽略,被抛弃。也就是说 scale 并不起作用!
modrm.mod = 0, modrm.r/m = 4 并且 sib.base = 5, sib.index = 4
它是一个 [disp32],也就是说,它是一个绝对地址寻址。
如:[0x080c1040] 这是一个绝对地址寻址
再举个例子:
当 modrm = 01-XXX-100 (modrm.mod = 01)
且当 sib = 11-000-101 (即:sib.scale = 11, sib.index = 000, sib.base = 101)
它的寻址是:[eax*8 + 0x0c] (这个 0x0c 是举个例子):index 是 eax 寄存器, scale 是 8, 无 base 寄存器
此时,scale 才有意义,因为它的 modrm.mod = 1
---------------------------------------
所以:
sib.index = 4 时,寻址模式依赖于 sib.base 并且还要依赖于 modrm.mod 的值
或许你要认真是看一下,我网站上的文档(关于 x86/x64 指令体系):http://www.mouseos.com/x64/index.html
谢谢,那|| scale != 0其实是多余的
再请教mik版主,64位模式下的objdump解码有问题?
[root@mail ~]# printf "\xff\x34\x65\xf4\x94\x04\x08" > x1.dat
[root@mail ~]# objdump -b binary -m i386 -D x1.dat
x1.dat: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ff 34 65 f4 94 04 08 pushl 0x80494f4
[root@mail ~]# objdump -b binary -m i386 -M x86-64 -D x1.dat
x1.dat: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ff 34 65 f4 94 04 08 pushq 0x80494f4(,2)
[root@mail ~]#
ff 34 65 f4 94 04 08
这个机器码在 32 位下是: push dword ptr [0x080494f4]
在 64 位下是:push qword ptr [0x080494f4]
------------------------------------------------------------------
在 32 位与 64 位下其实是一样的,只是它们的 operand size 不一样而已
>>> 0: ff 34 65 f4 94 04 08 pushq 0x80494f4(,2)
我对 gnu 语法并不是很熟,这条 gnu 语法语句 对应的 intel 语法是什么 ??
但是,我能猜到,objdump 的死板,它把 scale = 2 直接给显示出来,才有 (,2) 这样的结果。
我只能说是 objdump 死板,或者说不够智能,这样很容易迷惑人
binutils 2.20 显示结果又不一样
[root@ssq_pppoe binutils]# printf "\xff\x34\x65\xf4\x94\x04\x08" > x1.dat
[root@ssq_pppoe binutils]# ./objdump -b binary -m i386 -D x1.dat
x1.dat: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ff 34 65 f4 94 04 08 pushl 0x80494f4(,%eiz,2)
[root@ssq_pppoe binutils]# ./objdump -b binary -m i386 -M x86-64 -D x1.dat
x1.dat: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ff 34 65 f4 94 04 08 pushq 0x80494f4(,%riz,2)
[root@ssq_pppoe binutils]# ./objdump -b binary -m i386 -M x86-64,intel -D x1.dat
x1.dat: file format binary
Disassembly of section .data:
00000000 <.data>:
0: ff 34 65 f4 94 04 08 push QWORD PTR [riz*2+0x80494f4]
多出了一个riz
查了一下
Changes from binutils 2.18.50.0.1:
7. Add fake index registers, EIZ/RIZ, to x86 assembler/disassembler.
不知道是什么意思?
以我的为准吧,我所说的是肯定不会错的。
但是,我可以解释一下,objdump 为什么会这样的
(1) eiz/riz 是什么?
如果,我没猜错的话,它们是:eip 和 rip ----> 它们是 zero 的 eip/rip
意思是:为 0 eip/rip 寄存器
那么:push QWORD PTR [riz*2+0x80494f4] ===> 由于为 riz * 2 等于 0
>>> 最终结果还是等于: push qword ptr [0x080494f4]
这个 eiz 与 riz 是 gnu binutils 自已加上去的东西,并不是 intel 的东西
gnu objdump 又把别人给忽优了
(2)解释一个为什么会有 push QWORD PTR [riz*2+0x80494f4] 这样的思维?
那是因为:在 x64 体系 64 位模式下,新增了一种寻址方式: rip 相对寻址(rip-rellative 寻址)
这种寻址是这样的:
当 modrm.mod = 0 , modrm.r/m = 5 的时候就出现 [RIP + offset] 这种寻址,它是不需要 SIB 字节的。
在原来的 32 位下, modrm.mod = 0 & modrm.r/m = 5 的时候,它是 [disp32] 这种寻址
那么:在 modrm.mod = 0, modrm.r/m = 4 并且 sib.base = 5,sib.index = 4 时,出现的是:[disp32] 这种寻址
刚好和 modrm.mod = 0, modrm.r/m = 5 时的寻址是一样的。
这样就产生了重码,一个是仅仅需要 modrm 就可以了,一个是 modrm + sib 两个字节
SO:
我不知道,binutils 是出于什么考虑,要把 [disp32] 和 [rip+offset] 这两种寻址混在一起,binutils 把它们统一起来了。
但是,最终结果,由于 eiz/riz 等于 0 值的 eip/rip
因此,它们的结果是一样的。
只是,显示上这样引起了很大的混乱
我想可能的解释是想让我们知道
pushq 0x80494f4(,%riz,2)
的指令序列是不同于
pushq 0x80494f4
反过来说,让gas据此生成不同的指令序列
这里证实了我的想法,可以使用.allow_index_reg伪指令指示%riz或%eiz的使用
[root@ssq_pppoe i386]# more /root/binutils-2.20/gas/testsuite/gas/i386/x86-64-sib.s
复制代码
这对编译器内部有用
但对用户来说, objump 直接显示出来,就显得很不智能和造成困拢了