From 380465cc62d2a8cd59e4c69026e64f0f97a79e2f Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 21 Nov 2020 18:29:54 +0100 Subject: rename 01 --- 01_dynamic_linking/Makefile | 13 ++++++ 01_dynamic_linking/README.md | 103 ++++++++++++++++++++++++++++++++++++++++++ 01_dynamic_linking/libgreet.c | 5 ++ 01_dynamic_linking/main.c | 6 +++ 01_hello_dynld/Makefile | 13 ------ 01_hello_dynld/README.md | 103 ------------------------------------------ 01_hello_dynld/libgreet.c | 5 -- 01_hello_dynld/main.c | 6 --- 8 files changed, 127 insertions(+), 127 deletions(-) create mode 100644 01_dynamic_linking/Makefile create mode 100644 01_dynamic_linking/README.md create mode 100644 01_dynamic_linking/libgreet.c create mode 100644 01_dynamic_linking/main.c delete mode 100644 01_hello_dynld/Makefile delete mode 100644 01_hello_dynld/README.md delete mode 100644 01_hello_dynld/libgreet.c delete mode 100644 01_hello_dynld/main.c diff --git a/01_dynamic_linking/Makefile b/01_dynamic_linking/Makefile new file mode 100644 index 0000000..efcc457 --- /dev/null +++ b/01_dynamic_linking/Makefile @@ -0,0 +1,13 @@ +inspect: build + readelf -W --sections main + readelf -W --dynamic main + readelf -W --program-headers main + readelf -W --string-dump .interp main + gdb -q --batch -ex 'starti' -ex 'bt' ./main + +build: libgreet.c main.c + gcc -o libgreet.so libgreet.c -shared -fPIC + gcc -o main main.c -lgreet -L. -Wl,--rpath=$(PWD) + +clean: + rm -f libgreet.so main diff --git a/01_dynamic_linking/README.md b/01_dynamic_linking/README.md new file mode 100644 index 0000000..6c0dd5d --- /dev/null +++ b/01_dynamic_linking/README.md @@ -0,0 +1,103 @@ +# Hello dynamic linking + +In `dynamic linking` a program can use code that is not contained in the +program file itself but rather in separate library files, so called shared +objects. + +In comparison a statically linked program contains all the `code` & `data` that +it needs to run from start until completion. The program will be loaded by the +Linux Kernel from the disk into the virtual address space and control is handed +over to the mapped program which then executes. +```text + @vm + | | + @disk |--------| ++--------+ execve(2) | | <- $rip +| prog A | ------------> | prog A | ++--------+ | | + |--------| + | | +``` + +A dynamically linked program on the other hand needs to specify a `dynamic +linker` which is basically a runtime interpreter. The Linux Kernel will additionally load +that interpreter into the virtual address space and give control to the +interpreter rather than the user program. +The interpreter will prepare the execution environment for the user program by +for example loading dependencies and running initialization routines. After the +environment is set up the dynamic linker passes control to the user program. +```text + @vm @vm + | | | | + @disk |--------| |----------| ++--------------+ execve(2) | | | | <- $rip +| prog A | ------------> | prog A | | prog A | ++--------------+ | | load deps | | +| interp ldso | |--------| ------------> |----------| ++--------------+ | | | | +| dep libgreet | |--------| |----------| ++--------------+ | ldso | <- $rip | ldso | + |--------| |----------| + | | + |----------| + | libgreet | + |----------| +``` +> NOTE: Technically the Linux Kernel does not need to load the dynamically +> linked user program itself, but that detail is not important here. + +In the `ELF` binary format the name of the dynamic linker is specified as a +string in the special section `.interp`. +```bash +readelf -W --string-dump .interp main + +String dump of section '.interp': + [ 0] /lib64/ld-linux-x86-64.so.2 +``` + +The `.interp` section is referenced by the `PT_INTERP` segment in the program +headers. This segment is used by the Linux Kernel during the `execve(2)` +syscall in the [`load_elf_binary`][load_elf_binary] function to check if the +program needs a dynamic linker and if so to retrieve its name. +```bash +readelf -W --sections --program-headers main + +Section Headers: + [Nr] Name Type Address Off Size ES Flg Lk Inf Al + [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 + [ 1] .interp PROGBITS 00000000000002a8 0002a8 00001c 00 A 0 0 1 + ... + +Program Headers: + Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align + PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R 0x8 + INTERP 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R 0x1 + [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] + ... +``` + +With the use of `gdb` it can be easily verified that the control is first +passed to the dynamic linker and not the user program. This is shown by +stopping at the first instruction of the new process (`starti`) and examining +the backtrace (`bt`). Where `ld-linux-x86-64.so` is the dynamic linker as shown +in the `.interp` section above. +```bash +gdb -q --batch -ex 'starti' -ex 'bt' ./main + +Program stopped. +0x00007ffff7fd2090 in _start () from /lib64/ld-linux-x86-64.so.2 +#0 0x00007ffff7fd2090 in _start () from /lib64/ld-linux-x86-64.so.2 +#1 0x0000000000000001 in ?? () +#2 0x00007fffffffe43e in ?? () +#3 0x0000000000000000 in ?? () +``` +> NOTE: Frames `#1 - #3` don't actually exist, gdb's unwinder just tried to further unwind the stack. + +## Things to remember +- Dynamically linked programs use code contained in separate library files. +- The `dynamic linker` is an interpreter loaded by the Linux Kernel and gets + control before the user program. +- A dynamically linked program specifies the dynamic linker needed in the + `.interp` section. + +[load_elf_binary]: https://elixir.bootlin.com/linux/v5.9.8/source/fs/binfmt_elf.c#L850 diff --git a/01_dynamic_linking/libgreet.c b/01_dynamic_linking/libgreet.c new file mode 100644 index 0000000..2419d92 --- /dev/null +++ b/01_dynamic_linking/libgreet.c @@ -0,0 +1,5 @@ +#include + +void greet() { + puts("Hello from libgreet.so!"); +} diff --git a/01_dynamic_linking/main.c b/01_dynamic_linking/main.c new file mode 100644 index 0000000..a12a448 --- /dev/null +++ b/01_dynamic_linking/main.c @@ -0,0 +1,6 @@ +extern void greet(); + +int main() { + greet(); + return 0; +} diff --git a/01_hello_dynld/Makefile b/01_hello_dynld/Makefile deleted file mode 100644 index efcc457..0000000 --- a/01_hello_dynld/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -inspect: build - readelf -W --sections main - readelf -W --dynamic main - readelf -W --program-headers main - readelf -W --string-dump .interp main - gdb -q --batch -ex 'starti' -ex 'bt' ./main - -build: libgreet.c main.c - gcc -o libgreet.so libgreet.c -shared -fPIC - gcc -o main main.c -lgreet -L. -Wl,--rpath=$(PWD) - -clean: - rm -f libgreet.so main diff --git a/01_hello_dynld/README.md b/01_hello_dynld/README.md deleted file mode 100644 index 6c0dd5d..0000000 --- a/01_hello_dynld/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Hello dynamic linking - -In `dynamic linking` a program can use code that is not contained in the -program file itself but rather in separate library files, so called shared -objects. - -In comparison a statically linked program contains all the `code` & `data` that -it needs to run from start until completion. The program will be loaded by the -Linux Kernel from the disk into the virtual address space and control is handed -over to the mapped program which then executes. -```text - @vm - | | - @disk |--------| -+--------+ execve(2) | | <- $rip -| prog A | ------------> | prog A | -+--------+ | | - |--------| - | | -``` - -A dynamically linked program on the other hand needs to specify a `dynamic -linker` which is basically a runtime interpreter. The Linux Kernel will additionally load -that interpreter into the virtual address space and give control to the -interpreter rather than the user program. -The interpreter will prepare the execution environment for the user program by -for example loading dependencies and running initialization routines. After the -environment is set up the dynamic linker passes control to the user program. -```text - @vm @vm - | | | | - @disk |--------| |----------| -+--------------+ execve(2) | | | | <- $rip -| prog A | ------------> | prog A | | prog A | -+--------------+ | | load deps | | -| interp ldso | |--------| ------------> |----------| -+--------------+ | | | | -| dep libgreet | |--------| |----------| -+--------------+ | ldso | <- $rip | ldso | - |--------| |----------| - | | - |----------| - | libgreet | - |----------| -``` -> NOTE: Technically the Linux Kernel does not need to load the dynamically -> linked user program itself, but that detail is not important here. - -In the `ELF` binary format the name of the dynamic linker is specified as a -string in the special section `.interp`. -```bash -readelf -W --string-dump .interp main - -String dump of section '.interp': - [ 0] /lib64/ld-linux-x86-64.so.2 -``` - -The `.interp` section is referenced by the `PT_INTERP` segment in the program -headers. This segment is used by the Linux Kernel during the `execve(2)` -syscall in the [`load_elf_binary`][load_elf_binary] function to check if the -program needs a dynamic linker and if so to retrieve its name. -```bash -readelf -W --sections --program-headers main - -Section Headers: - [Nr] Name Type Address Off Size ES Flg Lk Inf Al - [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 - [ 1] .interp PROGBITS 00000000000002a8 0002a8 00001c 00 A 0 0 1 - ... - -Program Headers: - Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align - PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R 0x8 - INTERP 0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R 0x1 - [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] - ... -``` - -With the use of `gdb` it can be easily verified that the control is first -passed to the dynamic linker and not the user program. This is shown by -stopping at the first instruction of the new process (`starti`) and examining -the backtrace (`bt`). Where `ld-linux-x86-64.so` is the dynamic linker as shown -in the `.interp` section above. -```bash -gdb -q --batch -ex 'starti' -ex 'bt' ./main - -Program stopped. -0x00007ffff7fd2090 in _start () from /lib64/ld-linux-x86-64.so.2 -#0 0x00007ffff7fd2090 in _start () from /lib64/ld-linux-x86-64.so.2 -#1 0x0000000000000001 in ?? () -#2 0x00007fffffffe43e in ?? () -#3 0x0000000000000000 in ?? () -``` -> NOTE: Frames `#1 - #3` don't actually exist, gdb's unwinder just tried to further unwind the stack. - -## Things to remember -- Dynamically linked programs use code contained in separate library files. -- The `dynamic linker` is an interpreter loaded by the Linux Kernel and gets - control before the user program. -- A dynamically linked program specifies the dynamic linker needed in the - `.interp` section. - -[load_elf_binary]: https://elixir.bootlin.com/linux/v5.9.8/source/fs/binfmt_elf.c#L850 diff --git a/01_hello_dynld/libgreet.c b/01_hello_dynld/libgreet.c deleted file mode 100644 index 2419d92..0000000 --- a/01_hello_dynld/libgreet.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -void greet() { - puts("Hello from libgreet.so!"); -} diff --git a/01_hello_dynld/main.c b/01_hello_dynld/main.c deleted file mode 100644 index a12a448..0000000 --- a/01_hello_dynld/main.c +++ /dev/null @@ -1,6 +0,0 @@ -extern void greet(); - -int main() { - greet(); - return 0; -} -- cgit v1.2.3