I was told to use a disassembler. Does gcc
have anything built in? What is the easiest way to do this?

- 328,167
- 45
- 605
- 847

- 5,964
- 15
- 53
- 73
-
And reassemble afterwards: http://stackoverflow.com/questions/4309771/disassembling-modifying-and-then-reassembling-a-linux-executable – Ciro Santilli OurBigBook.com Apr 03 '17 at 15:52
-
Related: [How to remove "noise" from GCC/clang assembly output?](//stackoverflow.com/q/38552116) - if you really just want to see what the compiler did, you don't always need to compile + link + disassemble. – Peter Cordes Nov 15 '19 at 09:18
10 Answers
I don't think gcc
has a flag for it, since it's primarily a compiler, but another of the GNU development tools does. objdump
takes a -d
/--disassemble
flag:
$ objdump -d /path/to/binary
The disassembly looks like this:
080483b4 <main>:
80483b4: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483b8: 83 e4 f0 and $0xfffffff0,%esp
80483bb: ff 71 fc pushl -0x4(%ecx)
80483be: 55 push %ebp
80483bf: 89 e5 mov %esp,%ebp
80483c1: 51 push %ecx
80483c2: b8 00 00 00 00 mov $0x0,%eax
80483c7: 59 pop %ecx
80483c8: 5d pop %ebp
80483c9: 8d 61 fc lea -0x4(%ecx),%esp
80483cc: c3 ret
80483cd: 90 nop
80483ce: 90 nop
80483cf: 90 nop

- 169,610
- 28
- 168
- 175
-
23For intel-syntax: `objdump -Mintel -d`. Or Agner Fog's objconv disassembler is the nicest one I've tried yet (see my answer). Adding numbered labels to branch-targets is really really nice. – Peter Cordes Nov 29 '15 at 02:47
-
10Useful options: `objdump -drwC -Mintel`. `-r` shows relocations from the symbol table. `-C` demangles C++ names. `-W` avoids line wrapping for long instructions. If you use it often, this is handy: `alias disas='objdump -drwC -Mintel'`. – Peter Cordes Dec 30 '16 at 04:11
-
4Add `-S` to display source code intermixed with disassembly. (As pointed in [another answer](https://stackoverflow.com/a/24530673/1800052).) – Alexander Pozdneev Jul 26 '18 at 06:43
-
can i know is there a disassembler which will output only AT&A assembly? not all the addresses, binary encodings, etc... – user135142 Dec 06 '21 at 15:26
An interesting alternative to objdump is gdb. You don't have to run the binary or have debuginfo.
$ gdb -q ./a.out
Reading symbols from ./a.out...(no debugging symbols found)...done.
(gdb) info functions
All defined functions:
Non-debugging symbols:
0x00000000004003a8 _init
0x00000000004003e0 __libc_start_main@plt
0x00000000004003f0 __gmon_start__@plt
0x0000000000400400 _start
0x0000000000400430 deregister_tm_clones
0x0000000000400460 register_tm_clones
0x00000000004004a0 __do_global_dtors_aux
0x00000000004004c0 frame_dummy
0x00000000004004f0 fce
0x00000000004004fb main
0x0000000000400510 __libc_csu_init
0x0000000000400580 __libc_csu_fini
0x0000000000400584 _fini
(gdb) disassemble main
Dump of assembler code for function main:
0x00000000004004fb <+0>: push %rbp
0x00000000004004fc <+1>: mov %rsp,%rbp
0x00000000004004ff <+4>: sub $0x10,%rsp
0x0000000000400503 <+8>: callq 0x4004f0 <fce>
0x0000000000400508 <+13>: mov %eax,-0x4(%rbp)
0x000000000040050b <+16>: mov -0x4(%rbp),%eax
0x000000000040050e <+19>: leaveq
0x000000000040050f <+20>: retq
End of assembler dump.
(gdb) disassemble fce
Dump of assembler code for function fce:
0x00000000004004f0 <+0>: push %rbp
0x00000000004004f1 <+1>: mov %rsp,%rbp
0x00000000004004f4 <+4>: mov $0x2a,%eax
0x00000000004004f9 <+9>: pop %rbp
0x00000000004004fa <+10>: retq
End of assembler dump.
(gdb)
With full debugging info it's even better.
(gdb) disassemble /m main
Dump of assembler code for function main:
9 {
0x00000000004004fb <+0>: push %rbp
0x00000000004004fc <+1>: mov %rsp,%rbp
0x00000000004004ff <+4>: sub $0x10,%rsp
10 int x = fce ();
0x0000000000400503 <+8>: callq 0x4004f0 <fce>
0x0000000000400508 <+13>: mov %eax,-0x4(%rbp)
11 return x;
0x000000000040050b <+16>: mov -0x4(%rbp),%eax
12 }
0x000000000040050e <+19>: leaveq
0x000000000040050f <+20>: retq
End of assembler dump.
(gdb)
objdump has a similar option (-S)

- 10,215
- 7
- 31
- 46

- 1,282
- 12
- 13
This answer is specific to x86. Portable tools that can disassemble AArch64, MIPS, or whatever machine code include objdump
and llvm-objdump
.
Agner Fog's disassembler, objconv
, is quite nice. It will add comments to the disassembly output for performance problems (like the dreaded LCP stall from instructions with 16bit immediate constants, for example).
objconv -fyasm a.out /dev/stdout | less
(It doesn't recognize -
as shorthand for stdout, and defaults to outputting to a file of similar name to the input file, with .asm
tacked on.)
It also adds branch targets to the code. Other disassemblers usually disassemble jump instructions with just a numeric destination, and don't put any marker at a branch target to help you find the top of loops and so on.
It also indicates NOPs more clearly than other disassemblers (making it clear when there's padding, rather than disassembling it as just another instruction.)
It's open source, and easy to compile for Linux. It can disassemble into NASM, YASM, MASM, or GNU (AT&T) syntax.
Sample output:
; Filling space: 0FH
; Filler type: Multi-byte NOP
; db 0FH, 1FH, 44H, 00H, 00H, 66H, 2EH, 0FH
; db 1FH, 84H, 00H, 00H, 00H, 00H, 00H
ALIGN 16
foo: ; Function begin
cmp rdi, 1 ; 00400620 _ 48: 83. FF, 01
jbe ?_026 ; 00400624 _ 0F 86, 00000084
mov r11d, 1 ; 0040062A _ 41: BB, 00000001
?_020: mov r8, r11 ; 00400630 _ 4D: 89. D8
imul r8, r11 ; 00400633 _ 4D: 0F AF. C3
add r8, rdi ; 00400637 _ 49: 01. F8
cmp r8, 3 ; 0040063A _ 49: 83. F8, 03
jbe ?_029 ; 0040063E _ 0F 86, 00000097
mov esi, 1 ; 00400644 _ BE, 00000001
; Filling space: 7H
; Filler type: Multi-byte NOP
; db 0FH, 1FH, 80H, 00H, 00H, 00H, 00H
ALIGN 8
?_021: add rsi, rsi ; 00400650 _ 48: 01. F6
mov rax, rsi ; 00400653 _ 48: 89. F0
imul rax, rsi ; 00400656 _ 48: 0F AF. C6
shl rax, 2 ; 0040065A _ 48: C1. E0, 02
cmp r8, rax ; 0040065E _ 49: 39. C0
jnc ?_021 ; 00400661 _ 73, ED
lea rcx, [rsi+rsi] ; 00400663 _ 48: 8D. 0C 36
...
Note that this output is ready to be assembled back into an object file, so you can tweak the code at the asm source level, rather than with a hex-editor on the machine code. (So you aren't limited to keeping things the same size.) With no changes, the result should be near-identical. It might not be, though, since disassembly of stuff like
(from /lib/x86_64-linux-gnu/libc.so.6)
SECTION .plt align=16 execute ; section number 11, code
?_00001:; Local function
push qword [rel ?_37996] ; 0001F420 _ FF. 35, 003A4BE2(rel)
jmp near [rel ?_37997] ; 0001F426 _ FF. 25, 003A4BE4(rel)
...
ALIGN 8
?_00002:jmp near [rel ?_37998] ; 0001F430 _ FF. 25, 003A4BE2(rel)
; Note: Immediate operand could be made smaller by sign extension
push 11 ; 0001F436 _ 68, 0000000B
; Note: Immediate operand could be made smaller by sign extension
jmp ?_00001 ; 0001F43B _ E9, FFFFFFE0
doesn't have anything in the source to make sure it assembles to the longer encoding that leaves room for relocations to rewrite it with a 32bit offset.
If you don't want to install it objconv, GNU binutils objdump -drwC -Mintel
is very usable, and will already be installed if you have a normal Linux gcc setup. I use alias disas='objdump -drwC -Mintel'
on my system. (-w
is no line-wrapping, -C
is demangle, -r
prints relocations in object files.)
llvm-objdump -d
also works, and can disassemble for a variety of architectures from a single binary. (Unlike GNU objdump
where you'd need a separate per arch, like aarch64-linux-gnu-objdump -d
.) Similarly, clang -O3 -target mips -c
or clang -O3 -target riscv32 -c
or whatever are useful to compile for architectures you're interested in, but not interested enough to bother installing a cross-compiler. (https://godbolt.org/ Compiler Explorer is also a useful resource for that; see How to remove "noise" from GCC/clang assembly output? for more about it and writing small functions that compile to interesting asm.)

- 328,167
- 45
- 605
- 847
there's also ndisasm, which has some quirks, but can be more useful if you use nasm. I agree with Michael Mrozek that objdump is probably best.
[later] you might also want to check out Albert van der Horst's ciasdis: http://home.hccnet.nl/a.w.m.van.der.horst/forthassembler.html. it can be hard to understand, but has some interesting features you won't likely find anywhere else.

- 37,688
- 6
- 92
- 107
-
2In particular: http://home.hccnet.nl/a.w.m.van.der.horst/ciasdis.html contains under "latest developments" a debian package that you can install easily. With proper instructions (it does scripting) it will generate a source file that will reassemble again to the exact same binary. I'm not aware of any package that can do that. It may be hard to use from the instructions, I intend to publish in github with extensive examples. – Albert van der Horst Oct 05 '18 at 14:34
You might find ODA useful. It's a web-based disassembler that supports tons of architectures.

- 897
- 7
- 6
-
2great idea. getting Server Error (500) to https://onlinedisassembler.com/odaweb/ - hope it's transient. – jouell Apr 21 '18 at 14:20
Use IDA Pro and the Decompiler.

- 26,914
- 8
- 68
- 96
-
IDA seems a bit overkill for this, especially considering it's rather expensive – Michael Mrozek Feb 26 '11 at 08:45
-
1the free version is not available for Linux, only the limited demo version. (too bad because, on windows, that's the best disassembler i have ever used) – Adrien Plisson Feb 26 '11 at 10:22
-
IDA is good but the problem of IDA is you get lazy if you used for small tasks.. gdb does the job for most of everything, gdb easier? no, but possible. – cfernandezlinux Jul 02 '16 at 05:17
-
1IDA is proprietary software, it doesn't respect the user's freedom. It contains DRM which restricts the user from using many features. Moreover, that's a paid software. See https://gnu.org/proprietary/proprietary.html. – Akib Azmain Turja Mar 14 '21 at 13:55
You can come pretty damn close (but no cigar) to generating assembly that will reassemble, if that's what you are intending to do, using this rather crude and tediously long pipeline trick (replace /bin/bash with the file you intend to disassemble and bash.S with what you intend to send the output to):
objdump --no-show-raw-insn -Matt,att-mnemonic -Dz /bin/bash | grep -v "file format" | grep -v "(bad)" | sed '1,4d' | cut -d' ' -f2- | cut -d '<' -f2 | tr -d '>' | cut -f2- | sed -e "s/of\ section/#Disassembly\ of\ section/" | grep -v "\.\.\." > bash.S
Note how long this is, however. I really wish there was a better way (or, for that matter, a disassembler capable of outputting code that an assembler will recognize), but unfortunately there isn't.

- 722
- 1
- 6
- 13
-
Wow! This is fantastic. Btw, regarding your problem, why don't you use an alias for it to skip typing this huge command? – Bat May 12 '20 at 10:26
ht editor can disassemble binaries in many formats. It is similar to Hiew, but open source.
To disassemble, open a binary, then press F6 and then select elf/image.

- 2,086
- 18
- 21
Let's say that you have:
#include <iostream>
double foo(double x)
{
asm("# MyTag BEGIN"); // <- asm comment,
// used later to locate piece of code
double y = 2 * x + 1;
asm("# MyTag END");
return y;
}
int main()
{
std::cout << foo(2);
}
To get assembly code using gcc you can do:
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.'
c++filt
demangles symbols
grep -vE '\s+\.'
removes some useless information
Now if you want to visualize the tagged part, simply use:
g++ prog.cpp -c -S -o - -masm=intel | c++filt | grep -vE '\s+\.' | grep "MyTag BEGIN" -A 20
With my computer I get:
# MyTag BEGIN
# 0 "" 2
#NO_APP
movsd xmm0, QWORD PTR -24[rbp]
movapd xmm1, xmm0
addsd xmm1, xmm0
addsd xmm0, xmm1
movsd QWORD PTR -8[rbp], xmm0
#APP
# 9 "poub.cpp" 1
# MyTag END
# 0 "" 2
#NO_APP
movsd xmm0, QWORD PTR -8[rbp]
pop rbp
ret
.LFE1814:
main:
.LFB1815:
push rbp
mov rbp, rsp
A more friendly approach is to use: Compiler Explorer

- 10,518
- 5
- 31
- 70
-
This is only reliable with optimization disabled, otherwise parts of the operations inside the region could optimize into stuff outside, or be optimized away. So you can only see the clunky `-O0` asm. – Peter Cordes Nov 15 '19 at 09:20