programing

GCC의 C/C++ 소스에서 어셈블러 출력을 얻는 방법은 무엇입니까?

newsource 2022. 8. 1. 22:49

GCC의 C/C++ 소스에서 어셈블러 출력을 얻는 방법은 무엇입니까?

어떻게 하는 거야?

컴파일 방법을 분석하려면 내보낸 어셈블리 코드를 어떻게 얻어야 합니까?

하다를 사용하세요.-Sgcc(g++)라고 합니다.

gcc -S helloworld.c

그러면 프리프로세서(cpp)가 hellowolld.c 상에서 실행되고 초기 컴파일을 수행한 후 어셈블러가 실행되기 전에 중지됩니다.

로는 파일 「」이 됩니다.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 코드 + 라인 번호가 상호 연결된 어셈블리 코드가 생성되어 어떤 라인이 어떤 코드를 생성하는지 보다 쉽게 확인할 수 있습니다.

# create assembler code:
g++ -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페이지)에 기재되어 있습니다.

-save-temps

이것은 https://stackoverflow.com/a/17083009/895245에서 언급되었지만, 좀 더 예를 들어 보겠습니다.

큰 은 " " " 입니다.-S빌드 자체에 큰 간섭 없이 빌드 스크립트에 쉽게 추가할 수 있습니다.

실행 시:

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

메인

#define INC 1

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

의 출력 「」에, 「」라고 하는 것이 있습니다.main.o현재 작업 디렉토리에는 다음 파일도 포함되어 있습니다.

  • main.i파일이 .

    # 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

중간 이 "Directory"와 됩니다.-o현재 작업 디렉토리가 아닌 객체 출력을 통해 잠재적인 기본 이름 충돌을 방지합니다.

또 다른 은 ' 낫다'를 더하면 .-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

Ubuntu 19.04 amd64, GCC 8.3.0에서 테스트 완료.

CMake 사전 정의된 대상

CMake는 전처리된 파일의 타깃을 자동으로 제공합니다.

make help

는 다음 작업을 수행할 수 있음을 나타냅니다.

make main.s

그 타깃은 다음과 같습니다.

Compiling C source to assembly CMakeFiles/main.dir/main.c.s
/usr/bin/cc    -S /home/ciro/hello/main.c -o CMakeFiles/main.dir/main.c.s

이 은 음음음음 음음 so 음 so음 so so so so so so so so에서 볼수 있습니다.CMakeFiles/main.dir/main.c.s

cmake 3.16.1로 테스트.

-S 스위치를 사용합니다.

g++ -S main.cpp

또는 gcc를 사용하여

gcc -S main.c

이것도 참조해 주세요

다음으로 GCC를 사용한C용 솔루션을 나타냅니다.

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

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

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

다음 명령어는 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 옵션을 사용합니다.-save-temps 옵션을 사용하면 전처리된 파일(.i), 어셈블리 파일(.s), 오브젝트 파일(*.o)도 얻을 수 있습니다(-E, -S 및 -c를 사용하여 각 파일을 가져옵니다).

2008년 질문이라 그런지 답변 중에는 이 가능성을 볼 수 없지만, 2018년에는 Matt Goldbolt의 온라인 웹 사이트 https://godbolt.org를 사용할 수 있습니다.

로컬로 클론을 생성하여 https://github.com/mattgodbolt/compiler-explorer 프로젝트를 실행할 수도 있습니다.

LLVM 어셈블리를 찾고 있는 경우:

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

앞에서 설명한 바와 같이 -S 플래그를 확인합니다.

fdump-tree 플래그 패밀리, 특히 gcc의 중간 형식을 볼 수 있는 fdump-tree-all 플래그를 살펴 볼 필요도 있습니다.이것들은 (적어도 나에게는) 어셈블러보다 읽기 쉬우며 최적화가 어떻게 이루어지는지 알 수 있습니다.

-S 옵션을 사용합니다.

gcc -S program.c

송신원: http://www.delorie.com/djgpp/v2faq/faq8_20.html

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

PhirePhly의 대답 대신, 아니면 모두가 말한 대로 -S를 사용하세요.

한 바와 , 「이행자」를 합니다.-S옵션을 선택합니다. 옵션최적화 옵션)을 수 것도 덧붙이고 .-O0없음,-O2어그레시브 최적화).

특히 RISC 아키텍처에서는 컴파일러가 최적화를 할 때 코드를 거의 인식할 수 없을 정도로 변환하는 경우가 많습니다.결과를 보는 것은 인상적이고 흥미롭습니다!

출력 링크에 따라 표시되는 내용이 다를 경우 앞서 설명한 gcc -S 외에 출력 객체 파일/executable의 objdump도 유용할 수 있습니다.다음은 기본 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의 출력에도 사용할 수 있을 것 같습니다.

이러한 명령어의 출력

다음은 Windows에서 C 프로그램의 어셈블리 코드를 표시/인쇄하는 단계입니다.

console / terminal / 명령어프롬프트:

  1. 코드 블록과 같은 C 코드 에디터에 C 프로그램을 작성하여 확장자 .c로 저장합니다.

  2. 컴파일하여 실행합니다.

  3. 정상적으로 실행되면 gcc 컴파일러가 설치된 폴더로 이동하여

    다음 명령어를 사용하여 .c 파일의 .s 파일을 가져옵니다.

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

    명령어 예시(내 경우와 동일)

    C:\gcc>gcc-S D:\Aa_C_Certified\alternate_letters.c

    그러면 원래 .c 파일의 .s 파일이 출력됩니다.

4. 그 후에 다음 명령을 입력합니다.

C;\gcc> cpp filename.s ENTER

명령어 예시(내 경우와 동일)

C;\gcc> cpp alternate_letters.s

그러면 C 프로그램의 전체 어셈블리 언어 코드가 인쇄/출력됩니다.

최근에 저는 a의 각 기능의 조립을 알고 싶었습니다.저는 이렇게 했습니다.

$ 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

옵션으로 "-S"를 사용합니다.단말기의 어셈블리 출력이 표시됩니다.

언급URL : https://stackoverflow.com/questions/137038/how-do-you-get-assembler-output-from-c-c-source-in-gcc