GCC를 사용하여 읽을 수있는 어셈블리를 생성 하시겠습니까?


256

내 C 소스 파일에서 GCC 를 사용 하여 니모닉 버전의 기계어 코드를 덤프하여 내 코드가 컴파일되는 것을 볼 수있는 방법이 궁금합니다 . Java 로이 작업을 수행 할 수는 있지만 GCC로는 방법을 찾지 못했습니다.

어셈블리에서 C 메서드를 다시 작성하려고 시도하고 GCC가 어떻게 작동하는지 보는 것이 큰 도움이됩니다.


25
'bytecode'는 일반적으로 JVM 또는 .NET의 CLR과 같은 VM에서 사용하는 코드를 의미합니다. GCC의 출력은 '머신 코드', '머신 언어'또는 '어셈블리 언어'라고합니다.
Javier

2
Godbolt를 사용하여 답변을 추가했습니다. 다른 옵션이 코드 생성에 어떤 영향을 미치는지 빠르게 실험 할 수있는 강력한 도구이기 때문입니다.
Shafik Yaghmour



asm 출력을 사람이 읽을 수있게 만드는 방법에 대한 자세한 내용 은 GCC / clang 어셈블리 출력에서 ​​"노이즈"를 제거하는 방법
Peter Cordes

답변:


335

디버그 기호로 컴파일 objdump하면 더 읽기 쉬운 디스 어셈블리를 생성하는 데 사용할 수 있습니다 .

>objdump --help
[...]
-S, --source             Intermix source code with disassembly
-l, --line-numbers       Include line numbers and filenames in output

objdump -drwC -Mintel 좋다 :

  • -r재배치에 쇼 기호 이름 (당신이 보는 것, 그래서 puts에서 call아래 명령)
  • -R 동적 연결 재배치 / 기호 이름 표시 (공유 라이브러리에서 유용)
  • -C C ++ 심볼 이름 demangles
  • -w "와이드"모드 : 기계 코드 바이트를 줄 바꿈하지 않습니다.
  • -Mintel: .intel_syntax noprefixAT & T 대신 GAS / binutils MASM 유사 구문을 사용하십시오.
  • -S: 디스 어셈블리가있는 소스 라인을 인터리브합니다.

당신은 같은 것을 넣을 수 alias disas="objdump -drwCS -Mintel"있습니다~/.bashrc


예:

> gcc -g -c test.c
> objdump -d -M intel -S test.o

test.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
#include <stdio.h>

int main(void)
{
   0:   55                      push   ebp
   1:   89 e5                   mov    ebp,esp
   3:   83 e4 f0                and    esp,0xfffffff0
   6:   83 ec 10                sub    esp,0x10
    puts("test");
   9:   c7 04 24 00 00 00 00    mov    DWORD PTR [esp],0x0
  10:   e8 fc ff ff ff          call   11 <main+0x11>

    return 0;
  15:   b8 00 00 00 00          mov    eax,0x0
}
  1a:   c9                      leave  
  1b:   c3                      ret

3
인텔 명령어 만 가져 오는 스위치가 있습니까?
James

3
이들은 모두 인텔 프로세서에서 실행되므로 인텔 명령어입니다.
toto

12
@toto 그가 AT & T 구문 대신 Intel 구문을 의미한다고 생각합니다
Amok

7
스위치 순서를 사용하여 중간 오브젝트 파일을 잊어 버릴 수 있습니다 -Wa,-adhln -g to gcc. 이것은 어셈블러가 가스라고 가정하며 항상 그런 것은 아닙니다.
Marc Butler

8
@James 예, 공급하십시오 -Mintel.
fuz September

106

당신이주는 경우에 GCC에게 플래그를 -fverbose-asm, 그것은 것입니다

생성 된 어셈블리 코드에 주석을 추가로 추가하여 더 읽기 쉽게 만듭니다.

[...] 추가 된 의견은 다음과 같습니다.

  • 컴파일러 버전 및 명령 행 옵션에 대한 정보
  • FILENAME : LINENUMBER : CONTENT OF LINE 형식의 조립 지침과 관련된 소스 코드 행
  • 다양한 어셈블리 명령어 피연산자에 해당하는 고급 표현에 대한 힌트

