Some ELF files produced by lld may have zero-size segment placeholders as shown below.
Since GNU_STACK Offset is 0, the current code makes it the lowest used offset, and relocates all the segments over the ELF header. The resulting binary is total garbage.
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x001000 0xc0000000 0x10000000 0x48000 0x48000 R E 0x1000 LOAD 0x04c000 0xc0048000 0x10048000 0x155e0 0x67000 RW 0x4000 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x0 Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS c0000000 001000 01e7d4 00 AX 0 0 4 [ 2] .vector_table PROGBITS c001e7d4 01f7d4 000038 00 A 0 0 4 [ 3] .rodata PROGBITS c001e80c 01f80c 0297f4 00 AMS 0 0 4 [ 4] .data PROGBITS c0048000 04c000 0155e0 00 WA 0 0 16384 [ 5] .bss NOBITS c0060000 0615e0 04f000 00 WA 0 0 16384 [ 6] .ARM.attributes ARM_ATTRIBUTES 00000000 0615e0 00002f 00 0 0 1 [ 7] .debug_line PROGBITS 00000000 06160f 015219 00 0 0 1 [ 8] .debug_info PROGBITS 00000000 076828 01e940 00 0 0 1 [ 9] .debug_abbrev PROGBITS 00000000 095168 00435f 00 0 0 1 [10] .debug_aranges PROGBITS 00000000 0994c7 0000e8 00 0 0 1 [11] .debug_str PROGBITS 00000000 0995af 008095 01 MS 0 0 1 [12] .debug_ranges PROGBITS 00000000 0a1644 0000a0 00 0 0 1 [13] .debug_macinfo PROGBITS 00000000 0a16e4 00003a 00 0 0 1 [14] .debug_pubnames PROGBITS 00000000 0a171e 004fc6 00 0 0 1 [15] .debug_pubtypes PROGBITS 00000000 0a66e4 007099 00 0 0 1 [16] .comment PROGBITS 00000000 0ad77d 000045 01 MS 0 0 1 [17] .debug_frame PROGBITS 00000000 0ad7c4 004740 00 0 0 4 [18] .debug_loc PROGBITS 00000000 0b1f04 000522 00 0 0 1 [19] .symtab SYMTAB 00000000 0b2428 003a50 10 21 469 4 [20] .shstrtab STRTAB 00000000 0b5e78 0000f0 00 0 0 1 [21] .strtab STRTAB 00000000 0b5f68 004252 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), l (large) I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific)
I made an assumption here about where the program headers would actually go that was wrong. Instead of sizeof(Elf_Ehdr) this needs to be derived from ProgramHdrSegment to get the correct offset.