Wiki
Clone wikichocos / ELF - assembler
Użyłem przykładowego exampla dla STM32G431KBTX z STM32Cube IDE. Kod:
extern int externalVal1, externalVal2, externalVal3; int externalFunc1(){ return externalVal1; }; int externalFunc2(){ return externalVal2; }; int externalFunc3(){ return externalVal3; }; int externalFunc4(){ return externalVal1; };
externalFunc1
i externalFunc4
zwracają tę samą zmienną.
Przy włączonej optymalizacji -O1
Bez flagi -fpic
080002ac <externalFunc1>: 80002ac: 4b01 ldr r3, [pc, #4] ; (80002b4 <externalFunc1+0x8>) -> Załaduj do rejestru R3 0x20000008 (bezwzględny adres zmiennej externalVar1) 80002ae: 6818 ldr r0, [r3, #0] ; Załaduj do rejestru R0 wartość spod adresu R3, czyli wartość externalVar1 80002b0: 4770 bx lr 80002b2: bf00 nop 80002b4: 20000008 .word 0x20000008 080002b8 <externalFunc2>: 80002b8: 4b01 ldr r3, [pc, #4] ; (80002c0 <externalFunc2+0x8>) 80002ba: 6818 ldr r0, [r3, #0] 80002bc: 4770 bx lr 80002be: bf00 nop 80002c0: 2000000c .word 0x2000000c 080002c4 <externalFunc3>: 80002c4: 4b01 ldr r3, [pc, #4] ; (80002cc <externalFunc3+0x8>) 80002c6: 6818 ldr r0, [r3, #0] 80002c8: 4770 bx lr 80002ca: bf00 nop 80002cc: 20000010 .word 0x20000010 080002d0 <externalFunc4>: 80002d0: 4b01 ldr r3, [pc, #4] ; (80002d8 <externalFunc4+0x8>) 80002d2: 6818 ldr r0, [r3, #0] 80002d4: 4770 bx lr 80002d6: bf00 nop 80002d8: 20000008 .word 0x20000008
externalFunc1
i externalFunc4
jest taki sam, ponieważ obie te funkcje odwołują się bezpośrednio do adresu zmiennej externalVar1
Wynik komendy readelf -e Led_Jumper.elf
(brak sekcji .got i .got.plt):
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .isr_vector PROGBITS 08000000 010000 0001d8 00 A 0 0 1 [ 2] .text PROGBITS 080001d8 0101d8 0001d4 00 AX 0 0 4 [ 3] .rodata PROGBITS 080003ac 020014 000000 00 WA 0 0 1 [ 4] .ARM.extab PROGBITS 080003ac 020014 000000 00 W 0 0 1 [ 5] .ARM PROGBITS 080003ac 020014 000000 00 W 0 0 1 [ 6] .preinit_array PREINIT_ARRAY 080003ac 020014 000000 04 WA 0 0 1 [ 7] .init_array INIT_ARRAY 080003ac 0103ac 000004 04 WA 0 0 4 [ 8] .fini_array FINI_ARRAY 080003b0 0103b0 000004 04 WA 0 0 4 [ 9] .data PROGBITS 20000000 020000 000014 00 WA 0 0 4 [10] .bss NOBITS 20000014 020014 000020 00 WA 0 0 4 [11] ._user_heap_stack NOBITS 20000034 020034 000604 00 WA 0 0 1 [12] .ARM.attributes ARM_ATTRIBUTES 00000000 020014 000030 00 0 0 1 [13] .comment PROGBITS 00000000 020044 000043 01 MS 0 0 1 [14] .debug_line PROGBITS 00000000 020087 00007b 00 0 0 1 [15] .debug_line_str PROGBITS 00000000 020102 000074 01 MS 0 0 1 [16] .debug_info PROGBITS 00000000 020176 000023 00 0 0 1 [17] .debug_abbrev PROGBITS 00000000 020199 000012 00 0 0 1 [18] .debug_aranges PROGBITS 00000000 0201b0 000028 00 0 0 8 [19] .debug_str PROGBITS 00000000 0201d8 000080 01 MS 0 0 1 [20] .debug_rnglists PROGBITS 00000000 020258 000019 00 0 0 1 [21] .debug_frame PROGBITS 00000000 020274 00002c 00 0 0 4 [22] .symtab SYMTAB 00000000 0202a0 000de0 10 23 104 4 [23] .strtab STRTAB 00000000 021080 000971 00 0 0 1 [24] .shstrtab STRTAB 00000000 0219f1 00010f 00 0 0 1
Z flagą -fpic
080002c0 <externalFunc1>: 80002c0: 4b02 ldr r3, [pc, #8] ; (80002cc <externalFunc1+0xc>) -> załaduj do rejestru R3 wartość 17fffd4e 80002c2: 447b add r3, pc ; dodaj do wartości z rejestru R3 program counter -> w tym momencie w R3 jest adres tablicy got 80002c4: 4a02 ldr r2, [pc, #8] ; (80002d0 <externalFunc1+0x10>) -> do rejestru R2 załaduj "0x10" (jest to offset zmiennej externVar1 z tablicy got) 80002c6: 589b ldr r3, [r3, r2] ; W R3 znajduje się adres got, w r2 offset do zmiennej w tablicy got. Ta instrukcja ładuje do rejestru R3 wartość z tablicy got (R3) z offsetem (R2). Po tej operacji w R3 znajduje się wartość z tablicy got, czyli adres zmiennej externVar1 80002c8: 6818 ldr r0, [r3, #0] ; Załaduj wartość spod adresu w R3 do rejestru R0 80002ca: 4770 bx lr 80002cc: 17fffd4e .word 0x17fffd4e 80002d0: 00000010 .word 0x00000010 080002d4 <externalFunc2>: 80002d4: 4b02 ldr r3, [pc, #8] ; (80002e0 <externalFunc2+0xc>) 80002d6: 447b add r3, pc 80002d8: 4a02 ldr r2, [pc, #8] ; (80002e4 <externalFunc2+0x10>) 80002da: 589b ldr r3, [r3, r2] 80002dc: 6818 ldr r0, [r3, #0] 80002de: 4770 bx lr 80002e0: 17fffd3a .word 0x17fffd3a 80002e4: 00000014 .word 0x00000014 080002e8 <externalFunc3>: 80002e8: 4b02 ldr r3, [pc, #8] ; (80002f4 <externalFunc3+0xc>) 80002ea: 447b add r3, pc 80002ec: 4a02 ldr r2, [pc, #8] ; (80002f8 <externalFunc3+0x10>) 80002ee: 589b ldr r3, [r3, r2] 80002f0: 6818 ldr r0, [r3, #0] 80002f2: 4770 bx lr 80002f4: 17fffd26 .word 0x17fffd26 80002f8: 00000000 .word 0x00000000 080002fc <externalFunc4>: 80002fc: 4b02 ldr r3, [pc, #8] ; (8000308 <externalFunc4+0xc>) 80002fe: 447b add r3, pc 8000300: 4a02 ldr r2, [pc, #8] ; (800030c <externalFunc4+0x10>) 8000302: 589b ldr r3, [r3, r2] 8000304: 6818 ldr r0, [r3, #0] 8000306: 4770 bx lr 8000308: 17fffd12 .word 0x17fffd12 800030c: 00000010 .word 0x00000010
Wynik komendy readelf -e Led_Jumper.elf
(2 nowe sekcje [10] i [11]):
Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .isr_vector PROGBITS 08000000 010000 0001d8 00 A 0 0 1 [ 2] .text PROGBITS 080001d8 0101d8 000208 00 AX 0 0 4 [ 3] .rodata PROGBITS 080003e0 020038 000000 00 WA 0 0 1 [ 4] .ARM.extab PROGBITS 080003e0 020038 000000 00 W 0 0 1 [ 5] .ARM PROGBITS 080003e0 020038 000000 00 W 0 0 1 [ 6] .preinit_array PREINIT_ARRAY 080003e0 020038 000000 04 WA 0 0 1 [ 7] .init_array INIT_ARRAY 080003e0 0103e0 000004 04 WA 0 0 4 [ 8] .fini_array FINI_ARRAY 080003e4 0103e4 000004 04 WA 0 0 4 [ 9] .data PROGBITS 20000000 020000 000014 00 WA 0 0 4 [10] .got PROGBITS 20000014 020014 000018 00 WA 0 0 4 [11] .got.plt PROGBITS 2000002c 02002c 00000c 04 WA 0 0 4 [12] .bss NOBITS 20000038 020038 000020 00 WA 0 0 4 [13] ._user_heap_stack NOBITS 20000058 020058 000600 00 WA 0 0 1 [14] .ARM.attributes ARM_ATTRIBUTES 00000000 020038 000030 00 0 0 1 [15] .comment PROGBITS 00000000 020068 000043 01 MS 0 0 1 [16] .debug_line PROGBITS 00000000 0200ab 00007b 00 0 0 1 [17] .debug_line_str PROGBITS 00000000 020126 000074 01 MS 0 0 1 [18] .debug_info PROGBITS 00000000 02019a 000023 00 0 0 1 [19] .debug_abbrev PROGBITS 00000000 0201bd 000012 00 0 0 1 [20] .debug_aranges PROGBITS 00000000 0201d0 000028 00 0 0 8 [21] .debug_str PROGBITS 00000000 0201f8 000080 01 MS 0 0 1 [22] .debug_rnglists PROGBITS 00000000 020278 000019 00 0 0 1 [23] .debug_frame PROGBITS 00000000 020294 00002c 00 0 0 4 [24] .symtab SYMTAB 00000000 0202c0 000e10 10 25 107 4 [25] .strtab STRTAB 00000000 0210d0 000987 00 0 0 1 [26] .shstrtab STRTAB 00000000 021a57 00011d 00 0 0 1
Przy włączonej optymalizacji -O3
Bez flagi -fpic
Kod jest identyczny, jak w przypadku optymalizacji -O1
Z flagą -fpic
Wszystkie funkcje wyglądają analogicznie do poniższej. Zajmuje ona tyle samo miejsca, co ta z optymalizacją -O1, tylko instrukcja 2. i 3. są zamienione miejscami:
080002c0 <externalFunc1>: 80002c0: 4b02 ldr r3, [pc, #8] ; (80002cc <externalFunc1+0xc>) 80002c2: 4a03 ldr r2, [pc, #12] ; (80002d0 <externalFunc1+0x10>) 80002c4: 447b add r3, pc 80002c6: 589b ldr r3, [r3, r2] 80002c8: 6818 ldr r0, [r3, #0] 80002ca: 4770 bx lr 80002cc: 17fffd4c .word 0x17fffd4c 80002d0: 00000010 .word 0x00000010
-fpic + O1 + adresy sekcji linkera na 0
000002ac <externalFunc>: 2ac: 4b02 ldr r3, [pc, #8] ; (2b8 <externalFunc+0xc>) 2ae: 447b add r3, pc 2b0: 4a02 ldr r2, [pc, #8] ; (2bc <externalFunc+0x10>) 2b2: 589b ldr r3, [r3, r2] 2b4: 6818 ldr r0, [r3, #0] 2b6: 4770 bx lr 2b8: 0000014a .word 0x0000014a 2bc: 0000000c .word 0x0000000c 000002c0 <externalFunc1>: 2c0: 4b02 ldr r3, [pc, #8] ; (2cc <externalFunc1+0xc>) 2c2: 447b add r3, pc 2c4: 4a02 ldr r2, [pc, #8] ; (2d0 <externalFunc1+0x10>) 2c6: 589b ldr r3, [r3, r2] 2c8: 6818 ldr r0, [r3, #0] 2ca: 4770 bx lr 2cc: 00000136 .word 0x00000136 2d0: 00000010 .word 0x00000010 000002d4 <externalFunc2>: 2d4: 4b02 ldr r3, [pc, #8] ; (2e0 <externalFunc2+0xc>) 2d6: 447b add r3, pc 2d8: 4a02 ldr r2, [pc, #8] ; (2e4 <externalFunc2+0x10>) 2da: 589b ldr r3, [r3, r2] 2dc: 6818 ldr r0, [r3, #0] 2de: 4770 bx lr 2e0: 00000122 .word 0x00000122 2e4: 00000014 .word 0x00000014 000002e8 <externalFunc3>: 2e8: 4b02 ldr r3, [pc, #8] ; (2f4 <externalFunc3+0xc>) 2ea: 447b add r3, pc 2ec: 4a02 ldr r2, [pc, #8] ; (2f8 <externalFunc3+0x10>) 2ee: 589b ldr r3, [r3, r2] 2f0: 6818 ldr r0, [r3, #0] 2f2: 4770 bx lr 2f4: 0000010e .word 0x0000010e 2f8: 00000000 .word 0x00000000 000002fc <externalFunc4>: 2fc: 4b02 ldr r3, [pc, #8] ; (308 <externalFunc4+0xc>) 2fe: 447b add r3, pc 300: 4a02 ldr r2, [pc, #8] ; (30c <externalFunc4+0x10>) 302: 589b ldr r3, [r3, r2] 304: 6818 ldr r0, [r3, #0] 306: 4770 bx lr 308: 000000fa .word 0x000000fa 30c: 00000010 .word 0x00000010
Komentarz: kod jest identyczny, tylko adresy się zmieniły.
-fpic + O1 + adresy sekcji linkera na 0 + -msingle-pic-base
Zakłada, że w rejestrze R9 znajduje się adres GOT. R9 musi być zainicjalizowane przez system. Można zdefiniować inny rejestr za pomocą flagi kmpilatora: -mpic-register=reg
000002b8 <externalFunc1>: 2b8: 4b02 ldr r3, [pc, #8] ; (2c4 <externalFunc1+0xc>) 2ba: f859 3003 ldr.w r3, [r9, r3] 2be: 6818 ldr r0, [r3, #0] 2c0: 4770 bx lr 2c2: bf00 nop 2c4: 00000010 .word 0x00000010 000002c8 <externalFunc2>: 2c8: 4b02 ldr r3, [pc, #8] ; (2d4 <externalFunc2+0xc>) 2ca: f859 3003 ldr.w r3, [r9, r3] 2ce: 6818 ldr r0, [r3, #0] 2d0: 4770 bx lr 2d2: bf00 nop 2d4: 00000014 .word 0x00000014 000002d8 <externalFunc3>: 2d8: 4b02 ldr r3, [pc, #8] ; (2e4 <externalFunc3+0xc>) 2da: f859 3003 ldr.w r3, [r9, r3] 2de: 6818 ldr r0, [r3, #0] 2e0: 4770 bx lr 2e2: bf00 nop 2e4: 00000000 .word 0x00000000 000002e8 <externalFunc4>: 2e8: 4b02 ldr r3, [pc, #8] ; (2f4 <externalFunc4+0xc>) 2ea: f859 3003 ldr.w r3, [r9, r3] 2ee: 6818 ldr r0, [r3, #0] 2f0: 4770 bx lr 2f2: bf00 nop 2f4: 00000010 .word 0x00000010
Updated