그러나, 나는에 사용되는 모든 스위치 잃어버린 것 objdump- objdump -drwCS -Mintel그래서 어떻게 같은 것을 사용할 수 verbose와를 objdump? -fverbose-asmgcc에서 와 같이 asm 코드로 주석을 작성할 수 있습니까?
목자

1
@Herdsman : 할 수 없습니다. 추가되는 -fverbose-asm추가 항목은 출력에 asm 구문으로 주석 형태로 표시되며 .o파일에 추가 항목을 넣는 지시문은 아닙니다 . 조립할 때 모두 버려집니다. 예를 들어 godbolt.org 에서 디스 어셈블리 대신 컴파일러 asm 출력 을 확인하십시오. 여기서 마우스 오버 및 해당 소스 / asm 라인의 색상 강조 표시를 통해 소스 라인과 쉽게 일치시킬 수 있습니다. GCC / clang 어셈블리 출력에서 ​​"노이즈"를 제거하는 방법?
Peter Cordes

75

-S (참고 : 대문자 S) 스위치를 GCC로 사용하면 확장명이 .s 인 파일에 어셈블리 코드가 생성됩니다. 예를 들어, 다음 명령은

gcc -O2 -S foo.c

생성 된 어셈블리 코드를 foo.s 파일에 그대로 둡니다.

http://www.delorie.com/djgpp/v2faq/faq8_20.html 에서 똑바로 제거 (그러나 잘못된 제거 -c)


35
-c와 -S를 섞어서는 안되며 그중 하나만 사용하십시오. 이 경우 하나는 다른 순서보다 우선합니다 (아마도 사용 순서에 따라 다름).
Adam Rosenfield

4
@AdamRosenfield '-c와 -S를 섞어서는 안된다'에 대한 언급이 있습니까? 사실이라면 저자에게 상기 시켜서 편집해야 할 수도 있습니다.
Tony

5
@Tony : gcc.gnu.org/onlinedocs/gcc/Overall-Options.html#Overall-Options " -c, -S 또는 -E 옵션 중 하나 를 사용 하여 gcc가 중지되는 위치를 말할 수 있습니다. "
Nate Eldredge

1
모든 중간 출력을 원하면을 사용하십시오 gcc -march=native -O3 -save-temps. -c링크 등을 시도하지 않고도 객체 파일 생성을 중지 하는 데 계속 사용할 수 있습니다 .
Peter Cordes 1

2
-save-temps한 번에 정확한 코드 생성 코드를 덤프하는 반면에 컴파일러를 호출하는 다른 옵션은 -S두 번 컴파일 하고 다른 옵션을 사용하는 것을 의미합니다. 그러나 -save-temps 현재 디렉토리에 모두 덤프합니다. 코드를 검사하는 도구가 아닌 GCC의 디버그 옵션으로 의도 된 것 같습니다.
Stéphane Gourichon

50

-Sx86 기반 시스템에서 GCC로 스위치를 사용하면 기본적으로 다음과 같이 -masm=att스위치 로 지정할 수있는 AT & T 구문 덤프가 생성됩니다 .

gcc -S -masm=att code.c

Intel 구문으로 덤프를 생성하려면 다음과 같이 -masm=intel스위치를 사용할 수 있습니다 .

gcc -S -masm=intel code.c

(둘 다 code.c다양한 구문, 파일로 덤프를 생성합니다 code.s)

objdump와 비슷한 효과를 내기 위해 --disassembler-options= intel/ att스위치 (예 : 구문 차이를 설명하기 위해 코드 덤프 포함)를 사용하려고합니다 .

 $ objdump -d --disassembler-options=att code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    0x4(%esp),%ecx
 80483c8:   83 e4 f0                and    $0xfffffff0,%esp
 80483cb:   ff 71 fc                pushl  -0x4(%ecx)
 80483ce:   55                      push   %ebp
 80483cf:   89 e5                   mov    %esp,%ebp
 80483d1:   51                      push   %ecx
 80483d2:   83 ec 04                sub    $0x4,%esp
 80483d5:   c7 04 24 b0 84 04 08    movl   $0x80484b0,(%esp)
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    $0x0,%eax
 80483e6:   83 c4 04                add    $0x4,%esp 
 80483e9:   59                      pop    %ecx
 80483ea:   5d                      pop    %ebp
 80483eb:   8d 61 fc                lea    -0x4(%ecx),%esp
 80483ee:   c3                      ret
 80483ef:   90                      nop

