Programming

gcc의 C / C ++ 소스에서 어셈블러 출력을 어떻게 얻습니까?

procodes 2020. 3. 5. 08:03
반응형

gcc의 C / C ++ 소스에서 어셈블러 출력을 어떻게 얻습니까?


어떻게합니까?

무언가가 어떻게 컴파일되는지 분석하고 싶다면 방출 된 어셈블리 코드를 어떻게 얻을 수 있습니까?


사용 -SGCC (또는 g ++) 옵션을 선택합니다.

gcc -S helloworld.c

그러면 helloworld.c에서 전 처리기 (cpp)가 실행되고 초기 컴파일을 수행 한 다음 어셈블러가 실행되기 전에 중지됩니다.

기본적으로 이것은 파일을 출력합니다 helloworld.s. -o옵션 을 사용하여 출력 파일을 계속 설정할 수 있습니다 .

gcc -S -o my_asm_output.s helloworld.c

물론 원본 소스가있는 경우에만 작동합니다. 결과 객체 파일 만있는 경우 옵션 objdump을 설정하여 --disassemble(또는 -d약식 양식으로)을 사용하는 방법이 있습니다.

objdump -S --disassemble helloworld > helloworld.dump

이 옵션은 객체 파일에 대해 디버깅 옵션이 활성화되어 있고 ( -g컴파일시) 파일이 제거되지 않은 경우에 가장 효과적 입니다.

실행 file helloworld하면 objdump를 사용하여 얻을 수있는 세부 수준에 대한 정보가 제공됩니다.


이것은 어떤 코드가 어떤 코드를 생성하는지 쉽게 알 수 있도록 C 코드 + 라인 번호가 섞인 asm 코드를 생성합니다.

# create assembler code:
c++ -S -fverbose-asm -g -O2 test.cc -o test.s
# create asm interlaced with source lines:
as -alhnd test.s > test.lst

에서 발견 프로그래머를위한 알고리즘 , 3 페이지 (PDF 파일의 전체 15 페이지입니다).


다음 명령 줄은 Christian Garbin의 블로그에 있습니다.

g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt

암시 적 캐스트가 포함 된 루틴에 대해 Win-XP의 DOS 창에서 G ++을 실행했습니다.

c:\gpp_code>g++ -g -O -Wa,-aslh horton_ex2_05.cpp >list.txt
horton_ex2_05.cpp: In function `int main()':
horton_ex2_05.cpp:92: warning: assignment to `int' from `double'

