This PR fixes an issue where some specific ELF configurations will sigsegv on the first instruction when run in blink, only when blink is compiled with threads disabled
It also fixes an issue where the stack in an ELF is not set as executable when explicitly defined as such via flags in PT_GNU_STACK. This is based on the current behaviour of the linux kernel ,
But i'm not sure if it is proper behaviour for the blink project.
A minimal reproducible example of a faulting program is this:
as example.s -o example.o
ld example.o --no-dynamic-linker
readelf -Wa
```
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x401000
Start of program headers: 64 (bytes into file)
Start of section headers: 4304 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 5
Section header string table index: 4
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000401000 001000 000014 00 AX 0 0 1
[ 2] .symtab SYMTAB 0000000000000000 001018 000078 18 3 1 8
[ 3] .strtab STRTAB 0000000000000000 001090 000019 00 0 0 1
[ 4] .shstrtab STRTAB 0000000000000000 0010a9 000021 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0000b0 0x0000b0 R 0x1000
LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x000014 0x000014 R E 0x1000
Section to Segment mapping:
Segment Sections...
00
01 .text
There is no dynamic section in this file.
There are no relocations in this file.
No processor specific unwind information to decode
Symbol table '.symtab' contains 5 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000401000 0 NOTYPE GLOBAL DEFAULT 1 _start
2: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 __bss_start
3: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 _edata
4: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 _end
```
The issue is that FindPageTableEntry is caching addresses with the wrong access levels
when it's called during the LoadProgram phase.
This is normally not a problem, because the tlb in that stage is always reset by subsequent calls to InvalidateSystem.
But when threads are disabled, that function is incorrectly optimized away
This screenshot shows the content of the tlb immediately before the first instruction is fetched:
the highlighted cached page entry incorrectly starts with 0x8
This PR fixes an issue where some specific ELF configurations will sigsegv on the first instruction when run in blink, only when blink is compiled with threads disabled
It also fixes an issue where the stack in an ELF is not set as executable when explicitly defined as such via flags in
PT_GNU_STACK
. This is based on the current behaviour of the linux kernel , But i'm not sure if it is proper behaviour for the blink project.A minimal reproducible example of a faulting program is this:
example.s
compiled with:
readelf -Wa
``` ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: Advanced Micro Devices X86-64 Version: 0x1 Entry point address: 0x401000 Start of program headers: 64 (bytes into file) Start of section headers: 4304 (bytes into file) Flags: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 2 Size of section headers: 64 (bytes) Number of section headers: 5 Section header string table index: 4 Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 0000000000401000 001000 000014 00 AX 0 0 1 [ 2] .symtab SYMTAB 0000000000000000 001018 000078 18 3 1 8 [ 3] .strtab STRTAB 0000000000000000 001090 000019 00 0 0 1 [ 4] .shstrtab STRTAB 0000000000000000 0010a9 000021 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), l (large), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0000b0 0x0000b0 R 0x1000 LOAD 0x001000 0x0000000000401000 0x0000000000401000 0x000014 0x000014 R E 0x1000 Section to Segment mapping: Segment Sections... 00 01 .text There is no dynamic section in this file. There are no relocations in this file. No processor specific unwind information to decode Symbol table '.symtab' contains 5 entries: Num: Value Size Type Bind Vis Ndx Name 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 1: 0000000000401000 0 NOTYPE GLOBAL DEFAULT 1 _start 2: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 __bss_start 3: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 _edata 4: 0000000000402000 0 NOTYPE GLOBAL DEFAULT 1 _end ```The issue is that
FindPageTableEntry
is caching addresses with the wrong access levels when it's called during theLoadProgram
phase. This is normally not a problem, because the tlb in that stage is always reset by subsequent calls toInvalidateSystem
. But when threads are disabled, that function is incorrectly optimized awayThis screenshot shows the content of the tlb immediately before the first instruction is fetched: the highlighted cached page entry incorrectly starts with
0x8