$ objdump -d --disassembler-options=intel code.c
 080483c4 <main>:
 80483c4:   8d 4c 24 04             lea    ecx,[esp+0x4]
 80483c8:   83 e4 f0                and    esp,0xfffffff0
 80483cb:   ff 71 fc                push   DWORD PTR [ecx-0x4]
 80483ce:   55                      push   ebp
 80483cf:   89 e5                   mov    ebp,esp
 80483d1:   51                      push   ecx
 80483d2:   83 ec 04                sub    esp,0x4
 80483d5:   c7 04 24 b0 84 04 08    mov    DWORD PTR [esp],0x80484b0
 80483dc:   e8 13 ff ff ff          call   80482f4 <puts@plt>
 80483e1:   b8 00 00 00 00          mov    eax,0x0
 80483e6:   83 c4 04                add    esp,0x4
 80483e9:   59                      pop    ecx
 80483ea:   5d                      pop    ebp
 80483eb:   8d 61 fc                lea    esp,[ecx-0x4]
 80483ee:   c3                      ret    
 80483ef:   90                      nop

무엇 ... gcc -S -masm=intel test.c나를 위해 정확히 일을했다, 내가 인텔과 같은 AT & T 구문의 일부 잡종을 가지고 : mov %rax, QWORD PTR -24[%rbp]대신에, : movq -24(%rbp), %rax.
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

1
좋은 팁. 이는 또한 .oASM 파일과 ASM 파일 의 병렬 출력을 수행 할 때도 작동합니다.-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
underscore_d

-M옵션을 사용할 수 있습니다 --disassembler-options. 예 와 같지만 훨씬 짧습니다.objdump -d -M intel a.out | less -N
Eric Wang

34

godbolt 는 매우 유용한 도구이며 C ++ 컴파일러 만 나열하지만 -x c코드를 C로 처리하기 위해 플래그를 사용할 수 있습니다 . 그런 다음 코드에 대한 어셈블리 목록을 나란히 Colourise생성 하고 옵션을 사용하여 생성 할 수 있습니다 생성 된 어셈블리에 매핑 할 소스 코드를 시각적으로 나타내는 색상 막대입니다. 예를 들어 다음 코드는 :

#include <stdio.h>

void func()
{
  printf( "hello world\n" ) ;
}

다음 명령 줄을 사용하십시오.

-x c -std=c99 -O3

그리고 Colourise다음을 생성합니다 :

여기에 이미지 설명을 입력하십시오


godbolt 필터의 작동 방식을 알고 있으면 좋을 것입니다 : .LC0, .text, // 및 Intel. 인텔은 쉽지만 -masm=intel나머지는 어떻습니까?
Z boson

나는 여기에서 설명하는 추측 stackoverflow.com/a/38552509/2542702
Z 보손

godbolt는 C를 지원합니다 (Rust, D, Pascal과 같은 다른 언어와 함께). C 컴파일러가 훨씬 적다는 것만으로도 C ++ 컴파일러를 사용하는 것이 좋습니다.-x c
phuclv

23

gcc -S -fverbose-asm -O source.c그런 다음 생성 된 source.s어셈블러 파일 을 살펴 보셨습니까 ?

생성 된 어셈블러 코드가 들어갑니다 source.s( -o 어셈블러 파일 이름으로 대체 할 수 있음 ). 이 -fverbose-asm옵션은 컴파일러에게 생성 된 어셈블러 코드를 "설명"하는 어셈블러 주석을 생성하도록 요청합니다. 이 -O옵션은 컴파일러에게 비트를 최적화하도록 요청합니다 ( -O2또는로 더 최적화 할 수 있음 -O3).

