编译器可以生成无用的汇编代码吗?

DJ_*_*Joe -1 c x86 assembly gcc

我试图找到从ac程序生成的汇编代码的含义.这是C中的程序:

int* a = &argc;
int b = 8;
a = &b;
Run Code Online (Sandbox Code Playgroud)

以下是使用说明生成的汇编代码.有一部分我不明白:

主要序言:

leal    4(%esp), %ecx
andl    $-16, %esp
pushl   -4(%ecx)
pushl   %ebp
movl    %esp, %ebp
pushl   %ecx
subl    $36, %esp
Run Code Online (Sandbox Code Playgroud)

在%eax中加载argc的地址:

movl    %ecx, %eax
Run Code Online (Sandbox Code Playgroud)

我得不到的部分:

movl    4(%eax), %edx
movl    %edx, -28(%ebp)
Run Code Online (Sandbox Code Playgroud)

Stack-Smashing Protector代码(设置):

movl    %gs:20, %ecx
movl    %ecx, -12(%ebp)
xorl    %ecx, %ecx
Run Code Online (Sandbox Code Playgroud)

在a和b中加载值(参见main.c):

movl    %eax, -16(%ebp)
movl    $8, -20(%ebp)
Run Code Online (Sandbox Code Playgroud)

修改a(a =&b)的值:

leal    -20(%ebp), %eax
movl    %eax, -16(%ebp)
Run Code Online (Sandbox Code Playgroud)

Stack-Smashing Protector代码(验证堆栈是否正常):

movl    $0, %eax
movl    -12(%ebp), %edx
xorl    %gs:20, %edx
je  .L7
call    __stack_chk_fail
Run Code Online (Sandbox Code Playgroud)

如果堆栈是Ok:

.L7:
    addl    $36, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
Run Code Online (Sandbox Code Playgroud)

所以我不理解的部分是修改-28(%ebp)中的值,这是一个从未使用过的地址.有人知道为什么会产生这个部分吗?

klu*_*utt 6

查看编译器功能的好方法.我假设你有一个名为main.c的文件:

int main(int argc, char **argv) 
{
    int* a = &argc;
    int b = 8;
    a = &b;
}
Run Code Online (Sandbox Code Playgroud)

使用调试信息编译到目标文件:

$ gcc -c -g main.c
Run Code Online (Sandbox Code Playgroud)

查看程序集:

$ objdump -S main.o

main.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
int main(int argc, char **argv)
{
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   89 7d ec                mov    %edi,-0x14(%rbp)
   7:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
    int* a = &argc;
   b:   48 8d 45 ec             lea    -0x14(%rbp),%rax
   f:   48 89 45 f8             mov    %rax,-0x8(%rbp)
    int b = 8;
  13:   c7 45 f4 08 00 00 00    movl   $0x8,-0xc(%rbp)
    a = &b;
  1a:   48 8d 45 f4             lea    -0xc(%rbp),%rax
  1e:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  22:   b8 00 00 00 00          mov    $0x0,%eax
}
  27:   5d                      pop    %rbp
  28:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

然后使用完全优化做同样的事情:

$ gcc -c -g -O3 main.c 
Run Code Online (Sandbox Code Playgroud)

并再次查看程序集:

$ objdump -S main.o

main.o:     file format elf64-x86-64


Disassembly of section .text.startup:

0000000000000000 <main>:
int main(int argc, char **argv)
{
    int* a = &argc;
    int b = 8;
    a = &b;
}
   0:   31 c0                   xor    %eax,%eax
   2:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

所以答案是肯定的.编译器可以生成不需要的指令.这就是你打开优化的原因.当它们被关闭时,编译器会以一种非常通用的方式完成它的工作而不用考虑.例如,它为未使用的变量保留空间.