Wiki

Clone wiki

chocos / 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; };
Zwróc uwagę, że 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
Zwróć uwagę, że kod funkcji 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
Zauważ, że w każdej z tych funkcji adres ładowany do R3 na początku jest inny. Wynika to z tego, że każda funkcja ma inny pc, który jest dodawany w drugim kroku. Suma wartości z pc i rejestru R3 dla każdej z tych funkcji jest taka sama.

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