Assembly 在x86-64 AT&;中,地址前的星号*表示什么;T组装?
下面这行是什么意思Assembly 在x86-64 AT&;中,地址前的星号*表示什么;T组装?,assembly,x86-64,att,addressing-mode,Assembly,X86 64,Att,Addressing Mode,下面这行是什么意思 ... 401147: ff 24 c5 80 26 40 00 jmpq *0x402680(,%rax,8) ... 内存地址前面的星号是什么意思? 另外,当内存访问方法缺少它的第一个寄存器值时,这意味着什么 通常它类似于(“%register”,%rax,8),但在本例中它没有第一个寄存器 有什么提示吗?这是跳转到内存中包含的地址。地址存储在内存中的地址rax*8+0x402680,其中rax是当前的rax值(当此指令执行时)。将内容转换为英特尔语法总是让内
...
401147: ff 24 c5 80 26 40 00 jmpq *0x402680(,%rax,8)
...
内存地址前面的星号是什么意思?
另外,当内存访问方法缺少它的第一个寄存器值时,这意味着什么
通常它类似于(“%register”,%rax,8),但在本例中它没有第一个寄存器
有什么提示吗?这是跳转到内存中包含的地址。地址存储在内存中的地址
rax*8+0x402680
,其中rax
是当前的rax
值(当此指令执行时)。将内容转换为英特尔语法总是让内容更清晰:
FF24C5 80264000 JMP QWORD PTR [RAX*8+402680]
这是AT&T汇编语法:
- 源在目的之前
- 助记符后缀表示操作数的大小(
表示四元组,等等)q
- 寄存器前缀为
,立即值前缀为%
$
- 有效地址的格式为
(DISP+BASE+INDEX*SCALE)DISP(基、索引、刻度)
- 用
指示的间接跳转/调用操作数(与直接操作相对)*
jmpq
,它存储在%rax*8+0x402680
中,是一个四字长
AT&T语法需要一种方法来区分RIP=foo(
jmp-foo
)和来自某个符号地址的RIP=load(jmp*foo
)。请记住movl$1,foo
是绝对地址foo
的存储
对于其他寻址模式,您正在进行的跳转/呼叫类型之间没有歧义,除了裸标签之外的任何内容都必须是间接的。(如果您执行jmp%rax
或jmp 24(%rax)
或除裸符号名称以外的任何操作,GAS将推断并警告没有*
的间接跳转。)
(在64位模式下,您通常会使用
jmp*foo(%rip)
将全局变量加载到rip中,而不是使用像jmp*foo
这样的32位绝对地址。但这种可能性是存在的,在设计AT&T语法时,x86-64之前,这是正常的操作方式。)实际上这是计算表jmp,其中0x402680是tabele的地址,rax是8字节(qword)指针的索引。正如Necrolis所写,Intel语法使其更为明显,但实际上更为清晰。线路
jmpq *0x402680(,%rax,8)
将在RTN中描述为:
RIP <- M[0x402680 + (8 * RAX)]
jmpq
只是到给定地址的无条件跳转。“q”表示我们正在处理四字(64位长)
*0x402680(,%rax,8)
:这是在x-86程序集中写入地址的一种方法。您的说法是正确的,通常在第一个逗号之前有一个寄存器,但是如果没有指定寄存器,您仍然遵循相同的规则
格式的工作方式如下:
D(reg1,reg2,scalingFactor)
其中D代表位移。位移基本上只是一个整数reg1
是第一个或基址寄存器reg2
是第二个寄存器,scalingFactor
是2、4、8中的一个(甚至可能是1,但我不确定)。现在,您可以通过以下方式简单地添加值来获得您的地址:位移+(位于reg1
的值)+scalingFactor
*(位于reg2
的值)
我不完全确定地址前面的星号是什么意思,但我猜这意味着位移值存储在该地址
希望这有帮助。最简单的例子 为了让事情更清楚:
.data
# Store he address of the label in the data section.
symbol: .int label
.text
# Jumps to label.
jmp *symbol
label:
如果没有*
,它将跳转到.data
部分中的符号的地址,然后执行segfault
我觉得这种语法有点不一致,因为对于大多数指令:
mov symbol, %eax
mov label, %eax
已将数据移动到地址symbol
,并且$symbol
用于该地址。英特尔语法在这一点上更为一致,因为它总是使用[]
进行解引用
*
当然是C取消引用操作符的助记符*ptr
,但是它前面的星号会有区别吗?我明白你说的话在其他方面是有道理的。我认为首先星号将从内存位置0x402680中取出数据。所以基本上,它将变成%rax*8+mem[0x402680],星号只指定这是一个绝对跳转jmp
会将数据从指定的内存位置中取出,不管怎样。*
实际上意味着间接,就像C去引用操作符一样。考虑<代码> JMP Fo< <代码>(RIP= FO)vs.代码> JMP*Fo< <代码>(RIP= FO内存内容)。当然,通常使用RIP相对寻址来访问代码指针变量foo,比如jmp*foo(%RIP)
,但是foo
与*foo
的对比很好地说明了为什么AT&T语法需要使用*
来消除歧义。谁投了反对票,请解释一下原因?仅仅是反英特尔语法不是理由…@MichaelFoukarakis:除了用英语逐字重复数学之外,在使用英特尔语法时没有什么真正需要补充的。这并不能回答这个问题。@MichaelO这实际上是你能给出的最简洁、最直接的答案。如果你看一下这里评级最高的回复,它实际上是一个从左到右读取的英特尔助记符的要点列表……当C代码完成If-else或switch语句时,在汇编代码中经常使用跳转表。它允许以恒定的时间传递控件,而不必检查许多单独的相等性检查。re:“不一致性”:在标签处跳转“访问”代码jmp foo
使CPU将foo
处的字节作为代码加载(通过设置RIP)。与mov foo相比,%eax
将foo处的字节加载到寄存器中。我不确定使用jmp$foo
进行直接相关跳转的语法设计是否是好的,因为
mov symbol, %eax
mov label, %eax