# Lista 8 (29 kwietnia 2021) ###### tags: `ask21` `ćwiczenia` `kba` ## Deklaracje Gotowość rozwiązania zadania należy wyrazić poprzez postawienie X w odpowiedniej kolumnie! Jeśli pożądasz zreferować dane zadanie (co najwyżej jedno!) w trakcie dyskusji oznacz je znakiem ==X== na żółtym tle. **UWAGA: Tabelkę wolno edytować tylko wtedy, gdy jest na zielonym tle!** :::danger | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | | --------------------:| ----- | ----- | --- | --- | --- | ----- | --- | --- | | Andriy Bernad | ==X== | X | X | X | X | X | X | | 7 | Wojciech Bogucki| X | X | X | X | | | | | 4 | Michał Doros | X | X | X | X | | | | | 4 | Marko Golovko | | | | | | | | | 0 | Magdalena Jarecka | ==X== | X | X | X | X | | | | 5 | Szymon Jędras | X | X | X | | | | | | 3 | Heorhii Karpenko | X | X | X |==X==| X | X | X | | 7 | Szymon Kosakowski | X | ==X== | X | X | | | | | 4 | Izabella Kozioł | | | | | | | | | 0 | Franciszek Malinka | X | X | X | X | X | | | | 5 | Filip Pazera | | | | | | | | | 0 | Franciszek Pindel | X | X | X | X | X | X | X | | 7 | Kacper Puchalski | X | X | X | X | | | | | 4 | Kacper Solecki | X | X | X | X | | | | | 4 | Andrzej Tkaczyk | X | X | | | X | ==X== | X | | 5 | Łukasz Wasilewski | X | X | X | X | | | | | 4 | Vladyslav Yablonskyi | X | X | X | X | X | | | | 5 | Adam Zyzik | X | X | X | X | X | | | | 5 ::: ## Zadanie 1 :::info Autor: Magdalena Jarecka ::: **Plik relokowany** - assembler generuje ten plik podczas kompilacji pliku z kodem źródłowym. Jest on potrzebny do późniejszego przetworzenia przez kosolidator aby uzyskać plik wykonywalny lub bibliotekę dynamiczną. ``` readelf -t -s: ``` ``` There are 15 section headers, starting at offset 0x498: Section Headers: [Nr] Name Type Address Offset Link Size EntSize Info Align Flags [ 0] NULL 0000000000000000 0000000000000000 0 0000000000000000 0000000000000000 0 0 [0000000000000000]: [ 1] .text PROGBITS 0000000000000000 0000000000000040 0 000000000000006b 0000000000000000 0 1 [0000000000000006]: ALLOC, EXEC [ 2] .rela.text RELA 0000000000000000 0000000000000310 12 00000000000000c0 0000000000000018 1 8 [0000000000000040]: INFO LINK [ 3] .data PROGBITS 0000000000000000 00000000000000ab 0 0000000000000000 0000000000000000 0 1 [0000000000000003]: WRITE, ALLOC [ 4] .bss NOBITS 0000000000000000 00000000000000b0 0 000000000000000c 0000000000000000 0 8 [0000000000000003]: WRITE, ALLOC [ 5] .data.rel PROGBITS 0000000000000000 00000000000000b0 0 0000000000000008 0000000000000000 0 8 [0000000000000003]: WRITE, ALLOC [ 6] .rela.data.rel RELA 0000000000000000 00000000000003d0 12 0000000000000018 0000000000000018 5 8 [0000000000000040]: INFO LINK [ 7] .comment PROGBITS 0000000000000000 00000000000000b8 0 000000000000002b 0000000000000001 0 1 [0000000000000030]: MERGE, STRINGS [ 8] .note.GNU-stack PROGBITS 0000000000000000 00000000000000e3 0 0000000000000000 0000000000000000 0 1 [0000000000000000]: [ 9] .note.gnu.property NOTE 0000000000000000 00000000000000e8 0 0000000000000020 0000000000000000 0 8 [0000000000000002]: ALLOC [10] .eh_frame PROGBITS 0000000000000000 0000000000000108 0 0000000000000058 0000000000000000 0 8 [0000000000000002]: ALLOC [11] .rela.eh_frame RELA 0000000000000000 00000000000003e8 12 0000000000000030 0000000000000018 10 8 [0000000000000040]: INFO LINK [12] .symtab SYMTAB 0000000000000000 0000000000000160 13 0000000000000180 0000000000000018 13 8 [0000000000000000]: [13] .strtab STRTAB 0000000000000000 00000000000002e0 0 000000000000002d 0000000000000000 0 1 [0000000000000000]: [14] .shstrtab STRTAB 0000000000000000 0000000000000418 0 000000000000007b 0000000000000000 0 1 [0000000000000000]: Symbol table '.symtab' contains 16 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS swap.c 2: 0000000000000000 0 SECTION LOCAL DEFAULT 1 3: 0000000000000000 0 SECTION LOCAL DEFAULT 3 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 5: 0000000000000000 0 SECTION LOCAL DEFAULT 5 6: 0000000000000000 8 OBJECT LOCAL DEFAULT 4 bufp1 7: 0000000000000000 26 FUNC LOCAL DEFAULT 1 incr 8: 0000000000000008 4 OBJECT LOCAL DEFAULT 4 count.1915 9: 0000000000000000 0 SECTION LOCAL DEFAULT 8 10: 0000000000000000 0 SECTION LOCAL DEFAULT 9 11: 0000000000000000 0 SECTION LOCAL DEFAULT 10 12: 0000000000000000 0 SECTION LOCAL DEFAULT 7 13: 0000000000000000 8 OBJECT GLOBAL DEFAULT 5 bufp0 14: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND buf 15: 000000000000001a 81 FUNC GLOBAL DEFAULT 1 swap .text - kod programu .data - zainicjowane zmienne globalne .bss - niezainicjowane zmienne ``` Sekcja .strtab (string table) przechowuje tablice stringów dla wszystkich referencji, tzn. stringi reprezentujące nazwy symboli. Sekcja .shstrtab (section header string table) przechowuje nazwy sekcji. **Co gdzie jest:** - adres symbolu względem początku sekcji. **Value w .symtab** - typ symbolu – tj. «local», «global», «extern». **Type, Bind** - rozmiar danych, na które wskazuje symbol. **Size** - numer i nazwę sekcji – tj. «.text», «.data», «.bss» – do której odnosi się symbol. **NDX w Section Headers** ## Zadanie 2 :::info Autor: Szymon Kosakowski ::: ```c= // mismatch-a.c void p2(void); //symbol silny int main() { //symbol silny p2(); return 0; } ``` ```c= // mismatch-b.c #include <stdio.h> char main; //symbol słaby void p2() { //symbol silny printf("0x%x\n", main); } ``` Nie pokazuje się żaden błąd, gdyż linker wybiera zawsze silny symbol, tzn. w mismatch-a.c mamy zainicjowany main oraz jest on globalny, czyli jest silny, a w mismatch-b.c nie jest on zainicjowany, więc jest słaby. Gdybyśmy chcieli przypisać wartość pod zmienną globalną main w pliku mismatch-b.c, to otrzymalibyśmy błąd `multiple definition of 'main'`. Gdy chcemy przypisać wartość zmiennej main w ciele funkcji p2, to program skompiluje się poprawnie, jednak po uruchomieniu go otrzymamy Segmentation fault. Dzieje się tak bo będziemy chcieli wtedy pisać po wartości tylko do odczytu. Wartość wypisywana przez program to pierwszy bajt main, w moim przypadku jest to `0x48`. Można to sprawdzić wykonując `objdump -d mismatch-a.o`: ``` Disassembly of section .text: 0000000000000000 <main>: 0: 48 83 ec 08 sub $0x8,%rsp 4: e8 00 00 00 00 call 9 <main+0x9> 9: b8 00 00 00 00 mov $0x0,%eax e: 48 83 c4 08 add $0x8,%rsp 12: c3 ret ``` ## Zadanie 3 :::success Autor: Szymon Jędras ::: ### Treść zadania ![](https://i.imgur.com/QqhApWe.png) ### 1: Tą komnedą otrzymamy zawartość biblioteki: `ar -t libc.a` dodając wc z flagą -l `ar -t libc.a | wc -l` otrzymy ilość plików w bibliotece. ### 2: Nie, ponieważ flaga `-g` nie modyfikuje kodu, jedynie dodaje symbole ułatwiające debuggowanie. ### 3: za pomocą komend: `ldd python3` lub `readelf -d python3 | grep 'NEEDED'` otrzymamy że python3 korzysta z tych bibliotek: ``` linux-vdso.so.1 libc.so.6 libpthread.so.0 libdl.so.2 libutil.so.1 libm.so.6 libexpat.so.1 libz.so.1 ``` :::spoiler Wynik `ldd python3` ``` linux-vdso.so.1 (0x00007fffcbc82000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa30c220000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa30c1fd000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa30c1f0000) libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007fa30c1e0000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa30c091000) libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007fa30c060000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fa30c030000) ``` ::: :::spoiler Wynik `readelf -d python3 | grep 'NEEDED'` ``` 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x0000000000000001 (NEEDED) Shared library: [libpthread.so.0] 0x0000000000000001 (NEEDED) Shared library: [libdl.so.2] 0x0000000000000001 (NEEDED) Shared library: [libutil.so.1] 0x0000000000000001 (NEEDED) Shared library: [libm.so.6] 0x0000000000000001 (NEEDED) Shared library: [libexpat.so.1] 0x0000000000000001 (NEEDED) Shared library: [libz.so.1] ``` ::: ## Zadanie 4 :::info Autor: Kacper Puchalski ::: ![](https://i.imgur.com/Q5MkMoP.png) ``` objdump -s str-b.o ``` hello world jest w sekcji **read only data**, więc nie możemy nic w nim zmienić Można to rozwiązać wrzucając hello worlda do tablicy charów. ``` char pom[]="Hello, world!"; ``` daje to kolejnego seg faulta, ponieważ zmienna jest lokalna, w związku z czym niewidoczna poza funkcją. Trzeba zatem dodać statica. ```c= char *somestr(void) { static char pom[]="Hello, world!"; return pom; } ``` Po zamianie hello world znajduje się w sekcji **data** ## Zadanie 5 :::info Autor: Adam Zyzik ::: ![](https://i.ibb.co/4mcbmgt/Screenshot-2021-04-29-121814.png) Rozmiary sekcji: `objdump -h bar.o`, `objdump -h foo.o` Offsety i rozmiary symboli: `readelf -s bar.o`, `readelf -s foo.o` Opcja `fno-common` umieszcza niezainicjalizowane globalne symbole w sekcji `.bss` zamiast w sekcji `.common`. Z grubsza znaczy to tyle, że nie możemy mieć dwóch zmiennych o zasięgu globalnym o takiej samej nazwie w dwóch różnych plikach relokowalnych, które są linkowane. <kbd>![](https://i.ibb.co/41vCLgm/common.png)</kbd> :::spoiler `man gcc` -fno-common In C code, this option controls the placement of global variables defined without an initializer, known as tentative definitions in the C standard. Tentative definitions are distinct from declarations of a variable with the "extern" keyword, which do not allocate storage. Unix C compilers have traditionally allocated storage for uninitialized global variables in a common block. This allows the linker to resolve all tentative definitions of the same variable in different compilation units to the same object, or to a non-tentative definition. This is the behavior specified by -fcommon, and is the default for GCC on most targets. On the other hand, this behavior is not required by ISO C, and on some targets may carry a speed or code size penalty on variable references. The -fno-common option specifies that the compiler should instead place uninitialized global variables in the BSS section of the object file. This inhibits the merging of tentative definitions by the linker so you get a multiple-definition error if the same variable is defined in more than one compilation unit. Compiling with -fno-common is useful on targets for which it provides better performance, or if you wish to verify that the program will work on other systems that always treat uninitialized variable definitions this way. ::: **Częściowa konsolidacja** -- łączymy kilka plików relokowalnych w jeden plik relokowalny (zamiast od razu w plik wykonywalny). ::: spoiler **Mapa konsolidacji** ``` -M --print-map Print a link map to the standard output. A link map provides information about the link, including the following: • Where object files are mapped into memory. • How common symbols are allocated. • All archive members included in the link, with a mention of the symbol which caused the archive member to be brought in. • The values assigned to symbols. ``` ::: `ld -M=merge-1.map -r -o merge-1.o foo.o bar.o` `ld -M=merge-2.map -r -o merge-2.o bar.o foo.o` ::: spoiler merge-1.map: ``` .data 0x0000000000000000 0xc *(.data) .data 0x0000000000000000 0x8 foo.o 0x0000000000000000 foo .data 0x0000000000000008 0x4 bar.o 0x0000000000000008 bar ``` ::: ::: spoiler merge-2.map: ``` .data 0x0000000000000000 0x10 *(.data) .data 0x0000000000000000 0x4 bar.o 0x0000000000000000 bar *fill* 0x0000000000000004 0x4 .data 0x0000000000000008 0x8 foo.o 0x0000000000000008 foo ``` ::: Sposób wygenerowania plików merge-1.o i merge-2.o różni się po prostu kolejnością łączenia ich. Skutkuje to odwrotną kolejnością zmiennych w sekcjach `.data`, `.bss`. Różna kolejność oznacza w tym przypadku różny rozmiar tych sekcji, ze względu na padding. ::: spoiler `objdump -h merge-1.o`: ``` merge-1.o: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .note.gnu.property 00000020 0000000000000000 0000000000000000 00000040 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 00000000 0000000000000000 0000000000000000 00000060 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .data 0000000c 0000000000000000 0000000000000000 00000060 2**3 CONTENTS, ALLOC, LOAD, DATA 3 .bss 0000003e 0000000000000000 0000000000000000 00000070 2**4 ALLOC 4 .comment 00000056 0000000000000000 0000000000000000 00000070 2**0 CONTENTS, READONLY 5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000c6 2**0 CONTENTS, READONLY ``` ::: ::: spoiler `objdump -h merge-2.o`: ``` merge-2.o: file format elf64-x86-64 Sections: Idx Name Size VMA LMA File off Algn 0 .note.gnu.property 00000020 0000000000000000 0000000000000000 00000040 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .text 00000000 0000000000000000 0000000000000000 00000060 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .data 00000010 0000000000000000 0000000000000000 00000060 2**3 CONTENTS, ALLOC, LOAD, DATA 3 .bss 00000031 0000000000000000 0000000000000000 00000070 2**4 ALLOC 4 .comment 00000056 0000000000000000 0000000000000000 00000070 2**0 CONTENTS, READONLY 5 .note.GNU-stack 00000000 0000000000000000 0000000000000000 000000c6 2**0 CONTENTS, READONLY ``` ::: Konsolidator nie dysponuje informacjami o typach języka C, ale wymagane wyrównanie jest zapisane w nagłówkach sekcji. ::: spoiler `readelf -t foo.o` ``` Section Headers: [Nr] Name Type Address Offset Link Size EntSize Info Align Flags [ 2] .data PROGBITS 0000000000000000 0000000000000040 0 0000000000000008 0000000000000000 0 8 [0000000000000003]: WRITE, ALLOC ``` ::: ::: spoiler `readelf -t bar.o` ``` Section Headers: [Nr] Name Type Address Offset Link Size EntSize Info Align Flags [ 2] .data PROGBITS 0000000000000000 0000000000000040 0 0000000000000004 0000000000000000 0 4 [0000000000000003]: WRITE, ALLOC ``` ::: ## Zadanie 6 :::success Autor: Andrzej Tkaczyk ::: :::info Zadanie 6. Plik wykonywalny powstały w wyniku kompilacji poniższych plików źródłowych powinien być nie dłuższy niż 1KiB. Na podstawie nagłówka pliku ELF wskaż w zdeasemblowanym pierwszą instrukcję, którą wykona procesor po wejściu do programu. Na podstawie nagłówków programu wskaż pod jaki adres wirtualny zostanie załadowany segment z sekcją «.text». 1 /* start.c */ 2 int is_even(long); 3 8 return is_odd(n - 1); 9 } 1 /* odd.c */ 2 int is_even(long n); 3 4 int is_odd(long n) { 5 if (n == 0) 6 return 0; 7 else 8 return is_even(n - 1); 9 } Zapoznaj się ze skryptem konsolidatora w pliku «main.lds». Na podstawie dokumentacji1 wyjaśnij jak skrypt kieruje procesem konsolidacji poszczególnych sekcji i tworzeniem nagłówków programu. ::: plik wykonywalny - plik binarny który może być uruchomiony bezpośrednio w środowisku systemu operacyjnego. ~Wikipedia nagłówek pliku ELF - nagłówek pliku efl przechowuje informacje o pliku taie jak: typ pliku (np. wykonywalny, lub relokowalny), wymagana architektura maszyny, czy właśnie punkt startowy programu ``` ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x40012a Start of program headers: 64 (bytes into file) Start of section headers: 400 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 3 Size of section headers: 64 (bytes) Number of section headers: 4 Section header string table index: 3 ``` z powyższego nagłówka możemy wyczytać, że entry point address to 0x40012a, czyli 27 linijka w poniższym kodzie. ```= main: file format elf64-x86-64 Disassembly of section .text: 00000000004000e8 <.text>: 4000e8: f3 0f 1e fa endbr64 4000ec: 48 85 ff test %rdi,%rdi 4000ef: 75 06 jne 0x4000f7 4000f1: b8 01 00 00 00 mov $0x1,%eax 4000f6: c3 retq 4000f7: 48 83 ec 08 sub $0x8,%rsp 4000fb: 48 83 ef 01 sub $0x1,%rdi 4000ff: e8 05 00 00 00 callq 0x400109 400104: 48 83 c4 08 add $0x8,%rsp 400108: c3 retq 400109: f3 0f 1e fa endbr64 40010d: 48 85 ff test %rdi,%rdi 400110: 75 06 jne 0x400118 400112: b8 00 00 00 00 mov $0x0,%eax 400117: c3 retq 400118: 48 83 ec 08 sub $0x8,%rsp 40011c: 48 83 ef 01 sub $0x1,%rdi 400120: e8 c3 ff ff ff callq 0x4000e8 400125: 48 83 c4 08 add $0x8,%rsp 400129: c3 retq 40012a: f3 0f 1e fa endbr64 40012e: 48 83 ec 08 sub $0x8,%rsp 400132: bf 2a 00 00 00 mov $0x2a,%edi 400137: e8 ac ff ff ff callq 0x4000e8 40013c: 89 c7 mov %eax,%edi 40013e: b8 3c 00 00 00 mov $0x3c,%eax 400143: 0f 05 syscall 400145: 48 83 c4 08 add $0x8,%rsp 400149: c3 retq ``` nagłówek programu - An executable or shared object file's program header table is an array of structures, each describing a segment or other information the system needs to prepare the program for execution. An object file segment contains one or more sections. ~man elf ``` Elf file type is EXEC (Executable file) Entry point 0x40012a There are 3 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x00000000000000e8 0x00000000004000e8 0x00000000004000e8 0x0000000000000062 0x0000000000000062 R E 0x1000 LOAD 0x00000000000000e8 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 R 0x1000 LOAD 0x00000000000000e8 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x1000 Section to Segment mapping: Segment Sections... 00 .text 01 02 ``` z powyższego nagłówka możemy wyczytać że adres pod który zostanie wczytany segment z sekcją .text to 0x4000e8 skrypt konsolidatora - Every link is controlled by a linker script. This script is written in the linker command language. The main purpose of the linker script is to describe how the sections in the input files should be mapped into the output file, and to control the memory layout of the output file. Most linker scripts do nothing more than this. ~dokumentacja ```= OUTPUT_FORMAT("elf64-x86-64") OUTPUT_ARCH(i386:x86-64) ENTRY(_start) PHDRS { code PT_LOAD FLAGS(5); rodata PT_LOAD FLAGS(4); data PT_LOAD FLAGS(6); } SECTIONS { . = 0x400000 + SIZEOF_HEADERS; .text : { *(.text .text.*) } : code .rodata : { *(.rodata .rodata.*) } : rodata .data : { *(.data .data.*) } : data .bss : { *(.bss .bss.*) *(COMMON) } : data /DISCARD/ : { *(.note.gnu.property) } } ``` The SECTIONS command tells the linker how to map input sections into output sections, and how to place the output sections in memory. The format of the SECTIONS command is: SECTIONS { sections-command sections-command … } Each sections-command may of be one of the following: an ENTRY command (see Entry command) a symbol assignment (see Assignments) an output section description an overlay description ~dokumentacja ## Zadanie 7 :::success Autor: Franciszek Pindel ::: Wytłumacz uczestnikom zajęć składowe rekordów relokacji przechowywanych w sekcjach «.rel.text» i «.rel.data». Czy możliwe jest by asembler utworzył sekcję «.rel.bss»? Czym się różnią relokacje typu «R_X86_64_PC32» od «R_X86_64_32»? Na podstawie podręcznika zreferuj algorytm relokowania odwołań do symboli. ```c= typedef struct { long offset; /* offset od początku sekcji */ long type:32, /* typ relokacji: względna/bezwzględna */ symbol:32; /* adres do tablicy symboli */ long addend; /* dopełnienie do kolejnej instrukcji */ } Elf64_Rela; ``` Nie ma sensu tworzyć sekcji .re.bss, ponieważ w bss znajdują się symbole zmiennych niezainicjowanych statycznych oraz globalnych lub statycznych zainicjalizowanych na zero. Konsolidator zna już adres symboli do których nastąpi odwołanie, dlatego relokacja jest niepotrzebna ``` foreach section s { foreach relocation entry r { refptr = s + r.offset; /* ptr to reference to be relocated */ /* Relocate a PC-relative reference */ if (r.type == R_X86_64_PC32) { refaddr = ADDR(s) + r.offset; /* ref's run-time address */ *refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr); } /* Relocate an absolute reference */ if (r.type == R_X86_64_32) *refptr = (unsigned) (ADDR(r.symbol) + r.addend); } } ``` Przykład: ``` 0000000000000000 <main>: 2 0: 4883ec08 sub $0x8, %rsp 3 4: be 02 00 00 00 mov $0x2, %esi 4 9: bf 00 00 00 00 mov $0x0, %edi %edi = &array 5 a: R_X86_64_32 array Relocation entry 6 e: e8 00 00 00 00 callq 13 <main+0x13> sum() 7 f: R_X86_64_PC32 sum-0x4 Relocation entry 8 13: 4883c408 add $0x8, %rsp 9 17:c3 retq ``` ``` r.offset = 0xf r.symbol = sum r.type = R_X86_64_PC32 r.addend = -4 ``` ``` ADDR(s) = ADDR(.text) = 0x4004d0 ``` ``` ADDR(r.symbol) = ADDR(sum) = 0x4004e8 ``` ``` refaddr = ADDR(s) + r.offset = 0x4004d0 + 0xf = 0x4004df ``` ``` *refptr = (unsigned) (ADDR(r.symbol) + r.addend - refaddr) = (unsigned) (0x4004e8 + (-4) - 0x4004df) = (unsigned) (0x5) ``` ## Zadanie 8 :::danger Autor: :::