8.3.1. SysV symbol preemption example

Example 8.1. shared.c

int x = 1;

void multiply(void)
{
    x = x * x;
}

__attribute__((visibility("protected"))) void increment(void)
{
    x++;
}

void bar(void)
{
    increment();
    multiply();
}

In Example 8.1 there are three functions in the shared object: bar, multiply and increment. Both bar and multiply are given STV_DEFAULT visibility (the default for SysV). However, increment has been given STV_PROTECTED visibility.

Example 8.2. Sample output from fromelf -csry shared.so

**  Section #10 '.plt' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
    Size   : 64 bytes (alignment 4)
    Address: 0x000003B4

    $a
        0x000003B4:    E52DE004    ..-.    PUSH     {lr}
        0x000003B8:    E28FEC82    ....    ADR      lr,{pc}+0x8208 ; 0x85C0
        0x000003BC:    E28EE078    x...    ADD      lr,lr,#0x78
        0x000003C0:    E5BEF000    ....    LDR      pc,[lr,#0]!
    $t
        0x000003C4:    4778        xG      BX       pc
        0x000003C6:    46C0        .F      MOV      r8,r8
    $a
    [Anonymous symbol #31]
        0x000003C8:    E28FCC82    ....    ADR      r12,{pc}+0x8208 ; 0x85D0
        0x000003CC:    E28CC06C    l...    ADD      r12,r12,#0x6C
        0x000003D0:    E5BCF000    ....    LDR      pc,[r12,#0]!
    $t
        0x000003D4:    4778        xG      BX       pc
        0x000003D6:    46C0        .F      MOV      r8,r8
    $a
    [Anonymous symbol #32]
        0x000003D8:    E28FCC82    ....    ADR      r12,{pc}+0x8208 ; 0x85E0
        0x000003DC:    E28CC060    `...    ADD      r12,r12,#0x60
        0x000003E0:    E5BCF000    ....    LDR      pc,[r12,#0]!
    $t
        0x000003E4:    4778        xG      BX       pc
        0x000003E6:    46C0        .F      MOV      r8,r8
    $a
    [Anonymous symbol #33]
        0x000003E8:    E28FCC82    ....    ADR      r12,{pc}+0x8208 ; 0x85F0
        0x000003EC:    E28CC054    T...    ADD      r12,r12,#0x54
        0x000003F0:    E5BCF000    ....    LDR      pc,[r12,#0]!

**  Section #11 '.text' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
    Size   : 272 bytes (alignment 4)
    Address: 0x000003F4

$a
    [Anonymous symbol #23]
    multiply
        0x000003F4:    E59F1038    8...    LDR      r1,[pc,#56] ; [0x434] = 0x8248
        0x000003F8:    E79F1001    ....    LDR      r1,[pc,r1]
        0x000003FC:    E5910000    ....    LDR      r0,[r1,#0]
        0x00000400:    E0020090    ....    MUL      r2,r0,r0
        0x00000404:    E5812000    . ..    STR      r2,[r1,#0]
        0x00000408:    E12FFF1E    ../.    BX       lr
    increment
        0x0000040C:    E59F0024    $...    LDR      r0,[pc,#36] ; [0x438] = 0x8230
        0x00000410:    E79F0000    ....    LDR      r0,[pc,r0]
        0x00000414:    E5901000    ....    LDR      r1,[r0,#0]
        0x00000418:    E2811001    ....    ADD      r1,r1,#1
        0x0000041C:    E5801000    ....    STR      r1,[r0,#0]
        0x00000420:    E12FFF1E    ../.    BX       lr
    bar
        0x00000424:    E92D4010    .@-.    PUSH     {r4,lr}
        0x00000428:    EBFFFFF7    ....    BL       increment ; 0x40C
        0x0000042C:    EBFFFFE5    ....    BL       0x3C8 ; 0x3C8
        0x00000430:    E8BD8010    ....    POP      {r4,pc}
    $d
        0x00000434:    00008248    H...    DCD    33352
        0x00000438:    00008230    0...    DCD    33328
:
:
:

**  Section #19 '.got' (SHT_PROGBITS) [SHF_ALLOC + SHF_WRITE]
    Size   : 40 bytes (alignment 4)
    Address: 0x00008630

    0x008630:   48 85 00 00 00 00 00 00 00 00 00 00 B4 03 00 00    
    0x008640:   B4 03 00 00 B4 03 00 00 00 00 00 00 00 00 00 00    
    0x008650:   00 00 00 00 00 00 00 00

There are two function calls in the bar function. The first call is to the increment function using a standard branch with link (BL) instruction. This is because the increment symbol cannot be preempted. The second call to the multiply function, which can be preempted, uses a three step indirect PLT sequence.


  1. Branch with link to address 0x3C8 of the .plt section (the PLT entry for the multiply function).

  2. Load into register R12 address 0x863C from the .got section (0x85D0 + 0x6C), which is the address of the PLTGOT entry for the multiply function.

  3. Load into the program counter the address of the multiply function from the PLTGOT data entry at address 0x863C.[5].

The call to a non-preemptive, STV_PROTECTED symbol such as increment has the advantage of being faster because only a single branch instruction is required. It also means that the reference can be resolved at static link time, which also speeds-up and simplifies the dynamic linking step. However, unlike the call to a non-preemptive function, a call to a preemptive function always uses a PLT entry.

Because Example 8.1 is targeted for ARM Linux, the PLT entries are also indirect. Also, note that unlike the example in Indirect PLTs, where no GOT is generated by the static linker because the BPABI linking model is used, a .got section is generated by the static linker when targeting the SysV ARM Linux model.

Note

Preemption is related to function calls only. Data accesses to symbols given STV_PROTECTED visibility are reached using a GOT entry.

Note

In the BPABI model, symbol preemption is optional. See the BPABI for the ARM Architecture document for details.



[5] This address must be resolved by the dynamic linker, which in Example 8.1 is the ARM Linux kernel.

Copyright © 2010 ARM. All rights reserved.ARM DAI 0242A
Non-ConfidentialID011411