출력은 원래 C ++ 코드와 반복되는 어셈블 된 생성 코드입니다 (C ++ 코드는 생성 된 asm 스트림에서 주석으로 표시됨)

  16:horton_ex2_05.cpp **** using std::setw;
  17:horton_ex2_05.cpp ****
  18:horton_ex2_05.cpp **** void disp_Time_Line (void);
  19:horton_ex2_05.cpp ****
  20:horton_ex2_05.cpp **** int main(void)
  21:horton_ex2_05.cpp **** {
 164                    %ebp
 165                            subl $128,%esp
?GAS LISTING C:\DOCUME~1\CRAIGM~1\LOCALS~1\Temp\ccx52rCc.s
166 0128 55                    call ___main
167 0129 89E5          .stabn 68,0,21,LM2-_main
168 012b 81EC8000      LM2:
168      0000
169 0131 E8000000      LBB2:
169      00
170                    .stabn 68,0,25,LM3-_main
171                    LM3:
172                            movl $0,-16(%ebp)

-S 스위치 사용

g++ -S main.cpp

또는 gcc와 함께

gcc -S main.c

또한 이것을보십시오


당신이보고 싶은 것이 출력의 링크에 달려 있다면, 출력 객체 파일 / 실행 파일에 대한 objdump는 위에서 언급 한 gcc -S 외에도 유용 할 수 있습니다. Loren Merritt의 기본 objdump 구문을 읽기 쉬운 nasm 구문으로 변환하는 매우 유용한 스크립트는 다음과 같습니다.

#!/usr/bin/perl -w
$ptr='(BYTE|WORD|DWORD|QWORD|XMMWORD) PTR ';
$reg='(?:[er]?(?:[abcd]x|[sd]i|[sb]p)|[abcd][hl]|r1?[0-589][dwb]?|mm[0-7]|xmm1?[0-9])';
open FH, '-|', '/usr/bin/objdump', '-w', '-M', 'intel', @ARGV or die;
$prev = "";
while(<FH>){
    if(/$ptr/o) {
        s/$ptr(\[[^\[\]]+\],$reg)/$2/o or
        s/($reg,)$ptr(\[[^\[\]]+\])/$1$3/o or
        s/$ptr/lc $1/oe;
    }
    if($prev =~ /\t(repz )?ret / and
       $_ =~ /\tnop |\txchg *ax,ax$/) {
       # drop this line
    } else {
       print $prev;
       $prev = $_;
    }
}
print $prev;
close FH;

나는 이것이 gcc -S의 출력에도 사용될 수 있다고 생각합니다.


모두가 말했듯이 -S 옵션을 사용하십시오. -save-temps 옵션을 사용하면 사전 처리 된 파일 ( .i), 어셈블리 파일 ( .s) 및 객체 파일 (* .o)을 얻을 수도 있습니다 . (-E, -S 및 -c를 사용하여 각각 가져 오기)


모든 사람들이 지적했듯이 -SGCC 옵션을 사용하십시오 . 또한 최적화 옵션을 추가할지 여부에 따라 결과가 다를 수 있음을 추가하고 싶습니다 ( -O0아무것도, -O2적극적인 최적화의 경우).

특히 RISC 아키텍처에서 컴파일러는 최적화를 수행 할 때 인식을 훨씬 뛰어 넘는 코드를 종종 변환합니다. 결과를 보는 것은 인상적이며 매력적입니다!


앞에서 언급했듯이 -S 플래그를보십시오.

또한 '-fdump-tree'플래그 계열, 특히 '-fdump-tree-all'을 보면 gcc의 중간 형식을 볼 수 있습니다. 이것들은 종종 어셈블러보다 더 읽기 쉽습니다 (최소한 나에게), 최적화 패스가 어떻게 수행되는지 볼 수 있습니다.


LLVM 어셈블리를 찾고 있다면 :

llvm-gcc -emit-llvm -S hello.c

-S 옵션을 사용하십시오.

gcc -S program.c

아마도 2008 년부터 질문이 있었기 때문에 답변 중이 가능성을 보지 못했지만 2018 년에는 Matt Goldbolt의 온라인 웹 사이트 https://godbolt.org를 사용할 수 있습니다

로컬 git clone을 사용하고 자신의 프로젝트를 실행할 수도 있습니다 https://github.com/mattgodbolt/compiler-explorer


보낸 사람 : http://www.delorie.com/djgpp/v2faq/faq8_20.html

gcc -c -g -Wa, -a, -ad [다른 GCC 옵션] foo.c> foo.lst

PhirePhly의 답변 대신 또는 모두가 말했듯이 -S를 사용하십시오.


이 commnads의 출력

Windows에서 C 프로그램의 어셈블리 코드를 보거나 인쇄하는 단계는 다음과 같습니다.

콘솔 / 터미널 / 명령 프롬프트 :

  1. 코드 블록과 같은 C 코드 편집기에서 C 프로그램을 작성하고 확장자를 .c로 저장하십시오.

  2. 컴파일하고 실행하십시오.

  3. 성공적으로 실행되면 gcc 컴파일러를 설치 한 폴더로 이동하여

    '.c'파일의 '.s'파일을 가져 오는 명령

    C : \ gcc> gcc -S C 파일의 완전한 경로 ENTER

    예제 명령 (내 경우와 같이)

    C : \ gcc> gcc -SD : \ Aa_C_Certified \ alternate_letters.c

    원본 '.c'파일의 '.s'파일이 출력됩니다.

4. 이 후 다음 명령을 입력하십시오

C; \ gcc> cpp 파일 이름 .s ENTER

예제 명령 (내 경우와 같이)

C; \ gcc> cpp alternate_letters.s

C 프로그램의 전체 어셈블리 언어 코드를 인쇄 / 출력합니다.


-save-temps

이것은 https://stackoverflow.com/a/17083009/895245 에서 언급 되었지만 더 자세히 설명하겠습니다. 할 때 :

gcc -save-temps -c -o main.o main.c

main.c

#define INC 1

int myfunc(int i) {
    return i + INC;
}

이제 일반 출력 외에도 main.o현재 작업 디렉토리에는 다음 파일도 포함됩니다.

  • main.i 보너스이며 포함 된 파일은 원하는 prepossessed 파일입니다.

    # 1 "main.c"
    # 1 "<built-in>"
    # 1 "<command-line>"
    # 31 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 32 "<command-line>" 2
    # 1 "main.c"
    
    
    int myfunc(int i) {
        return i + 1;
    }
    
  • main.s 원하는 생성 된 어셈블리를 포함합니다.

        .file   "main.c"
        .text
        .globl  myfunc
        .type   myfunc, @function
    myfunc:
    .LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $1, %eax
        popq    %rbp
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
    .LFE0:
        .size   myfunc, .-myfunc
        .ident  "GCC: (Ubuntu 8.3.0-6ubuntu1) 8.3.0"
        .section    .note.GNU-stack,"",@progbits
    

많은 파일에 대해 수행하려면 대신 사용을 고려하십시오.

 -save-temps=obj

중간 파일을 -o현재 작업 디렉토리 대신 오브젝트 출력 과 동일한 디렉토리에 저장 하므로 잠재적 인 기본 이름 충돌을 피할 수 있습니다.

이 옵션의 장점은 -S빌드 자체를 많이 방해하지 않고 빌드 스크립트에 쉽게 추가 할 수 있다는 것입니다.

이 옵션에 대한 또 다른 멋진 점은 다음을 추가하는 것입니다 -v.

gcc -save-temps -c -o main.o -v main.c

실제로 추악한 임시 파일 대신 사용되는 명시 적 파일을 표시 /tmp하므로 사전 처리 / 컴파일 / 어셈블리 단계를 포함하여 진행중인 작업을 정확하게 알 수 있습니다.

/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -E -quiet -v -imultiarch x86_64-linux-gnu main.c -mtune=generic -march=x86-64 -fpch-preprocess -fstack-protector-strong -Wformat -Wformat-security -o main.i
/usr/lib/gcc/x86_64-linux-gnu/8/cc1 -fpreprocessed main.i -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase-strip main.o -version -fstack-protector-strong -Wformat -Wformat-security -o main.s
as -v --64 -o main.o main.s

우분투 19.04 amd64, GCC 8.3.0에서 테스트되었습니다.


"-S"를 옵션으로 사용하십시오. 터미널의 어셈블리 출력을 표시합니다.


최근에 프로그램에서 각 기능의 어셈블리를 알고 싶었
습니다.

$ gcc main.c                      // main.c source file
$ gdb a.exe                       // gdb a.out in linux
  (gdb) disass main               // note here main is a function
                                  // similary it can be done for other functions

gcc를 사용하는 C 솔루션은 다음과 같습니다.

gcc -S program.c && gcc program.c -o output
  1. 여기서 첫 번째 부분은 Program과 동일한 파일 이름으로 프로그램의 어셈블리 출력을 저장하지만 확장자가 .s 인 다른 일반 텍스트 파일로 열 수 있습니다.

  2. 두 번째 부분은 실제 사용을 위해 프로그램을 컴파일하고 지정된 파일 이름으로 프로그램의 실행 파일을 생성합니다.

program.c에 위의 사용은 프로그램의 이름이고 출력은 생성하려는 실행 파일의 이름입니다.

BTW StackOverFlow의 첫 번째 게시물입니다 :-}

참고 URL : https://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-cc-source-in-gcc

반응형