为什么在主力开始做gcc的推%RBX? [英] Why does gcc push %rbx at the beginning of main?

查看:216
本文介绍了为什么在主力开始做gcc的推%RBX?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

GCC的最新版本是生产大会,没有任何意义了我。我编不使用优化code;但是,这code的某些部分没有意义,甚至没有任何优化。

下面是C源代码:

 的#include<&stdio.h中GT;   诠释的main()
   {
     int类型的= 1324;
     INT B = 5657;
     INT差= 9876;
     INT printf_answer = 2221;     差值= A - B:     printf_answer =的printf(%d个+%D =%d个\\ N,A,B,差);     回差;
   }

它产生该组件:

  .fileexampleIML-1b.c
    .section伪.RODATA
.LC0:
    .string%D +%D =%d个\\ N
    。文本
.globl主
    .TYPE为主,@function
主要:
.LFB0:
    .cfi_startproc
    pushq%RBP
    .cfi_def_cfa_offset 16
    .cfi_offset 6,-16
    MOVQ%RSP,RBP%
    .cfi_def_cfa_register 6
    pushq%RBX
    SUBQ $ 24%RSP
    MOVL $ 1324 -32(RBP%)
    MOVL $ 5657,-28(RBP%)
    MOVL $ 9876,-24(RBP%)
    MOVL $ 2221 -20(RBP%)
    MOVL -28(RBP%),%EAX
    MOVL -32(RBP%),EDX%
    MOVL%EDX,ECX%
    subl%EAX,ECX%
    MOVL%ECX,EAX%
    MOVL%eax中,-24(RBP%)
    MOVL $ .LC0,EAX%
    MOVL -24(RBP%),ECX%
    MOVL -28(RBP%),EDX%
    MOVL -32(RBP%),EBX%
    .cfi_offset 3,-24
    MOVL%EBX,ESI%
    MOVQ%RAX,%RDI
    MOVL $ 0,%EAX
    调用printf
    MOVL%eax中,-20(RBP%)
    MOVL -24(RBP%),%EAX
    addq $ 24%RSP
    popq%RBX
    离开
    .cfi_def_cfa 7,8
    RET
    .cfi_endproc
.LFE0:
    .size为主,。,主
    .identGCC(GNU)4.4.6 20120305(红帽4.4.6-4)
    .section伪.note.GNU堆栈,,@ PROGBITS

有几件事情是没有意义的:

(1)我们为什么力推%RBX?什么是%RBX需要被拯救?

(2)我们为什么要减去前移动EDX%到%ECX?什么不只是做子%EAX,EDX%

(3)同样,为什么要从%ECX回到%EAX移动存储值之前?

(4)编译器投入内存位置-32(RBP%)的变量。除非我添加错了,是不是-32(RBP%)等于堆栈指针?应该不是所有的局部变量保存在值小于的当前堆栈指针?

我使用这个版本的GCC的:

[eos17:〜/课程/ CS451 / IntelMachineLanguage] $ gcc的-v
使用内置的规格。
目标:x86_64的-红帽Linux的
配置:../configure - preFIX =的/ usr --mandir =的/ usr / share / man的--infodir =的/ usr /共享/信息--with-bugurl = HTTP://bugzilla.redhat。 COM / Bugzilla的--enable-引导--enable-共享--enable-线程= POSIX --enable-检查=发行--with-系统的zlib --enable -__ cxa_atexit --disable-libunwind的异常--enable- GNU的唯一对象--enable-语言= C,C ++,objc,OBJ-C ++,JAVA,FORTRAN,ADA --enable-java的AWT = GTK --disable-DSSI --with-java主=的/ usr /lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj里,多文件--enable-java的维护者模式--with-ECJ-JAR =的/ usr /股/ JAVA /月食-ecj.jar --disable-libjava-multilib的--with-PPL --with-cloog --with调=通用--with-arch_32 = i686的--build = x86_64的-红帽Linux的
线程模型:POSIX
gcc版本4.4.6 20120305(红帽4.4.6-4)(GCC)


