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

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

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



답변

디버그 기호로 컴파일 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


답변

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

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

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

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

답변

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

gcc -O2 -S foo.c

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

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


답변

-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


답변

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

#include <stdio.h>

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

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

-x c -std=c99 -O3

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

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


답변

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 년에 포기했습니다)


답변

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 : 리트

어셈블러 덤프의 끝.