답변:
사용 -S
GCC (또는 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를 사용하여 얻을 수있는 세부 수준에 대한 정보가 제공됩니다.
.intel_syntax
는 NASM과 호환 되지 않습니다 . 그것은 MASM과 비슷하지만 (예를 들어 주소 mov eax, symbol
가있는 NASM과는 달리 부하 mov r32, imm32
입니다) MASM과 완전히 호환되지는 않습니다. 특히 NASM 구문으로 작성하려는 경우 읽기 좋은 형식으로 사용하는 것이 좋습니다. objdump -drwC -Mintel | less
또는 gcc foo.c -O1 -fverbose-asm -masm=intel -S -o- | less
유용합니다. GCC / clang 어셈블리 출력에서 "노이즈"를 제거하는 방법 도 참조하십시오 . -masm=intel
clang 과도 작동합니다.
gcc -O -fverbose-asm -S
그러면 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 페이지입니다).
as
OS X에서는 이러한 플래그를 알 수 없습니다. 그렇다면 -Wa
옵션을에 전달 하는 데 한 줄로 사용할 수 있습니다 as
.
g++ -g -O0 -c -fverbose-asm -Wa,-adhln test.cpp > test.lst
이것의 짧은 버전이 될 것입니다.
gcc -c -g -Wa,-ahl=test.s test.c
또는gcc -c -g -Wa,-a,-ad test.c > test.txt
-O0
? 그것은 값을 추적하기 어렵게하는로드 / 스토어들로 가득 차 있으며, 최적화 된 코드가 얼마나 효율적인지에 대해서는 아무 것도 알려주지 않습니다.
다음 명령 줄은 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)
-O2
, 또는 어떤 최적화 프로젝트를 빌드 할 때 GCC가 코드를 최적화하는 방법을보고 싶다면 당신이 실제로 사용하는 옵션을 제공합니다. (또는 LTO를 사용한다면, 원하는대로 링커 출력을 분해해야합니다.)
당신이보고 싶은 것이 출력의 링크에 달려 있다면, 출력 객체 파일 / 실행 파일에 대한 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의 출력에도 사용될 수 있다고 생각합니다.
mov eax,ds:0x804b794
NASMish는 아닙니다. 또한, 때로는 그냥 유용한 정보를 제거합니다 : movzx eax,[edx+0x1]
메모리가 피연산자인지 추측 독자 잎 byte
이나 word
.
objconv
. 출력 파일 =을 사용하여 stdout으로 분해 /dev/stdout
할 수 있으므로 파이프를 less
통해 볼 수 있습니다. 이 ndisasm
있지만 플랫 바이너리 만 분해하고 객체 파일 (ELF / PE)에 대해 알지 못합니다.
아마도 2008 년부터 질문이 있었기 때문에 답변 중이 가능성을 보지 못했지만 2018 년에 Matt Goldbolt의 온라인 웹 사이트 https://godbolt.org
로컬로 git clone을 사용하고 그의 프로젝트를 실행할 수 있습니다 https://github.com/mattgodbolt/compiler-explorer
-save-temps
이것은 https://stackoverflow.com/a/17083009/895245 에서 언급 되었지만 더 자세히 설명하겠습니다.
이 옵션의 가장 큰 장점은 -S
빌드 자체를 많이 방해하지 않고 빌드 스크립트에 추가하기가 매우 쉽다는 것입니다.
할 때 :
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
보너스이며 사전 제안 된 파일을 포함합니다.
# 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
현재 작업 디렉토리 대신 오브젝트 출력 과 동일한 디렉토리에 저장 하므로 잠재적 인 기본 이름 충돌을 피할 수 있습니다.
이 옵션에 대한 또 다른 멋진 점은 다음을 추가하는 것입니다 -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에서 테스트되었습니다.
보낸 사람 : http://www.delorie.com/djgpp/v2faq/faq8_20.html
gcc -c -g -Wa, -a, -ad [다른 GCC 옵션] foo.c> foo.lst
PhirePhly의 답변 대신 또는 모두가 말했듯이 -S를 사용하십시오.
Windows에서 C 프로그램의 어셈블리 코드를 보거나 인쇄하는 단계는 다음과 같습니다.
콘솔 / 터미널 / 명령 프롬프트 :
코드 블록과 같은 C 코드 편집기에서 C 프로그램을 작성하고 확장자를 .c로 저장하십시오.
컴파일하고 실행하십시오.
성공적으로 실행되면 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 프로그램의 전체 어셈블리 언어 코드를 인쇄 / 출력합니다.
"-S"를 옵션으로 사용하십시오. 터미널의 어셈블리 출력을 표시합니다.
gcc foo.c -masm=intel -fverbose-asm -O3 -S -o- |less
. -S
자체적으로 생성 foo.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
여기서 첫 번째 부분은 Program과 동일한 파일 이름으로 프로그램의 어셈블리 출력을 저장하지만 확장자가 .s 인 다른 일반 텍스트 파일로 열 수 있습니다.
두 번째 부분은 실제 사용을 위해 프로그램을 컴파일하고 지정된 파일 이름으로 프로그램의 실행 파일을 생성합니다.
그만큼 program.c에 위의 사용은 프로그램의 이름 출력 생성하려는 실행 파일의 이름입니다.
BTW StackOverFlow의 첫 번째 게시물입니다 :-}