무엇을하고 있는지 이해하고 싶다면 신중하게 gcc통과 -fdump-tree-all해야합니다. 수백 개의 덤프 파일을 얻게됩니다.

BTW, GCC는 플러그인 또는 MELT (GCC를 확장하기위한 고급 도메인 특정 언어로 확장 가능합니다 .2017 년에 포기했습니다)


source.s많은 사람들이 콘솔에서 인쇄물을 기대하기 때문에 출력이에 있다고 언급 할 수도 있습니다 .
RubenLaguna

1
@ecerulm : -S -o-표준 출력으로 덤프합니다. -masm=intelNASM / YASM 구문을 사용하려는 경우에 유용합니다. ( qword ptr [mem]단지가 아니라을 사용 qword하므로 NASM / YASM보다 Intel / MASM과 비슷합니다). gcc.godbolt.org 는 덤프를 정리하는 작업을 훌륭하게 수행합니다. 선택적으로 주석 전용 행, 사용하지 않는 레이블 및 어셈블러 지시문을 제거합니다.
Peter Cordes

2
언급을 잊어 버렸습니다 : "소스와 유사하지만 모든 소스 라인마다 저장 / 재로드의 소음이 없음"을 찾고 있다면, -Og보다 좋습니다 -O1. "디버깅 최적화"를 의미하며 소스가 말하는 모든 것을 수행하는 까다 롭고 따르기 어려운 최적화없이 asm을 만듭니다. gcc4.8부터 사용할 수 있지만 clang 3.7에는 아직 없습니다. IDK가 반대하거나 결정한 경우.
Peter Cordes

19

objdump와 같이 gdb를 사용할 수 있습니다.

이 발췌문은 http://sources.redhat.com/gdb/current/onlinedocs/gdb_9.html#SEC64 에서 가져 왔습니다 .


다음은 Intel x86의 혼합 소스 + 어셈블리를 보여주는 예입니다.

  (gdb) disas / m main
함수 main을위한 어셈블러 코드 덤프 :
5 {
0x08048330 : 푸시 % ebp
0x08048331 : mov % esp, % ebp
0x08048333 : 하위 $ 0x8, % esp
0x08048336 : 및 $ 0xfffffff0, % esp
0x08048339 : 하위 $ 0x10, % esp

6 printf ( "안녕하세요. \ n");
0x0804833c : movl $ 0x8048440, (% esp)
0x08048343 : 전화 0x8048284 

7은 0을 반환합니다.
8}
0x08048348 : mov $ 0x0, % eax
0x0804834d : 휴가
0x0804834e : 리트

어셈블러 덤프의 끝.


그리고 GDB 디스어셈블러를 인텔 구문으로 전환하려면 set disassembly-flavor intelcommand를 사용하십시오 .
Ruslan

13

-S (참고 : 대문자 S) 스위치를 GCC로 사용하면 확장명이 .s 인 파일에 어셈블리 코드가 생성됩니다. 예를 들어, 다음 명령은

gcc -O2 -S -c foo.c


4

나는 gcc에게 기회를주지 않았지만 g ++의 경우. 아래 명령은 저에게 효과적입니다. 디버그 빌드의 경우 -g 및 -Wa, -adhln은 소스 코드로 나열하기 위해 어셈블러로 전달됩니다.

g ++ -g-와아, 아들 src.cpp


gcc에서도 작동합니다! -Wa, ...는 어셈블러 부분의 명령 행 옵션입니다 (C / ++ 컴파일 후 gcc / g ++에서 실행). 내부적으로 호출합니다 (Windows의 경우 as.exe). 추가 도움말을 보려면 명령 줄로> as --help를 참조하십시오.
Hartmut Schorrig

0

gcc 또는 g ++에서 옵션으로 -Wa, -adhln 을 사용 하여 stdout에 리스팅 출력을 생성하십시오.

-Wa, ...는 어셈블러 부분의 명령 행 옵션입니다 (C / ++ 컴파일 후 gcc / g ++에서 실행). 그것은 호출 (Windows의 as.exe) 내부. 보다

> 도움말

gcc 내부의 어셈블러 도구에 대한 추가 도움말을 보려면 명령 줄로

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.