The ELF (Executable and Linkable Format) is the standard file format for programs on Linux. It has three main types:
int add(int a, int b)
{
return a + b;
}
$ gcc -Og -c add.c
$ file add.o
add.o: ELF 64-bit LSB relocatable, x86-64
$ objdump --syms add.o
SYMBOL TABLE:
Start Address Length
0000000000000000 g F .text 0000000000000008 add
$ objdump --disassemble add.o
0000000000000000 <add>:
0: f3 0f 1e fa endbr64
4: 8d 04 37 lea (%rdi,%rsi,1),%eax
7: c3 ret
int add(int a, int b);
int main(int argc, char** agrv)
{
(1, 2);
add
return 0;
}
$ gcc -Og -c add.c
$ gcc -Og -c main.c
$ gcc -Og -o prog main.o add.o
$ file prog
prog: ELF 64-bit LSB pie executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2
$ objdump --syms prog
000000000000114a g F .text 0000000000000008 add
0000000000001129 g F .text 0000000000000021 main
$ objdump --disassemble prog
0000000000001129 <main>:
1129: f3 0f 1e fa endbr64
112d: 48 83 ec 08 sub $0x8,%rsp
1131: be 02 00 00 00 mov $0x2,%esi
1136: bf 01 00 00 00 mov $0x1,%edi
113b: e8 0a 00 00 00 call 114a <add>
1140: b8 00 00 00 00 mov $0x0,%eax
1145: 48 83 c4 08 add $0x8,%rsp
1149: c3 ret
000000000000114a <add>:
114a: f3 0f 1e fa endbr64
114e: 8d 04 37 lea (%rdi,%rsi,1),%eax
1151: c3 ret
int subtract(int a, int b)
{
return a - b;
}
int subtract(int a, int b);
int main(int argc, char** agrv)
{
(1, 2);
subtract
return 0;
}
$ gcc -Og -fPIC -c sub.c
$ gcc -shared -o libSub.so sub.o
$ gcc -Og -c main.c
$ gcc -Og -o prog main.o -L. -lSub
$ file libSub.so
libSub.so: ELF 64-bit LSB shared object, x86-64, dynamically linked
$ objdump --syms libSub.so
00000000000010f9 g F .text 0000000000000009 subtract
$ objdump --syms prog
0000000000001149 g F .text 0000000000000021 main
0000000000000000 F *UND* 0000000000000000 subtract
$ objdump --disassemble prog
Disassembly of section .plt.sec:
0000000000001050 <subtract@plt>:
1050: f3 0f 1e fa endbr64
1054: ff 25 76 2f 00 00 jmp *0x2f76(%rip) # 3fd0 <subtract@Base>
105a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
Disassembly of section .text:
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 48 83 ec 08 sub $0x8,%rsp
1151: be 02 00 00 00 mov $0x2,%esi
1156: bf 01 00 00 00 mov $0x1,%edi
115b: e8 f0 fe ff ff call 1050 <subtract@plt>
1160: b8 00 00 00 00 mov $0x0,%eax
1165: 48 83 c4 08 add $0x8,%rsp
1169: c3 ret
subtract@plt
is a function in the Procedure Linkage
Table (PLT) that handles dynamic linking to the actual
subtract
function in a shared library. When the program
first calls subtract@plt
, it resolves and jumps to the real
subtract
function. After the first call, subsequent calls
directly invoke subtract
.
$ export LD_LIBRARY_PATH=.
$ gdb prog
(gdb) start
Temporary breakpoint 1, 0x0000555555555149 in main ()
(gdb) info sharedlibrary
From To Syms Read Shared Object Library
0x00007ffff7fc6000 0x00007ffff7ff0195 Yes /lib64/ld-linux-x86-64.so.2
0x00007ffff7fb9040 0x00007ffff7fb9102 Yes (*) ./libSub.so
0x00007ffff7c28800 0x00007ffff7dafcb9 Yes /lib/x86_64-linux-gnu/libc.so.6
(gdb) info functions subtract
Non-debugging symbols:
0x0000555555555050 subtract@plt
0x00007ffff7fb90f9 subtract
(gdb) break subtract@plt
Breakpoint 2 at 0x555555555050
(gdb) break subtract
Breakpoint 3 at 0x7ffff7fb90f9
(gdb) c
Continuing.
Breakpoint 2, 0x0000555555555050 in subtract@plt ()
(gdb) c
Continuing.
Breakpoint 3, 0x00007ffff7fb90f9 in subtract () from ./libSub.so