题目是:
以下程序输出是____。
1
2
3
4
5
6
7
8
9
10
|
#include <iostream>
using namespace std;
int
main(
void
)
{
const
int
a =
10
;
int
* p = (
int
*)(&a);
*p =
20
;
cout<<
"a = "
<<a<<
", *p = "
<<*p<<endl;
return
0
;
}
|
B a = 10, *p = 10
C a = 20, *p = 20
D a = 10, *p = 20
E a = 20, *p = 10
运行时,得到的是答案是D,通过命令objdump -S a.o反汇编:
0000000000400916 <main>:#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 53 push %rbx
40091b: 48 83 ec 28 sub $0x28,%rsp
40091f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400926: 00 00
400928: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092c: 31 c0 xor %eax,%eax
const int a = 10;
40092e: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp) //把10放入%rbp - 0x24地中存起来
int * p = (int *)(&a);
400935: 48 8d 45 dc lea -0x24(%rbp),%rax //把%rbp - 0x24放入寄存器rax中,注意,此处不是值,而是把地址放入这个寄存器中,rax寄存器保存的是地址。
400939: 48 89 45 e0 mov %rax,-0x20(%rbp) //把寄存器rax的值(也就是上一步//得到的地址)放入地址%rbp - 0x20中存起来。
*p = 20;
40093d: 48 8b 45 e0 mov -0x20(%rbp),%rax //同上一步,只是反过来赋值无变化
400941: c7 00 14 00 00 00 movl $0x14,(%rax) //把20放入%rbp-0x24地址中存起来,//也就是把存放a的地址中,保存了20.此处应该是a = 20了,*p = 20。
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400947: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094b: 8b 18 mov (%rax),%ebx
40094d: be 84 0a 40 00 mov $0x400a84,%esi
400952: bf 80 10 60 00 mov $0x601080,%edi
400957: e8 84 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40095c: be 0a 00 00 00 mov $0xa,%esi
400961: 48 89 c7 mov %rax,%rdi
400964: e8 17 fe ff ff callq 400780 <_ZNSolsEi@plt>
400969: be 89 0a 40 00 mov $0x400a89,%esi
40096e: 48 89 c7 mov %rax,%rdi
400971: e8 6a fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400976: 89 de mov %ebx,%esi
400978: 48 89 c7 mov %rax,%rdi
40097b: e8 00 fe ff ff callq 400780 <_ZNSolsEi@plt>
400980: be 10 08 40 00 mov $0x400810,%esi
400985: 48 89 c7 mov %rax,%rdi
400988: e8 73 fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
40098d: b8 00 00 00 00 mov $0x0,%eax
}
从上面的加粗部分汇编以及我的注释中可以看出,在汇编当中还没有进入打印时,在相应的内存中已经对a修改为20了,而且这个值也没有保存在寄存器中,说明后面的打印是需要访问这个地址的。答案是会得到a = 10, *p = 20,也就是说a没有得到更新,我把代码改一下,使得对a的定义改为:
const volatile a = 10.这样,对a的访问强制访问内存,编译执行后得到了a = 20, *p = 20的答案。由此可以看出估计是取a值的时候直接从寄存器里面取值了,但是汇编代码中a的值没有存在寄存器里面,哪里错了?我考虑对修改后的代码进行反汇编,得到:
0000000000400916 <main>:
#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 41 54 push %r12
40091c: 53 push %rbx
40091d: 48 83 ec 20 sub $0x20,%rsp
400921: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400928: 00 00
40092a: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092e: 31 c0 xor %eax,%eax
const volatile int a = 10;
400930: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp)
int * p = (int *)(&a);
400937: 48 8d 45 dc lea -0x24(%rbp),%rax
40093b: 48 89 45 e0 mov %rax,-0x20(%rbp)
*p = 20;
40093f: 48 8b 45 e0 mov -0x20(%rbp),%rax
400943: c7 00 14 00 00 00 movl $0x14,(%rax)
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400949: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094d: 8b 18 mov (%rax),%ebx
40094f: 44 8b 65 dc mov -0x24(%rbp),%r12d
400953: be 94 0a 40 00 mov $0x400a94,%esi
400958: bf 80 10 60 00 mov $0x601080,%edi
40095d: e8 7e fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400962: 44 89 e6 mov %r12d,%esi
400965: 48 89 c7 mov %rax,%rdi
400968: e8 13 fe ff ff callq 400780 <_ZNSolsEi@plt>
40096d: be 99 0a 40 00 mov $0x400a99,%esi
400972: 48 89 c7 mov %rax,%rdi
400975: e8 66 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40097a: 89 de mov %ebx,%esi
40097c: 48 89 c7 mov %rax,%rdi
40097f: e8 fc fd ff ff callq 400780 <_ZNSolsEi@plt>
400984: be 10 08 40 00 mov $0x400810,%esi
400989: 48 89 c7 mov %rax,%rdi
40098c: e8 6f fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
400991: b8 00 00 00 00 mov $0x0,%eax
}
对比一下这两个汇编,发现一模一样,看来是我们的objdump命令的问题了,我估计objdump -S命令应该得到的是非常标准没有经过优化的汇编代码(有大神可以可以确定的话,请告诉我,给出你从哪里看到的,比如书本名Pxxx页)。
到这里,结束了,你应该早就明白了,我扯远了。