【发布时间】:2018-11-04 08:05:39
【问题描述】:
我设置了一个实验,看看它是否有效
int *p;
p[0] = 3;
我的想法是编译器给p一个随机值,我可以把它当作一个数组。
但结果是分段错误,我看不懂汇编代码。
0x0000000000401530 <+0>: push %rbp
0x0000000000401531 <+1>: mov %rsp,%rbp
0x0000000000401534 <+4>: sub $0x30,%rsp
0x0000000000401538 <+8>: mov %ecx,0x10(%rbp)
0x000000000040153b <+11>: mov %rdx,0x18(%rbp)
0x000000000040153f <+15>: callq 0x402170 <__main>
0x0000000000401544 <+20>: mov -0x8(%rbp),%rax
=> 0x0000000000401548 <+24>: movl $0x3,(%rax)
0x000000000040154e <+30>: mov $0x0,%eax
0x0000000000401553 <+35>: add $0x30,%rsp
0x0000000000401557 <+39>: pop %rbp
0x0000000000401558 <+40>: retq
我在 google 上搜索,mov 是 Intel 风格,movl 是 AT&T 风格。这两种风格怎么会融合在一起?
在这一行:
mov -0x8(%rbp),%rax
似乎将地址 rbp-0x8 的值移动到注册 rax,对吧? 这个“-0x8(%rbp)”是随机值到p的吗?
我认为 %rax 不是 p,因为在下一行 CPU 将 $0x3 给 %rax。似乎 %rax 是数组的第一个内存。
如何解释这个汇编代码?谢谢。
【问题讨论】:
-
谢谢。为什么将 32 位值 3 移动到寄存器 rax 是分段错误?
-
因为它试图将立即值移动到您的程序无权访问的某个地址。
-
@iBug:AT&T 语法仅在不明确时才需要操作数大小的后缀(例如直接源和内存目标)。
mov $0, %eax是 32 位操作数大小,由 EAX 寄存器隐含。普通的mov绝不意味着16 位。这种反汇编只在不明确的地方使用后缀,不像objdump -d在每条指令上都使用后缀。 (@Andy:整个列表都是纯 AT&T 语法,总是在右边显示目的地)。 -
@iBug:不,这将是一个错误:将其放入
bar.S并与gcc -c bar.S组装,您将收到此汇编错误消息bar.S:1: Error: no instruction mnemonic suffix given and no register operands; can't size instruction。即操作数大小不明确,因此汇编器拒绝汇编它。 -
@iBug
mov不一定是16位操作!movw是 16 位mov,不带后缀的mov移动其操作数所需的位数。