7

Say for example I've got this C function:

void f(int *x, int *y)
{
    (*x) = (*x) * (*y);
}

When saved to f.c, compiling with gcc -c f.c produces f.o. objdump -d f.o gives this:

f.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <f>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
   8:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
   c:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  10:   8b 10                   mov    (%rax),%edx
  12:   48 8b 45 f0             mov    -0x10(%rbp),%rax
  16:   8b 00                   mov    (%rax),%eax
  18:   0f af d0                imul   %eax,%edx
  1b:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  1f:   89 10                   mov    %edx,(%rax)
  21:   5d                      pop    %rbp
  22:   c3                      retq  

I'd like it to output something more like this:

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3

I.e., just the hexadecimal values of the function. Is there some objdump flag to do this? Otherwise, what tools can I use (e.g. awk, sed, cut, etc) to get this desired output?

MD XF
  • 191
  • 1
  • 3
  • 13
  • 1
    `objdump -s` is somewhat like this. Or `objcopy -O binary infile outfile` to get a file without headers that you can then do a hex dump on. `-j .text` with either command to select the text section only. I wonder what you're really trying to do, and how "hex dump the function" became part of the solution –  Feb 03 '18 at 00:41

4 Answers4

11

You can extract the byte values in the text segment with:

$ objcopy -O binary -j .text f.o fo

The -O binary option:

objcopy can be used to generate a raw binary file by using an output target of binary (e.g., use -O binary). When objcopy generates a raw binary file, it will essentially produce a memory dump of the contents of the input object file. All symbols and relocation information will be discarded. The memory dump will start at the load address of the lowest section copied into the output file.

The -j .text option:

-j sectionpattern
--only-section=sectionpattern
Copy only the indicated sections from the input file to the output file. This option may be given more than once.
Note that using this option inappropriately may make the output file unusable. Wildcard characters are accepted in sectionpattern.

The end result is a file (fo) with the binary values of only the .text section, that is the executable code without symbols or relocation information.

And then print the hex values of the fo file:

$ od -An -v -t x1 fo
 55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8
 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89
 10 90 5d c3
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
3

How about

awk '/^....:/{a=substr($0,9,20);sub(/ +$/,"",a);b=b" "a}END{print substr(b,2)}'

In this case, would return

55 48 89 e5 48 89 7d f8 48 89 75 f0 48 8b 45 f8 8b 10 48 8b 45 f0 8b 00 0f af d0 48 8b 45 f8 89 10 5d c3
steve
  • 21,582
  • 5
  • 48
  • 75
  • What's the invocation for this command? I.e. where does the `objdump` go, standard in? – MD XF Feb 03 '18 at 00:48
  • Yes, standard in. `objdump -d f.o | awk '/^....:/{a=substr($0,9,20);sub(/ +$/,"",a);b=b" "a}END{print substr(b,2)}'` – steve Feb 03 '18 at 00:48
0

Another option is to use readelf:

$ readelf -x .text f.o

Hex dump of section '.text':
  0x00070c00 f30f1efa 488d15fd 13100048 8d357606 ....H......H.5v.
  0x00070c10 1100488d 3dc33809 00e902f5 fffff30f ..H.=.8.........
  0x00070c20 1efa5548 8d2d9606 1100be22 00000045 ..UH.-....."...E
  ...

With some specific .elf files, objdump and objcopy are lost for an unkown reason (maybe a specific arch incompatibility) and readelf is the only working solution I could find.

calandoa
  • 313
  • 3
  • 6
0

solution 1:

42sh$ objcopy -j .text f.o /proc/self/fd/1 -O verilog | tail -n +2 | tr '\n' ' ' | tr -d '\r'
8B 07 0F AF 06 89 07 C3 42sh$

You see the '\n' is transformed in space so we get a trailling space instead of last newline. tail and tr are only used to convert exactly like you asked.

solution 2:

42sh$ objcopy -O binary -j .text f.o /proc/self/fd/1 | xxd -ps -c 36 | sed 's,..,& ,g; s, $,,'
8b 07 0f af 06 89 07 c3
42sh$

Here we ask objcopy to print in raw binary, then we encode in hex with xxd (stand for hexa decimal dump) instead of od (stand for octal dump) like accepted answer.

-c is number of char you can use a huge number of char if you want all symbols in one line. The sed use two substitution like explained with https://askubuntu.com/a/661687/772955 one to intersperse space and one to remove last space. Sed keep \n

Common explanation:

objcopy read only the section we want.

In both solution we avoid temporary file by writing directly in the pipe /dev/stdout which point to /proc/self/fd/1 on linux and /dev/fd/1 on darwin.

The we need to convert to hex in case of binary output.

And then we prettify with sed/tr, awk/perl could be used

Edit 1:

Thanks @Stéphane Chazelas

Et7f3XIV
  • 103
  • 6
  • See `/dev/stdout` as a more portable alternative to `/proc/self/fd/1` – Stéphane Chazelas May 27 '23 at 15:10
  • 1
    `objcopy -j .text a.o /dev/stdout -O verilog | tail -n +2 | tr -d '\r' | paste -sd ' ' -` to avoid the problem with the missing line delimiter in that output. – Stéphane Chazelas May 27 '23 at 15:13
  • /dev/stdout is a char device: it will only print on the linked tty. In interactive sessions it is fine but if user wants to use in wider script it become inappropriate. For instance `var=$(your command);` will print directly and var will be empty. Thanks for your remarks on portability I should have warned it is only for linux. It should be $CONOUT on windows. – Et7f3XIV May 28 '23 at 17:53
  • `/dev/stdout` on Linux is a symlink to `/proc/self/fd/1` and on most other systems, a character device that acts so that opening it is like doing a `dup(1)`. In any case, it has nothing to do with ttys. You may be confusing with `/dev/tty`. – Stéphane Chazelas May 28 '23 at 17:56
  • In alpine: ls -lah /proc/self/fd/1 /dev/stdout ls: /dev/stdout: No such file or directory lrwxrwxrwx 0 root root 0 Jan 1 1970 /proc/self/fd/1 -> /dev/pts/0 – Et7f3XIV May 28 '23 at 18:04
  • 1
    Sounds like your system is broken if it's missing the `/dev/stdout` symlink. Note that `/proc/self/fd/1` is a magic symlink that points to the file opened on fd 1. In `ls -l /proc/self/fd/1 | cat`, you'd see an anonymous pipe as the target of the symlink as that's as that's what stdout is. – Stéphane Chazelas May 28 '23 at 18:09
  • Maybe I need to load a module for this symlink to appear on alpine. I will update my reply with your remark. – Et7f3XIV May 29 '23 at 19:25