tock / libtock-rs

Rust userland library for Tock
Apache License 2.0
168 stars 109 forks source link

build_scripts/layout.ld: add a relro section #526

Closed twilfredo closed 11 months ago

twilfredo commented 11 months ago

Context: I encountered this issue when linking mbedtls to a libtock-rs app.

This accommodates situations for example: where global variables are initialized to a value that requires relocation. Things like globally stored function pointers, or storing the address of another global variable. Such items require runtime initialization in the form of dynamic relocation, and cannot be placed in a RO segment. However, as it is declared to be a constant (not modified by the program), the dynamic linker can mark it as RO after the dynamic relocation as been applied [1].

When GCC sees a variable which is constant but requires dynamic relocation, it puts it into a section named .data.rel.ro, further, a variable that requires dynamic relocation against a local symbol is put into a .data.rel.ro.local section, this helps group such variables together so that the dynamic linker may apply the relocations, which will always be RELATIVE locations [1].

[1] https://www.airs.com/blog/archives/189

jrvanwhy commented 11 months ago

I want to make sure I'm understanding this correctly. When you build mbedtls, GCC generates a .data.rel.ro section, which is then relocated when mbedtls is linked into the app binary, correct? I'm seeing a bit of a mismatch between that model (in which .data.rel.ro is relocated when the app is statically linked) and the PR description/blog post, which indicate that .data.rel.ro is dynamically relocated.

twilfredo commented 11 months ago

I want to make sure I'm understanding this correctly. When you build mbedtls, GCC generates a .data.rel.ro section, which is then relocated when mbedtls is linked into the app binary, correct? I'm seeing a bit of a mismatch between that model (in which .data.rel.ro is relocated when the app is statically linked) and the PR description/blog post, which indicate that .data.rel.ro is dynamically relocated.

mbetls creates the following sections (and some more of the same type), this is from one of the mbedtls libraries:

Relocation section '.rel.data.rel.ro.local.ecp_x25519_bad_point_2' at offset 0x5200 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
00000008  0000c502 R_ARM_ABS32       00000000   .rodata.x25519_ba[...]

Relocation section '.rel.data.rel.ro.local.ecp_x25519_bad_point_1' at offset 0x5208 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
00000008  0000c702 R_ARM_ABS32       00000000   .rodata.x25519_ba[...]

When linking the static library to our libtock-rs app (without the changes in this PR), I see the following in the elf output :

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .start            PROGBITS        00040080 001080 000074 00  AX  0   0  1
  [ 2] .text             PROGBITS        000400f4 0010f4 01defc 00  AX  0   0  8
  [ 3] .rodata           PROGBITS        0005dff0 01eff0 003432 00 AMS  0   0  8
  [ 4] .stack            NOBITS          20008000 023000 004000 00  WA  0   0  1
  [ 5] .data             PROGBITS        2000c000 027000 000268 00  WA  0   0  4
  [ 6] .data..L_Mer[...] PROGBITS        2000c268 027268 00001d 00  WA  0   0  2
  [ 7] .data.rel.ro[...] PROGBITS        2000c288 027288 0001d0 00  WA  0   0  4
  [ 8] .data.rel.ro[...] PROGBITS        2000c458 027458 00000c 00  WA  0   0  4
...
  [36] .data.rel.ro[...] PROGBITS        2000c95c 02795c 00001c 00  WA  0   0  4
  [37] .data.rel.ro[...] PROGBITS        2000c978 027978 00001c 00  WA  0   0  4

...
...
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001080 0x00040080 0x00040080 0x1df70 0x1df70 R E 0x1000
  LOAD           0x01eff0 0x0005dff0 0x0005dff0 0x03432 0x03432 R   0x1000
  LOAD           0x023000 0x20008000 0x00061422 0x04268 0x04268 RW  0x1000
  LOAD           0x027268 0x2000c268 0x2000c268 0x0072c 0x0072c RW  0x1000
  LOAD           0x027994 0x2000c994 0x0006568c 0x00000 0x0266c RW  0x1000
  LOAD           0x028000 0x2000f000 0x2000f000 0x0004c 0x0004c RW  0x1000  <--- [comment: this shouldn't be here]
  GNU_RELRO      0x028000 0x2000f000 0x2000f000 0x0004c 0x01000 R   0x1
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

This is built for the nrf52840, so .data.rel.ro has a RAM Addr here. When elf2tab is used to create the app.tab it runs into this issue https://github.com/tock/elf2tab/issues/83 (between addrs for this case 0x0006568c-0x2000f000), and outputs a TAB of 512MB!.

With the changes in the PR we see the following in the elf:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .start            PROGBITS        00040080 001080 000074 00  AX  0   0  1
  [ 2] .text             PROGBITS        000400f4 0010f4 01defc 00  AX  0   0  8
  [ 3] .rodata           PROGBITS        0005dff0 01eff0 003432 00 AMS  0   0  8
  [ 4] ..data.rel.r[...] PROGBITS        00061424 022424 000708 00  WA  0   0  4
  [ 5] .data..L_Mer[...] PROGBITS        00061b2c 022b2c 00001d 00  WA  0   0  2
  [ 6] .data.one.0       PROGBITS        00061b4c 022b4c 000004 00  WA  0   0  4
  [ 7] .got              PROGBITS        00061b50 022b50 00004c 00  WA  0   0  4
  [ 8] .stack            NOBITS          20010000 023000 004000 00  WA  0   0  1
  [ 9] .data             PROGBITS        20014000 027000 000268 00  WA  0   0  4
  [10] .bss              NOBITS          20014268 027268 00266c 00  WA  0   0  4
...
...
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001080 0x00040080 0x00040080 0x1df70 0x1df70 R E 0x1000
  LOAD           0x01eff0 0x0005dff0 0x0005dff0 0x03432 0x03432 R   0x1000
  LOAD           0x022424 0x00061424 0x00061424 0x00778 0x00778 RW  0x1000
  LOAD           0x023000 0x20010000 0x00061b9c 0x04268 0x068d4 RW  0x1000
  GNU_RELRO      0x022b50 0x00061b50 0x00061b50 0x0004c 0x004b0 R   0x1
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0

and we can compile and run the app without the issue from the prior case. So my thinking was that adding a .data.rel.ro.local allows the respective data be put in the 'correct' place at link time. But it's kind of beyond my understanding. Perhaps you have a better idea of what is happening?

jrvanwhy commented 11 months ago

Okay, sounds reasonable to me.