Can it be done with objdump, readelf or some such?
Sure: you can write out the bytes that comprise the function using GDB. Example:
cat t.c
int foo() { return 42; }
int main() { return foo(); }
gcc t.c
gdb -q ./a.out
(gdb) disas/r foo
Dump of assembler code for function foo:
0x00000000004004c4 <+0>: 55 push %rbp
0x00000000004004c5 <+1>: 48 89 e5 mov %rsp,%rbp
0x00000000004004c8 <+4>: b8 2a 00 00 00 mov $0x2a,%eax
0x00000000004004cd <+9>: c9 leaveq
0x00000000004004ce <+10>: c3 retq
End of assembler dump.
(gdb) dump memory foo.o 0x00000000004004c4 0x00000000004004ce+1
(gdb) quit
od -tx1 foo.o
0000000 55 48 89 e5 b8 2a 00 00 00 c9 c3
0000013
Note that the contents of foo.o is exactly the code bytes of foo.
I want to get foo.o
That part unfortunately is impossible: the relocation records have all been resolved. If foo() calls bar(), the bar
will not appear anywhere in the code, only its address.
Now, if the functions need are all leaf (don't call any other ones), and don't reference any global data, then the byte sequence you now know how to dump can be used to reconstruct a linkable foo.o, like so:
{ echo -e "foo:\n\t.byte\t\c";
od -tx1 foo.o | cut -c9- |
sed -e '/^ *$/d' -e 's/^/0x/' -e 's/ /,0x/g'; } > foo1.s
cat foo1.s
foo:
.byte 0x55,0x48,0x89,0xe5,0xb8,0x2a,0x00,0x00,0x00,0xc9,0xc3
gcc -c foo1.s
objdump -d foo1.o
foo1.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <foo>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 2a 00 00 00 mov $0x2a,%eax
9: c9 leaveq
a: c3 retq
QED