Skip to content

segments need to start with a section#74

Closed
bradjc wants to merge 1 commit intomasterfrom
segments-contain-sections
Closed

segments need to start with a section#74
bradjc wants to merge 1 commit intomasterfrom
segments-contain-sections

Conversation

@bradjc
Copy link
Copy Markdown
Contributor

@bradjc bradjc commented Jul 24, 2023

The linker can put additional data in a segment before a section, but that violates assumptions that our linker files are making. elf2tab requires that data exist within sections, and expects that segments start with sections.

Most of the time this requirement is upheld by the linker. However, in the case of apps with 0 stack, puts everything in the first page. This makes the segment start where a section does not.

This patch adds logic to check for this discrepancy and adjust the segment to remove this (essentially) padding at the beginning of the segment. The rest of elf2tab can then operate as expected.

Short term fix

The easy fix is to just not have apps with 0 stack. Without this PR or something else like it apps with 0 stack do not work with elf2tab and that is a known bug.

The linker can put additional data in a segment before a section, but
that violates assumptions that our linker files are making. elf2tab
requires that data exist within sections, and expects that segments
start with sections.

Most of the time this requirement is upheld by the linker. However, in
the case of VERY small apps, the linker tries to optimize by packing in
more in the first segment. This makes the segment start where a section
does not.

This patch adds logic to check for this discrepency and adjust the
segment to remove this (essentially) padding at the beginning of the
segment. The rest of elf2tab can then operate as expected.
@bradjc
Copy link
Copy Markdown
Contributor Author

bradjc commented Jul 24, 2023

With stack size set to 0, and therefore no .stack section, the output elf looks like:

readelf.py -lS build/rv32imac/rv32imac.0x20040080.0x80002800.elf
There are 22 section headers, starting at offset 0xf28

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .got              PROGBITS        80002800 000800 000000 00  WA  0   0  1
  [ 2] .crt0_header      PROGBITS        20040080 000080 000028 00   A  0   0  1
  [ 3] .data             PROGBITS        80002800 000800 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          80002800 000800 000000 00  WA  0   0  1
  [ 5] .GCC.command.line PROGBITS        00000000 000800 0000a4 01  MS  0   0  1
  [ 6] .comment          PROGBITS        00000000 0008a4 000012 01  MS  0   0  1
  [ 7] .riscv.attributes ARM_ATTRIBUTES  00000000 0008b6 00002b 00      0   0  1
  [ 8] .wfr.app_state    PROGBITS        200400a8 0008e1 000000 00   W  0   0  1
  [ 9] .text             PROGBITS        200400a8 0000a8 000008 00  AX  0   0  2
  [10] .stack            PROGBITS        80002800 0008e1 000000 00   W  0   0  1
  [11] .debug_info       PROGBITS        00000000 0008e1 000083 00      0   0  1
  [12] .debug_abbrev     PROGBITS        00000000 000964 00005b 00      0   0  1
  [13] .debug_loc        PROGBITS        00000000 0009bf 000042 00      0   0  1
  [14] .debug_aranges    PROGBITS        00000000 000a01 000020 00      0   0  1
  [15] .debug_ranges     PROGBITS        00000000 000a21 000010 00      0   0  1
  [16] .debug_line       PROGBITS        00000000 000a31 000041 00      0   0  1
  [17] .debug_str        PROGBITS        00000000 000a72 00011e 01  MS  0   0  1
  [18] .debug_frame      PROGBITS        00000000 000b90 000020 00      0   0  4
  [19] .symtab           SYMTAB          00000000 000bb0 000210 10     20  20  4
  [20] .strtab           STRTAB          00000000 000dc0 000081 00      0   0  1
  [21] .shstrtab         STRTAB          00000000 000e41 0000e7 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point is 0x200400a8
There are 2 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x20040000 0x20040000 0x000b0 0x000b0 R E 0x1000
  LOAD           0x000800 0x80002800 0x200400b0 0x00000 0x00000 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .crt0_header .text
   01

With stack size set to anything else, for example 1, the output elf looks like:

