내 C 소스 파일에서 GCC 를 사용 하여 니모닉 버전의 기계어 코드를 덤프하여 내 코드가 컴파일되는 것을 볼 수있는 방법이 궁금합니다 . Java 로이 작업을 수행 할 수는 있지만 GCC로는 방법을 찾지 못했습니다.
어셈블리에서 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 noprefix
AT & 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
-Wa,-adhln -g to gcc
. 이것은 어셈블러가 가스라고 가정하며 항상 그런 것은 아닙니다.
-Mintel
.
당신이주는 경우에 GCC에게 플래그를 -fverbose-asm
, 그것은 것입니다
생성 된 어셈블리 코드에 주석을 추가로 추가하여 더 읽기 쉽게 만듭니다.
[...] 추가 된 의견은 다음과 같습니다.
- 컴파일러 버전 및 명령 행 옵션에 대한 정보
- FILENAME : LINENUMBER : CONTENT OF LINE 형식의 조립 지침과 관련된 소스 코드 행
- 다양한 어셈블리 명령어 피연산자에 해당하는 고급 표현에 대한 힌트
objdump
- objdump -drwCS -Mintel
그래서 어떻게 같은 것을 사용할 수 verbose
와를 objdump
? -fverbose-asm
gcc에서 와 같이 asm 코드로 주석을 작성할 수 있습니까?
-fverbose-asm
추가 항목은 출력에 asm 구문으로 주석 형태로 표시되며 .o
파일에 추가 항목을 넣는 지시문은 아닙니다 . 조립할 때 모두 버려집니다. 예를 들어 godbolt.org 에서 디스 어셈블리 대신 컴파일러 asm 출력 을 확인하십시오. 여기서 마우스 오버 및 해당 소스 / asm 라인의 색상 강조 표시를 통해 소스 라인과 쉽게 일치시킬 수 있습니다. GCC / clang 어셈블리 출력에서 "노이즈"를 제거하는 방법?
-S (참고 : 대문자 S) 스위치를 GCC로 사용하면 확장명이 .s 인 파일에 어셈블리 코드가 생성됩니다. 예를 들어, 다음 명령은
gcc -O2 -S foo.c
생성 된 어셈블리 코드를 foo.s 파일에 그대로 둡니다.
http://www.delorie.com/djgpp/v2faq/faq8_20.html 에서 똑바로 제거 (그러나 잘못된 제거 -c
)
gcc -march=native -O3 -save-temps
. -c
링크 등을 시도하지 않고도 객체 파일 생성을 중지 하는 데 계속 사용할 수 있습니다 .
-save-temps
한 번에 정확한 코드 생성 코드를 덤프하는 반면에 컴파일러를 호출하는 다른 옵션은 -S
두 번 컴파일 하고 다른 옵션을 사용하는 것을 의미합니다. 그러나 -save-temps
현재 디렉토리에 모두 덤프합니다. 코드를 검사하는 도구가 아닌 GCC의 디버그 옵션으로 의도 된 것 같습니다.
-S
x86 기반 시스템에서 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
.
.o
ASM 파일과 ASM 파일 의 병렬 출력을 수행 할 때도 작동합니다.-Wa,-ahls -o yourfile.o yourfile.cpp>yourfile.asm
-M
옵션을 사용할 수 있습니다 --disassembler-options
. 예 와 같지만 훨씬 짧습니다.objdump -d -M intel a.out | less -N
godbolt 는 매우 유용한 도구이며 C ++ 컴파일러 만 나열하지만 -x c
코드를 C로 처리하기 위해 플래그를 사용할 수 있습니다 . 그런 다음 코드에 대한 어셈블리 목록을 나란히 Colourise
생성 하고 옵션을 사용하여 생성 할 수 있습니다 생성 된 어셈블리에 매핑 할 소스 코드를 시각적으로 나타내는 색상 막대입니다. 예를 들어 다음 코드는 :
#include <stdio.h>
void func()
{
printf( "hello world\n" ) ;
}
다음 명령 줄을 사용하십시오.
-x c -std=c99 -O3
그리고 Colourise
다음을 생성합니다 :
-masm=intel
나머지는 어떻습니까?
-x c
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
많은 사람들이 콘솔에서 인쇄물을 기대하기 때문에 출력이에 있다고 언급 할 수도 있습니다 .
-S -o-
표준 출력으로 덤프합니다. -masm=intel
NASM / YASM 구문을 사용하려는 경우에 유용합니다. ( qword ptr [mem]
단지가 아니라을 사용 qword
하므로 NASM / YASM보다 Intel / MASM과 비슷합니다). gcc.godbolt.org 는 덤프를 정리하는 작업을 훌륭하게 수행합니다. 선택적으로 주석 전용 행, 사용하지 않는 레이블 및 어셈블러 지시문을 제거합니다.
-Og
보다 좋습니다 -O1
. "디버깅 최적화"를 의미하며 소스가 말하는 모든 것을 수행하는 까다 롭고 따르기 어려운 최적화없이 asm을 만듭니다. gcc4.8부터 사용할 수 있지만 clang 3.7에는 아직 없습니다. IDK가 반대하거나 결정한 경우.
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 : 리트 어셈블러 덤프의 끝.
set disassembly-flavor intel
command를 사용하십시오 .
나는 gcc에게 기회를주지 않았지만 g ++의 경우. 아래 명령은 저에게 효과적입니다. 디버그 빌드의 경우 -g 및 -Wa, -adhln은 소스 코드로 나열하기 위해 어셈블러로 전달됩니다.
g ++ -g-와아, 아들 src.cpp
gcc 또는 g ++에서 옵션으로 -Wa, -adhln 을 사용 하여 stdout에 리스팅 출력을 생성하십시오.
-Wa, ...는 어셈블러 부분의 명령 행 옵션입니다 (C / ++ 컴파일 후 gcc / g ++에서 실행). 그것은 호출 로 (Windows의 as.exe) 내부. 보다
> 도움말
gcc 내부의 어셈블러 도구에 대한 추가 도움말을 보려면 명령 줄로