解决方案

  GCC决定堆栈的使用方式。主叫方和被叫方在x86之间的合同:    *后调用指令:
          在函数第一个指令的0%EIP点
          0%ESP + 4点,第一个参数
          0%ESP指向的返回地址
    *后ret指令:
          0%EIP包含返回地址
          0%尤指争论点由主叫方推
          Ø调用的函数可能已经丢弃参数
          0%eax中包含的返回值(或垃圾,如果功能无效)
          0%ECX,EDX%可丢弃
          0%EBP,EBX%,%ESI,EDI%必须包含从通话时间的内容
    *术语:
          0%EAX,ECX%,%edx中的来电者保存寄存器
          0%EBP,EBX%,%ESI,EDI%是被调用者保存寄存器

的主要功能是像在这种情况下的任何其他功能。海湾合作委员会决定使用 EBX 中间计算,所以preserves它的价值。

The latest version of gcc is producing assembly that doesn't make sense to me. I compiled the code using no optimization; but, some parts of this code don't make sense, even with no optimization.

Here is the C source:

  #include <stdio.h>

   int main()
   {
     int a = 1324;
     int b = 5657;
     int difference = 9876;
     int printf_answer = 2221;

     difference = a - b;

     printf_answer = printf("%d + %d = %d\n", a, b, difference);

     return difference;
   }

It produces this assembly:

    .file   "exampleIML-1b.c"
    .section    .rodata
.LC0:
    .string "%d + %d = %d\n"
    .text
.globl main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $24, %rsp
    movl    $1324, -32(%rbp)
    movl    $5657, -28(%rbp)
    movl    $9876, -24(%rbp)
    movl    $2221, -20(%rbp)
    movl    -28(%rbp), %eax
    movl    -32(%rbp), %edx
    movl    %edx, %ecx
    subl    %eax, %ecx
    movl    %ecx, %eax
    movl    %eax, -24(%rbp)
    movl    $.LC0, %eax
    movl    -24(%rbp), %ecx
    movl    -28(%rbp), %edx
    movl    -32(%rbp), %ebx
    .cfi_offset 3, -24
    movl    %ebx, %esi
    movq    %rax, %rdi
    movl    $0, %eax
    call    printf
    movl    %eax, -20(%rbp)
    movl    -24(%rbp), %eax
    addq    $24, %rsp
    popq    %rbx
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (GNU) 4.4.6 20120305 (Red Hat 4.4.6-4)"
    .section    .note.GNU-stack,"",@progbits

Several things don't make sense:

(1) Why are we pushing %rbx? What is in %rbx that needs to be saved?

(2) Why are we moving %edx to %ecx before subtracting? What doesn't it just do sub %eax, %edx?

(3) Similarly, why the move from %ecx back to %eax before storing the value?

(4) The compiler is putting the variable a in memory location -32(%rbp). Unless I'm adding wrong, isn't -32(%rbp) equal to the stack pointer? Shouldn't all local variables be stored at values less than the current stack pointer?

I'm using this version of gcc:

[eos17:~/Courses/CS451/IntelMachineLanguage]$ gcc -v Using built-in specs. Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC)

解决方案

GCC dictates how the stack is used. Contract between caller and callee on x86:

    * after call instruction:
          o %eip points at first instruction of function
          o %esp+4 points at first argument
          o %esp points at return address 
    * after ret instruction:
          o %eip contains return address
          o %esp points at arguments pushed by caller
          o called function may have trashed arguments
          o %eax contains return value (or trash if function is void)
          o %ecx, %edx may be trashed
          o %ebp, %ebx, %esi, %edi must contain contents from time of call 
    * Terminology:
          o %eax, %ecx, %edx are "caller save" registers
          o %ebp, %ebx, %esi, %edi are "callee save" registers

The main function is like any other function in this context. gcc decided to use ebx for intermediate calculations, so it preserves its value.

这篇关于为什么在主力开始做gcc的推%RBX?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