8

gccの最新バージョンは、私には意味のないアセンブリを生成しています。最適化を使用せずにコードをコンパイルしました。ただし、このコードの一部は、最適化を行わなくても意味がありません。

Cソースは次のとおりです。

  #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;
   }

このアセンブリを生成します。

    .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

意味をなさないことがいくつかあります。

(1)なぜ%rbxをプッシュするのですか?保存する必要がある%rbxには何がありますか?

(2)減算する前に%edxを%ecxに移動するのはなぜですか?それはただ何をしませんsub %eax, %edxか?

(3)同様に、値を保存する前に、なぜ%ecxから%eaxに戻るのですか?

(4)コンパイラは変数aをメモリ位置-32(%rbp)に配置しています。間違って追加しない限り、-32(%rbp)はスタックポインタと同じではありませんか?すべてのローカル変数を現在のスタックポインタよりも小さい値で格納する必要がありますか?

私はこのバージョンのgccを使用しています:

[eos17:〜/ Courses / CS451 / IntelMachineLanguage] $gcc-v組み込みの仕様を使用します。ターゲット:x86_64-redhat-linux構成:../ 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スレッドモデル:posixgccバージョン4.4.620120305(RedHat4。

4

2 に答える 2

18
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

メイン関数は、このコンテキストの他の関数と同様です。gcc はebx中間計算に使用することを決定したため、その値を保持します。

于 2012-10-04T21:56:37.477 に答える
5

デフォルトでは、gcc は最適化を無効にしてコンパイルします。

-O2最適化スイッチの 1 つ (または など)で有効にする必要があります-O3

そうすれば、冗長で一見無意味に見えるものは見えなくなります。

についてrbxは、呼び出し規約が必要とするため、保存する必要があります。関数によって変更されるため ( movl -32(%rbp), %ebx)、明示的に保存および復元する必要があります。

于 2012-10-04T22:02:50.867 に答える