readelf.py -lS build/rv32imac/rv32imac.0x20040080.0x80002800.elf
There are 22 section headers, starting at offset 0x1f38

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .got              PROGBITS        80002810 001810 000000 00  WA  0   0  1
  [ 2] .crt0_header      PROGBITS        20040080 001080 000028 00   A  0   0  1
  [ 3] .data             PROGBITS        80002810 001810 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          80002810 001810 000000 00  WA  0   0  1
  [ 5] .GCC.command.line PROGBITS        00000000 001810 0000a4 01  MS  0   0  1
  [ 6] .comment          PROGBITS        00000000 0018b4 000012 01  MS  0   0  1
  [ 7] .riscv.attributes ARM_ATTRIBUTES  00000000 0018c6 00002b 00      0   0  1
  [ 8] .wfr.app_state    PROGBITS        200400a8 0018f1 000000 00   W  0   0  1
  [ 9] .text             PROGBITS        200400a8 0010a8 000008 00  AX  0   0  2
  [10] .stack            NOBITS          80002800 002800 000010 00  WA  0   0  1
  [11] .debug_info       PROGBITS        00000000 0018f1 000083 00      0   0  1
  [12] .debug_abbrev     PROGBITS        00000000 001974 00005b 00      0   0  1
  [13] .debug_loc        PROGBITS        00000000 0019cf 000042 00      0   0  1
  [14] .debug_aranges    PROGBITS        00000000 001a11 000020 00      0   0  1
  [15] .debug_ranges     PROGBITS        00000000 001a31 000010 00      0   0  1
  [16] .debug_line       PROGBITS        00000000 001a41 000041 00      0   0  1
  [17] .debug_str        PROGBITS        00000000 001a82 00011e 01  MS  0   0  1
  [18] .debug_frame      PROGBITS        00000000 001ba0 000020 00      0   0  4
  [19] .symtab           SYMTAB          00000000 001bc0 000210 10     20  20  4
  [20] .strtab           STRTAB          00000000 001dd0 000081 00      0   0  1
  [21] .shstrtab         STRTAB          00000000 001e51 0000e7 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point is 0x200400a8
There are 3 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001080 0x20040080 0x20040080 0x00030 0x00030 R E 0x1000
  LOAD           0x001810 0x80002810 0x200400b0 0x00000 0x00000 RW  0x1000
  LOAD           0x000800 0x80002800 0x80002800 0x00000 0x00010 RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00     .crt0_header .text
   01
   02     .stack

The major issue (with the stack=0 version) is this line:

  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x20040000 0x20040000 0x000b0 0x000b0 R E 0x1000

The segment is at address 0x20040000, NOT what we expect which is 0x20040080. For some reason the linker includes its own header in that segment (note the offset is 0x0).

When adding any stack, the linker does not put text/crt0 in that first 4k page, and everything is great.

@bradjc
Copy link
Copy Markdown
Contributor Author

bradjc commented Jul 24, 2023

I know I created this PR, but I'm not really sure how to handle this. What if the linker adds some padding at the start of a segment for some reason, and the binary relies on the section starting at that offset?

We're telling the linker something like this:

MEMORY {
    FLASH (rx) : ORIGIN = 0x20040080, LENGTH = PROG_LENGTH
    SRAM (RWX) : ORIGIN = 0x80002800, LENGTH = RAM_LENGTH
}

and yet its giving us a segment which starts before flash. So, that's a problem, and not clear why it's our fault.

This might be the signal that, despite all my effort, we cannot really make elf2tab too agnostic to whether the app is fixed address or not. Because if elf2tab knew that the linker was trying to put content before the start of flash, then it can just ignore that portion, which would fix this issue. We also maybe can't assume that the linker will respect the start of flash.

So maybe the key is to also pass _flash_origin as a symbol (in addition to _sram_origin) and that would allow elf2tab to verify that its not trying to put something before the start of flash.

@bradjc
Copy link
Copy Markdown
Contributor Author

bradjc commented Aug 1, 2023

I'm leaning towards closing this in favor of #75

@bradjc bradjc closed this Aug 7, 2023
@bradjc bradjc deleted the segments-contain-sections branch August 29, 2023 02:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant