当我在gdb中使用disas
命令并使用以下代码时:
int main(){
char*a;
size_t r;
return 1;
}
我得到这个结果:
0x080483db <+0>: push %ebp
0x080483dc <+1>: mov %esp,%ebp
0x080483de <+3>: mov $0x1,%eax
0x080483e3 <+8>: pop %ebp
0x080483e4 <+9>: ret
我不明白为什么char*a
和size*t
没有说明。
如何获得a
值和r
值的地址?它们甚至存在吗?
答案 0 :(得分:4)
声明char*a;
和size_t r;
自己不做任何事情;他们宁愿告诉编译器您希望能够使用标识符a
和r
来存储值,并且其生命周期仅限于main
执行的持续时间。另一方面,大多数汇编说明(除了nops等)执行某些操作。
如果您在这些变量中存储和访问值,或者获取了它们的地址并使用了这些地址,而这在某种意义上并不等同于什么都不做,那么您会看到编译器发出了腾出空间的代码(通常通过调整堆栈指针,或将某些寄存器推入堆栈以保存其值,以便为您的数据提供额外的可用寄存器)并存储/加载值。
答案 1 :(得分:0)
您需要进行实验,以使无效代码不会得到优化。
unsigned int fun0 ( void )
{
return(0x12345678);
}
char * fun1 ( void )
{
char *x;
x = (char *)0x12345678;
return(x);
}
unsigned int fun2 ( unsigned int x )
{
return(x+12);
}
unsigned int * fun3 ( unsigned int *x )
{
return(x+3);
}
给予类似的东西
Disassembly of section .text:
00000000 <fun0>:
0: e59f0000 ldr r0, [pc] ; 8 <fun0+0x8>
4: e12fff1e bx lr
8: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
0000000c <fun1>:
c: e59f0000 ldr r0, [pc] ; 14 <fun1+0x8>
10: e12fff1e bx lr
14: 12345678 eorsne r5, r4, #120, 12 ; 0x7800000
00000018 <fun2>:
18: e280000c add r0, r0, #12
1c: e12fff1e bx lr
00000020 <fun3>:
20: e280000c add r0, r0, #12
24: e12fff1e bx lr
答案 2 :(得分:0)
这里要注意的是C语言的as-if rule表示编译后的程序只需要产生相同的可观察的行为。
由于程序的可观察行为与
相同int main(){
return 1;
}
这就是编译后的代码的作用。
这不仅适用于声明,而且可以任意复杂。例如常见的hello world程序:
#include <stdio.h>
int main(){
printf("Hello world!\n");
}
具有可观察到的行为,等同于
#include <stdio.h>
int main(){
puts("Hello world!");
}
后一个程序是使用-O3
编译前一个程序时得到的结果:
.LC0:
.string "Hello world!"
main:
leaq .LC0(%rip), %rdi
subq $8, %rsp
call puts@PLT
xorl %eax, %eax
addq $8, %rsp
ret