authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-10 00:10:17-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-11-10 00:10:17-05:00
logf3309a96a7d8061f944590577c2b6c58e4cf6637
treebf0e1ea69f9a088f590316fc13c74ec22aef32ce
parentbdbfc7de3fd3a05f338ec8beaa29894547a9df4c
parent57889cae80310fa774b181ea9d0a8543f8437df7
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #25819 from jacobly0/elfv2-emit-obj


10 files changed, 977 insertions(+), 580 deletions(-)

lib/std/c.zig+3-3
......@@ -3971,7 +3971,7 @@ pub const dl_phdr_info = switch (native_os) {
39713971 /// Module name.
39723972 name: ?[*:0]const u8,
39733973 /// Pointer to module's phdr.
3974 phdr: [*]std.elf.Phdr,
3974 phdr: [*]std.elf.ElfN.Phdr,
39753975 /// Number of entries in phdr.
39763976 phnum: u16,
39773977 /// Total number of loads.
......@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {
39843984 .illumos => extern struct {
39853985 addr: std.elf.Addr,
39863986 name: ?[*:0]const u8,
3987 phdr: [*]std.elf.Phdr,
3987 phdr: [*]std.elf.ElfN.Phdr,
39883988 phnum: std.elf.Half,
39893989 /// Incremented when a new object is mapped into the process.
39903990 adds: u64,
......@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {
39953995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {
39963996 addr: usize,
39973997 name: ?[*:0]const u8,
3998 phdr: [*]std.elf.Phdr,
3998 phdr: [*]std.elf.ElfN.Phdr,
39993999 phnum: std.elf.Half,
40004000 },
40014001 else => void,
lib/std/debug/SelfInfo/Elf.zig+10-10
......@@ -441,11 +441,11 @@ const DlIterContext = struct {
441441
442442 // Populate `build_id` and `gnu_eh_frame`
443443 for (info.phdr[0..info.phnum]) |phdr| {
444 switch (phdr.p_type) {
445 std.elf.PT_NOTE => {
444 switch (phdr.type) {
445 .NOTE => {
446446 // Look for .note.gnu.build-id
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.p_memsz]);
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.memsz]);
449449 const name_size = r.takeInt(u32, native_endian) catch continue;
450450 const desc_size = r.takeInt(u32, native_endian) catch continue;
451451 const note_type = r.takeInt(u32, native_endian) catch continue;
......@@ -455,9 +455,9 @@ const DlIterContext = struct {
455455 const desc = r.take(desc_size) catch continue;
456456 build_id = desc;
457457 },
458 std.elf.PT_GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.p_memsz];
458 std.elf.PT.GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.memsz];
461461 },
462462 else => {},
463463 }
......@@ -478,11 +478,11 @@ const DlIterContext = struct {
478478 });
479479
480480 for (info.phdr[0..info.phnum]) |phdr| {
481 if (phdr.p_type != std.elf.PT_LOAD) continue;
481 if (phdr.type != .LOAD) continue;
482482 try context.si.ranges.append(gpa, .{
483483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000
484 .start = info.addr +% phdr.p_vaddr,
485 .len = phdr.p_memsz,
484 .start = info.addr +% phdr.vaddr,
485 .len = phdr.memsz,
486486 .module_index = module_index,
487487 });
488488 }
lib/std/dynamic_library.zig+1-2
......@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
9292 });
9393}
9494
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
96 _ = phdrs;
95pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
9796 const _DYNAMIC = get_DYNAMIC() orelse {
9897 // No PT_DYNAMIC means this is a statically-linked non-PIE program.
9998 return .{ .current = null };
lib/std/elf.zig+228-100
......@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;
5050pub const AT_L2_CACHEGEOMETRY = 45;
5151pub const AT_L3_CACHESIZE = 46;
5252pub const AT_L3_CACHEGEOMETRY = 47;
53pub const AT_MINSIGSTKSZ = 51;
5354
5455pub const DT_NULL = 0;
5556pub const DT_NEEDED = 1;
......@@ -286,105 +287,111 @@ pub const VER_FLG_BASE = 1;
286287/// Weak version identifier
287288pub const VER_FLG_WEAK = 2;
288289
289/// Program header table entry unused
290pub const PT_NULL = 0;
291/// Loadable program segment
292pub const PT_LOAD = 1;
293/// Dynamic linking information
294pub const PT_DYNAMIC = 2;
295/// Program interpreter
296pub const PT_INTERP = 3;
297/// Auxiliary information
298pub const PT_NOTE = 4;
299/// Reserved
300pub const PT_SHLIB = 5;
301/// Entry for header table itself
302pub const PT_PHDR = 6;
303/// Thread-local storage segment
304pub const PT_TLS = 7;
305/// Number of defined types
306pub const PT_NUM = 8;
307/// Start of OS-specific
308pub const PT_LOOS = 0x60000000;
309/// GCC .eh_frame_hdr segment
310pub const PT_GNU_EH_FRAME = 0x6474e550;
311/// Indicates stack executability
312pub const PT_GNU_STACK = 0x6474e551;
313/// Read-only after relocation
314pub const PT_GNU_RELRO = 0x6474e552;
315pub const PT_LOSUNW = 0x6ffffffa;
316/// Sun specific segment
317pub const PT_SUNWBSS = 0x6ffffffa;
318/// Stack segment
319pub const PT_SUNWSTACK = 0x6ffffffb;
320pub const PT_HISUNW = 0x6fffffff;
321/// End of OS-specific
322pub const PT_HIOS = 0x6fffffff;
323/// Start of processor-specific
324pub const PT_LOPROC = 0x70000000;
325/// End of processor-specific
326pub const PT_HIPROC = 0x7fffffff;
290/// Deprecated, use `@intFromEnum(std.elf.PT.NULL)`
291pub const PT_NULL = @intFromEnum(std.elf.PT.NULL);
292/// Deprecated, use `@intFromEnum(std.elf.PT.LOAD)`
293pub const PT_LOAD = @intFromEnum(std.elf.PT.LOAD);
294/// Deprecated, use `@intFromEnum(std.elf.PT.DYNAMIC)`
295pub const PT_DYNAMIC = @intFromEnum(std.elf.PT.DYNAMIC);
296/// Deprecated, use `@intFromEnum(std.elf.PT.INTERP)`
297pub const PT_INTERP = @intFromEnum(std.elf.PT.INTERP);
298/// Deprecated, use `@intFromEnum(std.elf.PT.NOTE)`
299pub const PT_NOTE = @intFromEnum(std.elf.PT.NOTE);
300/// Deprecated, use `@intFromEnum(std.elf.PT.SHLIB)`
301pub const PT_SHLIB = @intFromEnum(std.elf.PT.SHLIB);
302/// Deprecated, use `@intFromEnum(std.elf.PT.PHDR)`
303pub const PT_PHDR = @intFromEnum(std.elf.PT.PHDR);
304/// Deprecated, use `@intFromEnum(std.elf.PT.TLS)`
305pub const PT_TLS = @intFromEnum(std.elf.PT.TLS);
306/// Deprecated, use `std.elf.PT.NUM`.
307pub const PT_NUM = PT.NUM;
308/// Deprecated, use `@intFromEnum(std.elf.PT.LOOS)`
309pub const PT_LOOS = @intFromEnum(std.elf.PT.LOOS);
310/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_EH_FRAME)`
311pub const PT_GNU_EH_FRAME = @intFromEnum(std.elf.PT.GNU_EH_FRAME);
312/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_STACK)`
313pub const PT_GNU_STACK = @intFromEnum(std.elf.PT.GNU_STACK);
314/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_RELRO)`
315pub const PT_GNU_RELRO = @intFromEnum(std.elf.PT.GNU_RELRO);
316/// Deprecated, use `@intFromEnum(std.elf.PT.LOSUNW)`
317pub const PT_LOSUNW = @intFromEnum(std.elf.PT.LOSUNW);
318/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWBSS)`
319pub const PT_SUNWBSS = @intFromEnum(std.elf.PT.SUNWBSS);
320/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWSTACK)`
321pub const PT_SUNWSTACK = @intFromEnum(std.elf.PT.SUNWSTACK);
322/// Deprecated, use `@intFromEnum(std.elf.PT.HISUNW)`
323pub const PT_HISUNW = @intFromEnum(std.elf.PT.HISUNW);
324/// Deprecated, use `@intFromEnum(std.elf.PT.HIOS)`
325pub const PT_HIOS = @intFromEnum(std.elf.PT.HIOS);
326/// Deprecated, use `@intFromEnum(std.elf.PT.LOPROC)`
327pub const PT_LOPROC = @intFromEnum(std.elf.PT.LOPROC);
328/// Deprecated, use `@intFromEnum(std.elf.PT.HIPROC)`
329pub const PT_HIPROC = @intFromEnum(std.elf.PT.HIPROC);
327330
328331pub const PN_XNUM = 0xffff;
329332
330/// Section header table entry unused
331pub const SHT_NULL = 0;
332/// Program data
333pub const SHT_PROGBITS = 1;
334/// Symbol table
335pub const SHT_SYMTAB = 2;
336/// String table
337pub const SHT_STRTAB = 3;
338/// Relocation entries with addends
339pub const SHT_RELA = 4;
340/// Symbol hash table
341pub const SHT_HASH = 5;
342/// Dynamic linking information
343pub const SHT_DYNAMIC = 6;
344/// Notes
345pub const SHT_NOTE = 7;
346/// Program space with no data (bss)
347pub const SHT_NOBITS = 8;
348/// Relocation entries, no addends
349pub const SHT_REL = 9;
350/// Reserved
351pub const SHT_SHLIB = 10;
352/// Dynamic linker symbol table
353pub const SHT_DYNSYM = 11;
354/// Array of constructors
355pub const SHT_INIT_ARRAY = 14;
356/// Array of destructors
357pub const SHT_FINI_ARRAY = 15;
358/// Array of pre-constructors
359pub const SHT_PREINIT_ARRAY = 16;
360/// Section group
361pub const SHT_GROUP = 17;
362/// Extended section indices
363pub const SHT_SYMTAB_SHNDX = 18;
364/// Start of OS-specific
365pub const SHT_LOOS = 0x60000000;
366/// LLVM address-significance table
367pub const SHT_LLVM_ADDRSIG = 0x6fff4c03;
368/// GNU hash table
369pub const SHT_GNU_HASH = 0x6ffffff6;
370/// GNU version definition table
371pub const SHT_GNU_VERDEF = 0x6ffffffd;
372/// GNU needed versions table
373pub const SHT_GNU_VERNEED = 0x6ffffffe;
374/// GNU symbol version table
375pub const SHT_GNU_VERSYM = 0x6fffffff;
376/// End of OS-specific
377pub const SHT_HIOS = 0x6fffffff;
378/// Start of processor-specific
379pub const SHT_LOPROC = 0x70000000;
380/// Unwind information
381pub const SHT_X86_64_UNWIND = 0x70000001;
382/// End of processor-specific
383pub const SHT_HIPROC = 0x7fffffff;
384/// Start of application-specific
385pub const SHT_LOUSER = 0x80000000;
386/// End of application-specific
387pub const SHT_HIUSER = 0xffffffff;
333/// Deprecated, use `@intFromEnum(std.elf.SHT.NULL)`
334pub const SHT_NULL = @intFromEnum(std.elf.SHT.NULL);
335/// Deprecated, use `@intFromEnum(std.elf.SHT.PROGBITS)`
336pub const SHT_PROGBITS = @intFromEnum(std.elf.SHT.PROGBITS);
337/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB)`
338pub const SHT_SYMTAB = @intFromEnum(std.elf.SHT.SYMTAB);
339/// Deprecated, use `@intFromEnum(std.elf.SHT.STRTAB)`
340pub const SHT_STRTAB = @intFromEnum(std.elf.SHT.STRTAB);
341/// Deprecated, use `@intFromEnum(std.elf.SHT.RELA)`
342pub const SHT_RELA = @intFromEnum(std.elf.SHT.RELA);
343/// Deprecated, use `@intFromEnum(std.elf.SHT.HASH)`
344pub const SHT_HASH = @intFromEnum(std.elf.SHT.HASH);
345/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNAMIC)`
346pub const SHT_DYNAMIC = @intFromEnum(std.elf.SHT.DYNAMIC);
347/// Deprecated, use `@intFromEnum(std.elf.SHT.NOTE)`
348pub const SHT_NOTE = @intFromEnum(std.elf.SHT.NOTE);
349/// Deprecated, use `@intFromEnum(std.elf.SHT.NOBITS)`
350pub const SHT_NOBITS = @intFromEnum(std.elf.SHT.NOBITS);
351/// Deprecated, use `@intFromEnum(std.elf.SHT.REL)`
352pub const SHT_REL = @intFromEnum(std.elf.SHT.REL);
353/// Deprecated, use `@intFromEnum(std.elf.SHT.SHLIB)`
354pub const SHT_SHLIB = @intFromEnum(std.elf.SHT.SHLIB);
355/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNSYM)`
356pub const SHT_DYNSYM = @intFromEnum(std.elf.SHT.DYNSYM);
357/// Deprecated, use `@intFromEnum(std.elf.SHT.INIT_ARRAY)`
358pub const SHT_INIT_ARRAY = @intFromEnum(std.elf.SHT.INIT_ARRAY);
359/// Deprecated, use `@intFromEnum(std.elf.SHT.FINI_ARRAY)`
360pub const SHT_FINI_ARRAY = @intFromEnum(std.elf.SHT.FINI_ARRAY);
361/// Deprecated, use `@intFromEnum(std.elf.SHT.PREINIT_ARRAY)`
362pub const SHT_PREINIT_ARRAY = @intFromEnum(std.elf.SHT.PREINIT_ARRAY);
363/// Deprecated, use `@intFromEnum(std.elf.SHT.GROUP)`
364pub const SHT_GROUP = @intFromEnum(std.elf.SHT.GROUP);
365/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB_SHNDX)`
366pub const SHT_SYMTAB_SHNDX = @intFromEnum(std.elf.SHT.SYMTAB_SHNDX);
367/// Deprecated, use `@intFromEnum(std.elf.SHT.RELR)`
368pub const SHT_RELR = @intFromEnum(std.elf.SHT.RELR);
369/// Deprecated, use `std.elf.SHT.NUM`.
370pub const SHT_NUM = SHT.NUM;
371/// Deprecated, use `@intFromEnum(std.elf.SHT.LOOS)`
372pub const SHT_LOOS = @intFromEnum(std.elf.SHT.LOOS);
373/// Deprecated, use `@intFromEnum(std.elf.SHT.LLVM_ADDRSIG)`
374pub const SHT_LLVM_ADDRSIG = @intFromEnum(std.elf.SHT.LLVM_ADDRSIG);
375/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_HASH)`
376pub const SHT_GNU_HASH = @intFromEnum(std.elf.SHT.GNU_HASH);
377/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERDEF)`
378pub const SHT_GNU_VERDEF = @intFromEnum(std.elf.SHT.GNU_VERDEF);
379/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERNEED)`
380pub const SHT_GNU_VERNEED = @intFromEnum(std.elf.SHT.GNU_VERNEED);
381/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERSYM)`
382pub const SHT_GNU_VERSYM = @intFromEnum(std.elf.SHT.GNU_VERSYM);
383/// Deprecated, use `@intFromEnum(std.elf.SHT.HIOS)`
384pub const SHT_HIOS = @intFromEnum(std.elf.SHT.HIOS);
385/// Deprecated, use `@intFromEnum(std.elf.SHT.LOPROC)`
386pub const SHT_LOPROC = @intFromEnum(std.elf.SHT.LOPROC);
387/// Deprecated, use `@intFromEnum(std.elf.SHT.X86_64_UNWIND)`
388pub const SHT_X86_64_UNWIND = @intFromEnum(std.elf.SHT.X86_64_UNWIND);
389/// Deprecated, use `@intFromEnum(std.elf.SHT.HIPROC)`
390pub const SHT_HIPROC = @intFromEnum(std.elf.SHT.HIPROC);
391/// Deprecated, use `@intFromEnum(std.elf.SHT.LOUSER)`
392pub const SHT_LOUSER = @intFromEnum(std.elf.SHT.LOUSER);
393/// Deprecated, use `@intFromEnum(std.elf.SHT.HIUSER)`
394pub const SHT_HIUSER = @intFromEnum(std.elf.SHT.HIUSER);
388395
389396// Note type for .note.gnu.build_id
390397pub const NT_GNU_BUILD_ID = 3;
......@@ -454,6 +461,127 @@ pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC);
454461/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)`
455462pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT);
456463
464pub const PT = enum(Word) {
465 /// Program header table entry unused
466 NULL = 0,
467 /// Loadable program segment
468 LOAD = 1,
469 /// Dynamic linking information
470 DYNAMIC = 2,
471 /// Program interpreter
472 INTERP = 3,
473 /// Auxiliary information
474 NOTE = 4,
475 /// Reserved
476 SHLIB = 5,
477 /// Entry for header table itself
478 PHDR = 6,
479 /// Thread-local storage segment
480 TLS = 7,
481 _,
482
483 /// Number of defined types
484 pub const NUM = @typeInfo(PT).@"enum".fields.len;
485
486 /// Start of OS-specific
487 pub const LOOS: PT = @enumFromInt(0x60000000);
488 /// End of OS-specific
489 pub const HIOS: PT = @enumFromInt(0x6fffffff);
490
491 /// GCC .eh_frame_hdr segment
492 pub const GNU_EH_FRAME: PT = @enumFromInt(0x6474e550);
493 /// Indicates stack executability
494 pub const GNU_STACK: PT = @enumFromInt(0x6474e551);
495 /// Read-only after relocation
496 pub const GNU_RELRO: PT = @enumFromInt(0x6474e552);
497
498 pub const LOSUNW: PT = @enumFromInt(0x6ffffffa);
499 pub const HISUNW: PT = @enumFromInt(0x6fffffff);
500
501 /// Sun specific segment
502 pub const SUNWBSS: PT = @enumFromInt(0x6ffffffa);
503 /// Stack segment
504 pub const SUNWSTACK: PT = @enumFromInt(0x6ffffffb);
505
506 /// Start of processor-specific
507 pub const LOPROC: PT = @enumFromInt(0x70000000);
508 /// End of processor-specific
509 pub const HIPROC: PT = @enumFromInt(0x7fffffff);
510};
511
512pub const SHT = enum(Word) {
513 /// Section header table entry unused
514 NULL = 0,
515 /// Program data
516 PROGBITS = 1,
517 /// Symbol table
518 SYMTAB = 2,
519 /// String table
520 STRTAB = 3,
521 /// Relocation entries with addends
522 RELA = 4,
523 /// Symbol hash table
524 HASH = 5,
525 /// Dynamic linking information
526 DYNAMIC = 6,
527 /// Notes
528 NOTE = 7,
529 /// Program space with no data (bss)
530 NOBITS = 8,
531 /// Relocation entries, no addends
532 REL = 9,
533 /// Reserved
534 SHLIB = 10,
535 /// Dynamic linker symbol table
536 DYNSYM = 11,
537 /// Array of constructors
538 INIT_ARRAY = 14,
539 /// Array of destructors
540 FINI_ARRAY = 15,
541 /// Array of pre-constructors
542 PREINIT_ARRAY = 16,
543 /// Section group
544 GROUP = 17,
545 /// Extended section indices
546 SYMTAB_SHNDX = 18,
547 /// RELR relative relocations
548 RELR = 19,
549 _,
550
551 /// Number of defined types
552 pub const NUM = @typeInfo(SHT).@"enum".fields.len;
553
554 /// Start of OS-specific
555 pub const LOOS: SHT = @enumFromInt(0x60000000);
556 /// End of OS-specific
557 pub const HIOS: SHT = @enumFromInt(0x6fffffff);
558
559 /// LLVM address-significance table
560 pub const LLVM_ADDRSIG: SHT = @enumFromInt(0x6fff4c03);
561
562 /// GNU hash table
563 pub const GNU_HASH: SHT = @enumFromInt(0x6ffffff6);
564 /// GNU version definition table
565 pub const GNU_VERDEF: SHT = @enumFromInt(0x6ffffffd);
566 /// GNU needed versions table
567 pub const GNU_VERNEED: SHT = @enumFromInt(0x6ffffffe);
568 /// GNU symbol version table
569 pub const GNU_VERSYM: SHT = @enumFromInt(0x6fffffff);
570
571 /// Start of processor-specific
572 pub const LOPROC: SHT = @enumFromInt(0x70000000);
573 /// End of processor-specific
574 pub const HIPROC: SHT = @enumFromInt(0x7fffffff);
575
576 /// Unwind information
577 pub const X86_64_UNWIND: SHT = @enumFromInt(0x70000001);
578
579 /// Start of application-specific
580 pub const LOUSER: SHT = @enumFromInt(0x80000000);
581 /// End of application-specific
582 pub const HIUSER: SHT = @enumFromInt(0xffffffff);
583};
584
457585pub const STB = enum(u4) {
458586 /// Local symbol
459587 LOCAL = 0,
......@@ -899,7 +1027,7 @@ pub const Elf32 = struct {
8991027 shstrndx: Half,
9001028 };
9011029 pub const Phdr = extern struct {
902 type: Word,
1030 type: PT,
9031031 offset: Elf32.Off,
9041032 vaddr: Elf32.Addr,
9051033 paddr: Elf32.Addr,
......@@ -910,7 +1038,7 @@ pub const Elf32 = struct {
9101038 };
9111039 pub const Shdr = extern struct {
9121040 name: Word,
913 type: Word,
1041 type: SHT,
9141042 flags: packed struct { shf: SHF },
9151043 addr: Elf32.Addr,
9161044 offset: Elf32.Off,
......@@ -989,7 +1117,7 @@ pub const Elf64 = struct {
9891117 shstrndx: Half,
9901118 };
9911119 pub const Phdr = extern struct {
992 type: Word,
1120 type: PT,
9931121 flags: PF,
9941122 offset: Elf64.Off,
9951123 vaddr: Elf64.Addr,
......@@ -1000,7 +1128,7 @@ pub const Elf64 = struct {
10001128 };
10011129 pub const Shdr = extern struct {
10021130 name: Word,
1003 type: Word,
1131 type: SHT,
10041132 flags: packed struct { shf: SHF, unused: Word = 0 },
10051133 addr: Elf64.Addr,
10061134 offset: Elf64.Off,
lib/std/os/linux.zig+1-1
......@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {
61016101pub const dl_phdr_info = extern struct {
61026102 addr: usize,
61036103 name: ?[*:0]const u8,
6104 phdr: [*]std.elf.Phdr,
6104 phdr: [*]std.elf.ElfN.Phdr,
61056105 phnum: u16,
61066106};
61076107
lib/std/posix.zig+30-39
......@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
50485048 }
50495049}
50505050
5051pub fn getSelfPhdrs() []std.elf.ElfN.Phdr {
5052 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5053 assert(getauxval(std.elf.AT_PHENT) == @sizeOf(std.elf.ElfN.Phdr));
5054 const phdrs: [*]std.elf.ElfN.Phdr = @ptrFromInt(getauxval(std.elf.AT_PHDR));
5055 return phdrs[0..getauxval(std.elf.AT_PHNUM)];
5056}
5057
50515058pub fn dl_iterate_phdr(
50525059 context: anytype,
50535060 comptime Error: type,
......@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(
50755082 }
50765083 }
50775084
5078 const elf_base = std.process.getBaseAddress();
5079 const ehdr: *elf.Ehdr = @ptrFromInt(elf_base);
5080 // Make sure the base address points to an ELF image.
5081 assert(mem.eql(u8, ehdr.e_ident[0..4], elf.MAGIC));
5082 const n_phdr = ehdr.e_phnum;
5083 const phdrs = (@as([*]elf.Phdr, @ptrFromInt(elf_base + ehdr.e_phoff)))[0..n_phdr];
5084
5085 var it = dl.linkmap_iterator(phdrs) catch unreachable;
5085 var it = dl.linkmap_iterator() catch unreachable;
50865086
50875087 // The executable has no dynamic link segment, create a single entry for
50885088 // the whole ELF image.
50895089 if (it.end()) {
5090 // Find the base address for the ELF image, if this is a PIE the value
5091 // is non-zero.
5092 const base_address = for (phdrs) |*phdr| {
5093 if (phdr.p_type == elf.PT_PHDR) {
5094 break @intFromPtr(phdrs.ptr) - phdr.p_vaddr;
5095 // We could try computing the difference between _DYNAMIC and
5096 // the p_vaddr of the PT_DYNAMIC section, but using the phdr is
5097 // good enough (Is it?).
5098 }
5099 } else unreachable;
5100
5101 var info = dl_phdr_info{
5102 .addr = base_address,
5103 .name = "/proc/self/exe",
5090 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5091 const phdrs = getSelfPhdrs();
5092 var info: dl_phdr_info = .{
5093 .addr = for (phdrs) |phdr| switch (phdr.type) {
5094 .PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr,
5095 else => {},
5096 } else unreachable,
5097 .name = switch (getauxval(std.elf.AT_EXECFN)) {
5098 0 => "/proc/self/exe",
5099 else => |name| @ptrFromInt(name),
5100 },
51045101 .phdr = phdrs.ptr,
5105 .phnum = ehdr.e_phnum,
5102 .phnum = @intCast(phdrs.len),
51065103 };
51075104
51085105 return callback(&info, @sizeOf(dl_phdr_info), context);
......@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(
51105107
51115108 // Last return value from the callback function.
51125109 while (it.next()) |entry| {
5113 var phdr: [*]elf.Phdr = undefined;
5114 var phnum: u16 = undefined;
5115
5116 if (entry.l_addr != 0) {
5117 const elf_header: *elf.Ehdr = @ptrFromInt(entry.l_addr);
5118 phdr = @ptrFromInt(entry.l_addr + elf_header.e_phoff);
5119 phnum = elf_header.e_phnum;
5120 } else {
5121 // This is the running ELF image
5122 phdr = @ptrFromInt(elf_base + ehdr.e_phoff);
5123 phnum = ehdr.e_phnum;
5124 }
5125
5126 var info = dl_phdr_info{
5110 const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
5111 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
5112 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
5113 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
5114 break :phdrs phdrs[0..ehdr.phnum];
5115 } else getSelfPhdrs();
5116
5117 var info: dl_phdr_info = .{
51275118 .addr = entry.l_addr,
51285119 .name = entry.l_name,
5129 .phdr = phdr,
5130 .phnum = phnum,
5120 .phdr = phdrs.ptr,
5121 .phnum = @intCast(phdrs.len),
51315122 };
51325123
51335124 try callback(&info, @sizeOf(dl_phdr_info), context);
lib/std/posix/test.zig+3-3
......@@ -257,11 +257,11 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
257257 while (i < info.phnum) : (i += 1) {
258258 const phdr = info.phdr[i];
259259
260 if (phdr.p_type != elf.PT_LOAD) continue;
260 if (phdr.type != .LOAD) continue;
261261
262 const reloc_addr = info.addr + phdr.p_vaddr;
262 const reloc_addr = info.addr + phdr.vaddr;
263263 // Find the ELF header
264 const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.p_offset));
264 const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.offset));
265265 // Validate the magic
266266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
267267 // Consistency check
lib/std/process.zig+7-7
......@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI
16581658pub fn getBaseAddress() usize {
16591659 switch (native_os) {
16601660 .linux => {
1661 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
1662 const base = getauxval(std.elf.AT_BASE);
1663 if (base != 0) {
1664 return base;
1665 }
1666 const phdr = getauxval(std.elf.AT_PHDR);
1667 return phdr - @sizeOf(std.elf.Ehdr);
1661 const phdrs = std.posix.getSelfPhdrs();
1662 var base: usize = 0;
1663 for (phdrs) |phdr| switch (phdr.type) {
1664 .LOAD => return base + phdr.vaddr,
1665 .PHDR => base = @intFromPtr(phdrs.ptr) - phdr.vaddr,
1666 else => {},
1667 } else unreachable;
16681668 },
16691669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
16701670 return @intFromPtr(&std.c._mh_execute_header);
src/link/Elf2.zig+682-390
......@@ -3,6 +3,7 @@ options: link.File.OpenOptions,
33mf: MappedFile,
44ni: Node.Known,
55nodes: std.MultiArrayList(Node),
6shdrs: std.ArrayList(Section),
67phdrs: std.ArrayList(MappedFile.Node.Index),
78si: Symbol.Known,
89symtab: std.ArrayList(Symbol),
......@@ -163,9 +164,29 @@ pub const Node = union(enum) {
163164 }
164165};
165166
167pub const Section = struct {
168 si: Symbol.Index,
169 rela_si: Symbol.Index,
170 rela_free: RelIndex,
171
172 pub const RelIndex = enum(u32) {
173 none,
174 _,
175
176 pub fn wrap(i: ?u32) RelIndex {
177 return @enumFromInt((i orelse return .none) + 1);
178 }
179 pub fn unwrap(ri: RelIndex) ?u32 {
180 return switch (ri) {
181 .none => null,
182 else => @intFromEnum(ri) - 1,
183 };
184 }
185 };
186};
187
166188pub const StringTable = struct {
167189 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
168 size: u32,
169190
170191 const Context = struct {
171192 slice: []const u8,
......@@ -193,14 +214,10 @@ pub const StringTable = struct {
193214 }
194215 };
195216
196 pub fn get(
197 st: *StringTable,
198 gpa: std.mem.Allocator,
199 mf: *MappedFile,
200 ni: MappedFile.Node.Index,
201 key: []const u8,
202 ) !u32 {
203 const slice_const = ni.sliceConst(mf);
217 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
218 const gpa = elf.base.comp.gpa;
219 const ni = si.node(elf);
220 const slice_const = ni.sliceConst(&elf.mf);
204221 const gop = try st.map.getOrPutContextAdapted(
205222 gpa,
206223 key,
......@@ -208,11 +225,18 @@ pub const StringTable = struct {
208225 .{ .slice = slice_const },
209226 );
210227 if (gop.found_existing) return gop.key_ptr.*;
211 const old_size = st.size;
212 const new_size: u32 = @intCast(old_size + key.len + 1);
213 st.size = new_size;
214 try ni.resize(mf, gpa, new_size);
215 const slice = ni.slice(mf)[old_size..];
228 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
229 inline else => |shdr| {
230 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
231 const new_size: u32 = @intCast(old_size + key.len + 1);
232 elf.targetStore(&shdr.size, new_size);
233 break :size .{ old_size, new_size };
234 },
235 };
236 _, const node_size = ni.location(&elf.mf).resolve(&elf.mf);
237 if (new_size > node_size)
238 try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor);
239 const slice = ni.slice(&elf.mf)[old_size..];
216240 @memcpy(slice[0..key.len], key);
217241 slice[key.len] = 0;
218242 gop.key_ptr.* = old_size;
......@@ -226,7 +250,7 @@ pub const Symbol = struct {
226250 loc_relocs: Reloc.Index,
227251 /// Relocations targeting this symbol
228252 target_relocs: Reloc.Index,
229 unused: u32 = 0,
253 unused: u32,
230254
231255 pub const Index = enum(u32) {
232256 null,
......@@ -252,6 +276,52 @@ pub const Symbol = struct {
252276 return @enumFromInt(@intFromEnum(si) + 1);
253277 }
254278
279 pub const Shndx = enum(Tag) {
280 UNDEF = std.elf.SHN_UNDEF,
281 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
282 ABS = reserve(std.elf.SHN_ABS),
283 COMMON = reserve(std.elf.SHN_COMMON),
284 _,
285
286 pub const Tag = u32;
287
288 pub const LORESERVE: Shndx = .fromSection(std.elf.SHN_LORESERVE);
289 pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE);
290 comptime {
291 assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));
292 }
293
294 fn reserve(sec: std.elf.Section) Tag {
295 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
296 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
297 }
298
299 pub fn fromSection(sec: std.elf.Section) Shndx {
300 return switch (sec) {
301 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),
302 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),
303 };
304 }
305 pub fn toSection(s: Shndx) ?std.elf.Section {
306 return switch (@intFromEnum(s)) {
307 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
308 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
309 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
310 sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,
311 ),
312 };
313 }
314
315 pub fn get(s: Shndx, elf: *Elf) *Section {
316 return &elf.shdrs.items[@intFromEnum(s)];
317 }
318 };
319 pub fn shndx(si: Symbol.Index, elf: *Elf) Shndx {
320 return .fromSection(switch (elf.symPtr(si)) {
321 inline else => |sym| elf.targetLoad(&sym.shndx),
322 });
323 }
324
255325 pub const InitOptions = struct {
256326 name: []const u8 = "",
257327 lib_name: ?[]const u8 = null,
......@@ -260,48 +330,83 @@ pub const Symbol = struct {
260330 type: std.elf.STT,
261331 bind: std.elf.STB = .LOCAL,
262332 visibility: std.elf.STV = .DEFAULT,
263 shndx: std.elf.Section = std.elf.SHN_UNDEF,
333 shndx: Shndx = .UNDEF,
264334 };
265335 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
266336 const gpa = elf.base.comp.gpa;
267337 const target_endian = elf.targetEndian();
268 const sym_size: usize = switch (elf.identClass()) {
269 .NONE, _ => unreachable,
270 inline else => |class| @sizeOf(class.ElfN().Sym),
271 };
272338 const name_strtab_entry = try elf.string(.strtab, opts.name);
273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
339 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
340 inline else => |shdr| {
341 const old_size = elf.targetLoad(&shdr.size);
342 const ent_size = elf.targetLoad(&shdr.entsize);
343 const new_size = ent_size * elf.symtab.items.len;
344 if (new_size > old_size) {
345 elf.targetStore(&shdr.size, @intCast(new_size));
346 const symtab_ni = elf.si.symtab.node(elf);
347 _, const node_size = symtab_ni.location(&elf.mf).resolve(&elf.mf);
348 if (new_size > node_size) try symtab_ni.resize(
349 &elf.mf,
350 gpa,
351 new_size +| new_size / MappedFile.growth_factor,
352 );
353 }
354 },
355 }
274356 switch (elf.symPtr(si)) {
275357 inline else => |sym, class| {
358 const Sym = class.ElfN().Sym;
276359 sym.* = .{
277360 .name = name_strtab_entry,
278361 .value = @intCast(opts.value),
279362 .size = @intCast(opts.size),
280363 .info = .{ .type = opts.type, .bind = opts.bind },
281364 .other = .{ .visibility = opts.visibility },
282 .shndx = opts.shndx,
365 .shndx = opts.shndx.toSection().?,
283366 };
284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
367 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym);
285368 },
286369 }
370 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
371 inline else => |shdr| elf.targetStore(&shdr.info, @max(
372 elf.targetLoad(&shdr.info),
373 @intFromEnum(si) + 1,
374 )),
375 }
287376 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
288377 const dsi = elf.dynsym.items.len;
289378 try elf.dynsym.append(gpa, si);
290 const dynsym_ni = elf.si.dynsym.node(elf);
291379 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
292 try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len);
380 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
381 inline else => |shdr| {
382 const old_size = elf.targetLoad(&shdr.size);
383 const ent_size = elf.targetLoad(&shdr.entsize);
384 const new_size = ent_size * elf.dynsym.items.len;
385 if (new_size > old_size) {
386 elf.targetStore(&shdr.size, @intCast(new_size));
387 const dynsym_ni = elf.si.dynsym.node(elf);
388 _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);
389 if (new_size > node_size) try dynsym_ni.resize(
390 &elf.mf,
391 gpa,
392 new_size +| new_size / MappedFile.growth_factor,
393 );
394 }
395 },
396 }
293397 switch (elf.dynsymSlice()) {
294 inline else => |dynsym, class| {
295 const dsym = &dynsym[dsi];
296 dsym.* = .{
398 inline else => |dynsyms, class| {
399 const Sym = class.ElfN().Sym;
400 const dynsym = &dynsyms[dsi];
401 dynsym.* = .{
297402 .name = name_dynstr_entry,
298403 .value = @intCast(opts.value),
299404 .size = @intCast(opts.size),
300405 .info = .{ .type = opts.type, .bind = opts.bind },
301406 .other = .{ .visibility = opts.visibility },
302 .shndx = opts.shndx,
407 .shndx = opts.shndx.toSection().?,
303408 };
304 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);
409 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
305410 },
306411 }
307412 }
......@@ -321,6 +426,7 @@ pub const Symbol = struct {
321426 }
322427
323428 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
429 if (elf.ehdrField(.type) == .REL) return;
324430 switch (si.get(elf).loc_relocs) {
325431 .none => {},
326432 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
......@@ -331,6 +437,7 @@ pub const Symbol = struct {
331437 }
332438
333439 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {
440 if (elf.ehdrField(.type) == .REL) return;
334441 var ri = si.get(elf).target_relocs;
335442 while (ri != .none) {
336443 const reloc = ri.get(elf);
......@@ -374,7 +481,7 @@ pub const Reloc = extern struct {
374481 next: Reloc.Index,
375482 loc: Symbol.Index,
376483 target: Symbol.Index,
377 unused: u32,
484 index: Section.RelIndex,
378485 offset: u64,
379486 addend: i64,
380487
......@@ -384,6 +491,16 @@ pub const Reloc = extern struct {
384491 RISCV: std.elf.R_RISCV,
385492 PPC64: std.elf.R_PPC64,
386493
494 pub fn none(elf: *Elf) Reloc.Type {
495 return switch (elf.ehdrField(.machine)) {
496 else => unreachable,
497 .AARCH64 => .{ .AARCH64 = .NONE },
498 .PPC64 => .{ .PPC64 = .NONE },
499 .RISCV => .{ .RISCV = .NONE },
500 .X86_64 => .{ .X86_64 = .NONE },
501 };
502 }
503
387504 pub fn absAddr(elf: *Elf) Reloc.Type {
388505 return switch (elf.ehdrField(.machine)) {
389506 else => unreachable,
......@@ -393,12 +510,35 @@ pub const Reloc = extern struct {
393510 .X86_64 => .{ .X86_64 = .@"64" },
394511 };
395512 }
513
396514 pub fn sizeAddr(elf: *Elf) Reloc.Type {
397515 return switch (elf.ehdrField(.machine)) {
398516 else => unreachable,
399517 .X86_64 => .{ .X86_64 = .SIZE64 },
400518 };
401519 }
520
521 pub fn wrap(int: u32, elf: *Elf) Reloc.Type {
522 return switch (elf.ehdrField(.machine)) {
523 else => unreachable,
524 inline .AARCH64,
525 .PPC64,
526 .RISCV,
527 .X86_64,
528 => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),
529 };
530 }
531
532 pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {
533 return switch (elf.ehdrField(.machine)) {
534 else => unreachable,
535 inline .AARCH64,
536 .PPC64,
537 .RISCV,
538 .X86_64,
539 => |machine| @intFromEnum(@field(rt, @tagName(machine))),
540 };
541 }
402542 };
403543
404544 pub const Index = enum(u32) {
......@@ -411,6 +551,7 @@ pub const Reloc = extern struct {
411551 };
412552
413553 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
554 assert(elf.ehdrField(.type) != .REL);
414555 const loc_ni = reloc.loc.get(elf).ni;
415556 switch (loc_ni) {
416557 .none => return,
......@@ -462,7 +603,7 @@ pub const Reloc = extern struct {
462603 .TPOFF32 => {
463604 const phdr = @field(elf.phdrSlice(), @tagName(class));
464605 const ph = &phdr[elf.getNode(elf.ni.tls).segment];
465 assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
606 assert(elf.targetLoad(&ph.type) == .TLS);
466607 std.mem.writeInt(
467608 i32,
468609 loc_slice[0..4],
......@@ -501,6 +642,33 @@ pub const Reloc = extern struct {
501642 .none => {},
502643 else => |next| next.get(elf).prev = reloc.prev,
503644 }
645 switch (elf.ehdrField(.type)) {
646 .NONE, .CORE, _ => unreachable,
647 .REL => {
648 const sh = reloc.loc.shndx(elf).get(elf);
649 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
650 inline else => |shdr, class| {
651 const Rela = class.ElfN().Rela;
652 const ent_size = elf.targetLoad(&shdr.entsize);
653 const start = ent_size * reloc.index.unwrap().?;
654 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
655 const rela: *Rela = @ptrCast(@alignCast(
656 rela_slice[@intCast(start)..][0..@intCast(ent_size)],
657 ));
658 rela.* = .{
659 .offset = @intFromEnum(sh.rela_free),
660 .info = .{
661 .type = @intCast(Reloc.Type.none(elf).unwrap(elf)),
662 .sym = 0,
663 },
664 .addend = 0,
665 };
666 },
667 }
668 sh.rela_free = reloc.index;
669 },
670 .EXEC, .DYN => assert(reloc.index == .none),
671 }
504672 reloc.* = undefined;
505673 }
506674
......@@ -601,6 +769,7 @@ fn create(
601769 .tls = .none,
602770 },
603771 .nodes = .empty,
772 .shdrs = .empty,
604773 .phdrs = .empty,
605774 .si = .{
606775 .dynsym = .null,
......@@ -611,16 +780,13 @@ fn create(
611780 .symtab = .empty,
612781 .shstrtab = .{
613782 .map = .empty,
614 .size = 1,
615783 },
616784 .strtab = .{
617785 .map = .empty,
618 .size = 1,
619786 },
620787 .dynsym = .empty,
621788 .dynstr = .{
622789 .map = .empty,
623 .size = 1,
624790 },
625791 .needed = .empty,
626792 .inputs = .empty,
......@@ -650,6 +816,7 @@ pub fn deinit(elf: *Elf) void {
650816 const gpa = elf.base.comp.gpa;
651817 elf.mf.deinit(gpa);
652818 elf.nodes.deinit(gpa);
819 elf.shdrs.deinit(gpa);
653820 elf.phdrs.deinit(gpa);
654821 elf.symtab.deinit(gpa);
655822 elf.shstrtab.map.deinit(gpa);
......@@ -681,11 +848,10 @@ fn initHeaders(
681848 const comp = elf.base.comp;
682849 const gpa = comp.gpa;
683850 const have_dynamic_section = switch (@"type") {
684 .NONE => unreachable,
851 .NONE, .CORE, _ => unreachable,
685852 .REL => false,
686853 .EXEC => comp.config.link_mode == .dynamic,
687854 .DYN => true,
688 .CORE, _ => unreachable,
689855 };
690856 const addr_align: std.mem.Alignment = switch (class) {
691857 .NONE, _ => unreachable,
......@@ -693,6 +859,7 @@ fn initHeaders(
693859 .@"64" => .@"8",
694860 };
695861
862 const shnum: u32 = 1;
696863 var phnum: u32 = 0;
697864 const phdr_phndx = phnum;
698865 phnum += 1;
......@@ -715,8 +882,17 @@ fn initHeaders(
715882 break :phndx phnum;
716883 } else undefined;
717884
718 const expected_nodes_len = 5 + phnum * 2 + @as(usize, 2) * @intFromBool(have_dynamic_section);
885 const expected_nodes_len = expected_nodes_len: switch (@"type") {
886 .NONE, .CORE, _ => unreachable,
887 .REL => {
888 defer phnum = 0;
889 break :expected_nodes_len 5 + phnum;
890 },
891 .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +
892 @as(usize, 2) * @intFromBool(have_dynamic_section),
893 };
719894 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
895 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
720896 try elf.phdrs.resize(gpa, phnum);
721897 elf.nodes.appendAssumeCapacity(.file);
722898
......@@ -751,7 +927,7 @@ fn initHeaders(
751927 ehdr.phentsize = @sizeOf(ElfN.Phdr);
752928 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
753929 ehdr.shentsize = @sizeOf(ElfN.Shdr);
754 ehdr.shnum = 1;
930 ehdr.shnum = if (shnum < std.elf.SHN_LORESERVE) shnum else 0;
755931 ehdr.shstrndx = std.elf.SHN_UNDEF;
756932 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
757933 },
......@@ -759,181 +935,187 @@ fn initHeaders(
759935
760936 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
761937 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
762 .alignment = addr_align,
938 .alignment = elf.mf.flags.block_size,
763939 .moved = true,
764940 .resized = true,
765941 }));
766942 elf.nodes.appendAssumeCapacity(.shdr);
767943
768 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
769 .alignment = elf.mf.flags.block_size,
770 .moved = true,
771 .bubbles_moved = false,
772 }));
773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
944 var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {
945 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
946 .alignment = elf.mf.flags.block_size,
947 .moved = true,
948 .bubbles_moved = false,
949 }));
950 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
951 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
775952
776 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
778 .alignment = addr_align,
779 .moved = true,
780 .resized = true,
781 .bubbles_moved = false,
782 }));
783 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
784 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
953 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
954 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
955 .alignment = addr_align,
956 .moved = true,
957 .resized = true,
958 .bubbles_moved = false,
959 }));
960 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
961 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
785962
786 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
787 .alignment = elf.mf.flags.block_size,
788 .moved = true,
789 .bubbles_moved = false,
790 }));
791 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
792 elf.phdrs.items[text_phndx] = elf.ni.text;
963 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
964 .alignment = elf.mf.flags.block_size,
965 .moved = true,
966 .bubbles_moved = false,
967 }));
968 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
969 elf.phdrs.items[text_phndx] = elf.ni.text;
793970
794 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
795 .alignment = elf.mf.flags.block_size,
796 .moved = true,
797 .bubbles_moved = false,
798 }));
799 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
800 elf.phdrs.items[data_phndx] = elf.ni.data;
801
802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
803 else => 0,
804 .EXEC => switch (elf.ehdrField(.machine)) {
805 .@"386" => 0x400000,
806 .AARCH64, .X86_64 => 0x200000,
807 .PPC, .PPC64 => 0x10000000,
808 .S390, .S390_OLD => 0x1000000,
809 .OLD_SPARCV9, .SPARCV9 => 0x100000,
810 else => 0x10000,
811 },
812 };
971 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
972 .alignment = elf.mf.flags.block_size,
973 .moved = true,
974 .bubbles_moved = false,
975 }));
976 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
977 elf.phdrs.items[data_phndx] = elf.ni.data;
978
979 break :ph_vaddr switch (elf.ehdrField(.type)) {
980 .NONE, .CORE, _ => unreachable,
981 .REL, .DYN => 0,
982 .EXEC => switch (elf.ehdrField(.machine)) {
983 .@"386" => 0x400000,
984 .AARCH64, .X86_64 => 0x200000,
985 .PPC, .PPC64 => 0x10000000,
986 .S390, .S390_OLD => 0x1000000,
987 .OLD_SPARCV9, .SPARCV9 => 0x100000,
988 else => 0x10000,
989 },
990 };
991 } else undefined;
813992 switch (class) {
814993 .NONE, _ => unreachable,
815994 inline else => |ct_class| {
816995 const ElfN = ct_class.ElfN();
817996 const target_endian = elf.targetEndian();
818997
819 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
820 const ph_phdr = &phdr[phdr_phndx];
821 ph_phdr.* = .{
822 .type = std.elf.PT_PHDR,
823 .offset = 0,
824 .vaddr = 0,
825 .paddr = 0,
826 .filesz = 0,
827 .memsz = 0,
828 .flags = .{ .R = true },
829 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
830 };
831 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
832
833 if (maybe_interp) |_| {
834 const ph_interp = &phdr[interp_phndx];
835 ph_interp.* = .{
836 .type = std.elf.PT_INTERP,
998 if (@"type" != .REL) {
999 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
1000 const ph_phdr = &phdr[phdr_phndx];
1001 ph_phdr.* = .{
1002 .type = .PHDR,
8371003 .offset = 0,
8381004 .vaddr = 0,
8391005 .paddr = 0,
8401006 .filesz = 0,
8411007 .memsz = 0,
8421008 .flags = .{ .R = true },
843 .@"align" = 1,
1009 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
8441010 };
845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
846 }
847
848 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
849 const ph_rodata = &phdr[rodata_phndx];
850 ph_rodata.* = .{
851 .type = std.elf.PT_NULL,
852 .offset = 0,
853 .vaddr = ph_vaddr,
854 .paddr = ph_vaddr,
855 .filesz = @intCast(rodata_size),
856 .memsz = @intCast(rodata_size),
857 .flags = .{ .R = true },
858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
859 };
860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
861 ph_vaddr += @intCast(rodata_size);
862
863 _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
864 const ph_text = &phdr[text_phndx];
865 ph_text.* = .{
866 .type = std.elf.PT_NULL,
867 .offset = 0,
868 .vaddr = ph_vaddr,
869 .paddr = ph_vaddr,
870 .filesz = @intCast(text_size),
871 .memsz = @intCast(text_size),
872 .flags = .{ .R = true, .X = true },
873 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
874 };
875 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
876 ph_vaddr += @intCast(text_size);
1011 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
1012
1013 if (maybe_interp) |_| {
1014 const ph_interp = &phdr[interp_phndx];
1015 ph_interp.* = .{
1016 .type = .INTERP,
1017 .offset = 0,
1018 .vaddr = 0,
1019 .paddr = 0,
1020 .filesz = 0,
1021 .memsz = 0,
1022 .flags = .{ .R = true },
1023 .@"align" = 1,
1024 };
1025 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
1026 }
8771027
878 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
879 const ph_data = &phdr[data_phndx];
880 ph_data.* = .{
881 .type = std.elf.PT_NULL,
882 .offset = 0,
883 .vaddr = ph_vaddr,
884 .paddr = ph_vaddr,
885 .filesz = @intCast(data_size),
886 .memsz = @intCast(data_size),
887 .flags = .{ .R = true, .W = true },
888 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
889 };
890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
891 ph_vaddr += @intCast(data_size);
1028 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
1029 const ph_rodata = &phdr[rodata_phndx];
1030 ph_rodata.* = .{
1031 .type = if (rodata_size == 0) .NULL else .LOAD,
1032 .offset = 0,
1033 .vaddr = ph_vaddr,
1034 .paddr = ph_vaddr,
1035 .filesz = @intCast(rodata_size),
1036 .memsz = @intCast(rodata_size),
1037 .flags = .{ .R = true },
1038 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
1039 };
1040 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
1041 ph_vaddr += @intCast(rodata_size);
8921042
893 if (have_dynamic_section) {
894 const ph_dynamic = &phdr[dynamic_phndx];
895 ph_dynamic.* = .{
896 .type = std.elf.PT_DYNAMIC,
1043 _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
1044 const ph_text = &phdr[text_phndx];
1045 ph_text.* = .{
1046 .type = if (text_size == 0) .NULL else .LOAD,
8971047 .offset = 0,
898 .vaddr = 0,
899 .paddr = 0,
900 .filesz = 0,
901 .memsz = 0,
902 .flags = .{ .R = true, .W = true },
903 .@"align" = @intCast(addr_align.toByteUnits()),
1048 .vaddr = ph_vaddr,
1049 .paddr = ph_vaddr,
1050 .filesz = @intCast(text_size),
1051 .memsz = @intCast(text_size),
1052 .flags = .{ .R = true, .X = true },
1053 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
9041054 };
905 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
906 }
1055 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
1056 ph_vaddr += @intCast(text_size);
9071057
908 if (comp.config.any_non_single_threaded) {
909 const ph_tls = &phdr[tls_phndx];
910 ph_tls.* = .{
911 .type = std.elf.PT_TLS,
1058 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
1059 const ph_data = &phdr[data_phndx];
1060 ph_data.* = .{
1061 .type = if (data_size == 0) .NULL else .LOAD,
9121062 .offset = 0,
913 .vaddr = 0,
914 .paddr = 0,
915 .filesz = 0,
916 .memsz = 0,
917 .flags = .{ .R = true },
918 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
1063 .vaddr = ph_vaddr,
1064 .paddr = ph_vaddr,
1065 .filesz = @intCast(data_size),
1066 .memsz = @intCast(data_size),
1067 .flags = .{ .R = true, .W = true },
1068 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
9191069 };
920 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
1070 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
1071 ph_vaddr += @intCast(data_size);
1072
1073 if (have_dynamic_section) {
1074 const ph_dynamic = &phdr[dynamic_phndx];
1075 ph_dynamic.* = .{
1076 .type = .DYNAMIC,
1077 .offset = 0,
1078 .vaddr = 0,
1079 .paddr = 0,
1080 .filesz = 0,
1081 .memsz = 0,
1082 .flags = .{ .R = true, .W = true },
1083 .@"align" = @intCast(addr_align.toByteUnits()),
1084 };
1085 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
1086 }
1087
1088 if (comp.config.any_non_single_threaded) {
1089 const ph_tls = &phdr[tls_phndx];
1090 ph_tls.* = .{
1091 .type = .TLS,
1092 .offset = 0,
1093 .vaddr = 0,
1094 .paddr = 0,
1095 .filesz = 0,
1096 .memsz = 0,
1097 .flags = .{ .R = true },
1098 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
1099 };
1100 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
1101 }
9211102 }
9221103
923 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
924 sh_null.* = .{
1104 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
1105 sh_undef.* = .{
9251106 .name = try elf.string(.shstrtab, ""),
926 .type = std.elf.SHT_NULL,
1107 .type = .NULL,
9271108 .flags = .{ .shf = .{} },
9281109 .addr = 0,
9291110 .offset = 0,
930 .size = 0,
1111 .size = if (shnum < std.elf.SHN_LORESERVE) 0 else shnum,
9311112 .link = 0,
932 .info = if (phnum >= std.elf.PN_XNUM) phnum else 0,
1113 .info = if (phnum < std.elf.PN_XNUM) 0 else phnum,
9331114 .addralign = 0,
9341115 .entsize = 0,
9351116 };
936 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null);
1117 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1118 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
9371119
9381120 try elf.symtab.ensureTotalCapacity(gpa, 1);
9391121 elf.symtab.addOneAssumeCapacity().* = .{
......@@ -943,10 +1125,11 @@ fn initHeaders(
9431125 .unused = 0,
9441126 };
9451127 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
946 .type = std.elf.SHT_SYMTAB,
1128 .type = .SYMTAB,
9471129 .size = @sizeOf(ElfN.Sym) * 1,
9481130 .addralign = addr_align,
9491131 .entsize = @sizeOf(ElfN.Sym),
1132 .node_align = elf.mf.flags.block_size,
9501133 }));
9511134 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
9521135 symtab_null.* = .{
......@@ -960,13 +1143,14 @@ fn initHeaders(
9601143 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
9611144
9621145 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
963 ehdr.shstrndx = ehdr.shnum;
1146 elf.targetStore(&ehdr.shstrndx, ehdr.shnum);
9641147 },
9651148 }
9661149 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
967 .type = std.elf.SHT_STRTAB,
968 .addralign = elf.mf.flags.block_size,
1150 .type = .STRTAB,
1151 .size = 1,
9691152 .entsize = 1,
1153 .node_align = elf.mf.flags.block_size,
9701154 }));
9711155 try elf.renameSection(.symtab, ".symtab");
9721156 try elf.renameSection(.shstrtab, ".shstrtab");
......@@ -974,10 +1158,10 @@ fn initHeaders(
9741158
9751159 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
9761160 .name = ".strtab",
977 .type = std.elf.SHT_STRTAB,
1161 .type = .STRTAB,
9781162 .size = 1,
979 .addralign = elf.mf.flags.block_size,
9801163 .entsize = 1,
1164 .node_align = elf.mf.flags.block_size,
9811165 }));
9821166 try elf.linkSections(.symtab, .strtab);
9831167 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
......@@ -997,87 +1181,96 @@ fn initHeaders(
9971181 .flags = .{ .WRITE = true, .ALLOC = true },
9981182 .addralign = elf.mf.flags.block_size,
9991183 }));
1000 if (maybe_interp) |interp| {
1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1002 .size = interp.len + 1,
1003 .moved = true,
1004 .resized = true,
1005 .bubbles_moved = false,
1006 });
1007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
1008 elf.phdrs.items[interp_phndx] = interp_ni;
1009
1010 const sec_interp_si = try elf.addSection(interp_ni, .{
1011 .name = ".interp",
1012 .flags = .{ .ALLOC = true },
1013 .size = @intCast(interp.len + 1),
1014 });
1015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
1016 @memcpy(sec_interp[0..interp.len], interp);
1017 sec_interp[interp.len] = 0;
1018 }
1019 if (have_dynamic_section) {
1020 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1021 .moved = true,
1022 .bubbles_moved = false,
1023 });
1024 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1025 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
1026
1027 switch (class) {
1028 .NONE, _ => unreachable,
1029 inline else => |ct_class| {
1030 const ElfN = ct_class.ElfN();
1031 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1032 .name = ".dynsym",
1033 .type = std.elf.SHT_DYNSYM,
1034 .size = @sizeOf(ElfN.Sym) * 1,
1035 .addralign = addr_align,
1036 .entsize = @sizeOf(ElfN.Sym),
1037 });
1038 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1039 dynsym_null.* = .{
1040 .name = try elf.string(.dynstr, ""),
1041 .value = 0,
1042 .size = 0,
1043 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1044 .other = .{ .visibility = .DEFAULT },
1045 .shndx = std.elf.SHN_UNDEF,
1046 };
1047 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null);
1048 },
1184 if (@"type" != .REL) {
1185 if (maybe_interp) |interp| {
1186 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1187 .size = interp.len + 1,
1188 .moved = true,
1189 .resized = true,
1190 .bubbles_moved = false,
1191 });
1192 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
1193 elf.phdrs.items[interp_phndx] = interp_ni;
1194
1195 const sec_interp_si = try elf.addSection(interp_ni, .{
1196 .type = .PROGBITS,
1197 .name = ".interp",
1198 .flags = .{ .ALLOC = true },
1199 .size = @intCast(interp.len + 1),
1200 });
1201 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
1202 @memcpy(sec_interp[0..interp.len], interp);
1203 sec_interp[interp.len] = 0;
10491204 }
1050 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1051 .name = ".dynstr",
1052 .type = std.elf.SHT_STRTAB,
1053 .size = 1,
1054 .addralign = elf.mf.flags.block_size,
1055 .entsize = 1,
1056 });
1057 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1058 .name = ".dynamic",
1059 .type = std.elf.SHT_DYNAMIC,
1060 .flags = .{ .ALLOC = true, .WRITE = true },
1061 .addralign = addr_align,
1062 });
1063 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1064 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1065 }
1066 if (comp.config.any_non_single_threaded) {
1067 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1068 .alignment = elf.mf.flags.block_size,
1069 .moved = true,
1070 .bubbles_moved = false,
1071 });
1072 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
1073 elf.phdrs.items[tls_phndx] = elf.ni.tls;
1205 if (have_dynamic_section) {
1206 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1207 .moved = true,
1208 .bubbles_moved = false,
1209 });
1210 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1211 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
10741212
1075 elf.si.tdata = try elf.addSection(elf.ni.tls, .{
1076 .name = ".tdata",
1077 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1078 .addralign = elf.mf.flags.block_size,
1079 });
1213 switch (class) {
1214 .NONE, _ => unreachable,
1215 inline else => |ct_class| {
1216 const Sym = ct_class.ElfN().Sym;
1217 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1218 .name = ".dynsym",
1219 .type = .DYNSYM,
1220 .size = @sizeOf(Sym) * 1,
1221 .addralign = addr_align,
1222 .entsize = @sizeOf(Sym),
1223 .node_align = elf.mf.flags.block_size,
1224 });
1225 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1226 dynsym_null.* = .{
1227 .name = try elf.string(.dynstr, ""),
1228 .value = 0,
1229 .size = 0,
1230 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1231 .other = .{ .visibility = .DEFAULT },
1232 .shndx = std.elf.SHN_UNDEF,
1233 };
1234 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(
1235 Sym,
1236 dynsym_null,
1237 );
1238 },
1239 }
1240 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1241 .name = ".dynstr",
1242 .type = .STRTAB,
1243 .size = 1,
1244 .entsize = 1,
1245 .node_align = elf.mf.flags.block_size,
1246 });
1247 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1248 .name = ".dynamic",
1249 .type = .DYNAMIC,
1250 .flags = .{ .ALLOC = true, .WRITE = true },
1251 .node_align = addr_align,
1252 });
1253 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1254 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1255 }
1256 if (comp.config.any_non_single_threaded) {
1257 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1258 .alignment = elf.mf.flags.block_size,
1259 .moved = true,
1260 .bubbles_moved = false,
1261 });
1262 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
1263 elf.phdrs.items[tls_phndx] = elf.ni.tls;
1264 }
1265 } else {
1266 assert(maybe_interp == null);
1267 assert(!have_dynamic_section);
10801268 }
1269 if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{
1270 .name = ".tdata",
1271 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1272 .addralign = elf.mf.flags.block_size,
1273 });
10811274 assert(elf.nodes.len == expected_nodes_len);
10821275}
10831276
......@@ -1116,7 +1309,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
11161309 .file => return 0,
11171310 .ehdr, .shdr => unreachable,
11181311 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
1119 inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
1312 inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
11201313 },
11211314 .section => |si| si,
11221315 .input_section => unreachable,
......@@ -1202,6 +1395,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
12021395 @"64": []std.elf.Elf64.Phdr,
12031396};
12041397pub fn phdrSlice(elf: *Elf) PhdrSlice {
1398 assert(elf.ehdrField(.type) != .REL);
12051399 const slice = elf.ni.phdr.slice(&elf.mf);
12061400 return switch (elf.identClass()) {
12071401 .NONE, _ => unreachable,
......@@ -1230,6 +1424,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
12301424 };
12311425}
12321426
1427pub const ShdrPtr = union(std.elf.CLASS) {
1428 NONE: noreturn,
1429 @"32": *std.elf.Elf32.Shdr,
1430 @"64": *std.elf.Elf64.Shdr,
1431};
1432pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {
1433 return switch (elf.shdrSlice()) {
1434 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),
1435 };
1436}
1437
12331438pub const SymtabSlice = union(std.elf.CLASS) {
12341439 NONE: noreturn,
12351440 @"32": []std.elf.Elf32.Sym,
......@@ -1242,7 +1447,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {
12421447 inline else => |class| @unionInit(
12431448 SymtabSlice,
12441449 @tagName(class),
1245 @ptrCast(@alignCast(slice)),
1450 @ptrCast(@alignCast(slice[0..std.mem.alignBackwardAnyAlign(
1451 usize,
1452 slice.len,
1453 @sizeOf(class.ElfN().Sym),
1454 )])),
12461455 ),
12471456 };
12481457}
......@@ -1254,7 +1463,7 @@ pub const SymPtr = union(std.elf.CLASS) {
12541463};
12551464pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
12561465 return switch (elf.symtabSlice()) {
1257 inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]),
1466 inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),
12581467 };
12591468}
12601469
......@@ -1544,7 +1753,7 @@ fn loadObject(
15441753 .si = try elf.initSymbolAssumeCapacity(.{
15451754 .name = std.fs.path.stem(member orelse path.sub_path),
15461755 .type = .FILE,
1547 .shndx = std.elf.SHN_ABS,
1756 .shndx = .ABS,
15481757 }),
15491758 };
15501759 const target_endian = elf.targetEndian();
......@@ -1571,7 +1780,7 @@ fn loadObject(
15711780 };
15721781 try r.discardAll(ehdr.shentsize);
15731782 switch (section.shdr.type) {
1574 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
1783 .NULL, .NOBITS => {},
15751784 else => if (section.shdr.offset + section.shdr.size > fl.size)
15761785 return diags.failParse(path, "bad section location", .{}),
15771786 }
......@@ -1580,8 +1789,7 @@ fn loadObject(
15801789 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
15811790 return diags.failParse(path, "missing section names", .{});
15821791 const shdr = &sections[ehdr.shstrndx].shdr;
1583 if (shdr.type != std.elf.SHT_STRTAB)
1584 return diags.failParse(path, "invalid shstrtab type", .{});
1792 if (shdr.type != .STRTAB) return diags.failParse(path, "invalid shstrtab type", .{});
15851793 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
15861794 errdefer gpa.free(shstrtab);
15871795 try fr.seekTo(fl.offset + shdr.offset);
......@@ -1594,7 +1802,7 @@ fn loadObject(
15941802 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
15951803 for (sections[1..]) |*section| switch (section.shdr.type) {
15961804 else => {},
1597 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {
1805 .PROGBITS, .NOBITS => {
15981806 if (section.shdr.name >= shstrtab.len) continue;
15991807 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
16001808 const parent_si = elf.namedSection(name) orelse continue;
......@@ -1611,7 +1819,7 @@ fn loadObject(
16111819 });
16121820 section.si = try elf.initSymbolAssumeCapacity(.{
16131821 .type = .SECTION,
1614 .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx),
1822 .shndx = parent_si.shndx(elf),
16151823 });
16161824 section.si.get(elf).ni = ni;
16171825 elf.input_sections.addOneAssumeCapacity().* = .{
......@@ -1629,14 +1837,14 @@ fn loadObject(
16291837 defer symmap.deinit(gpa);
16301838 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
16311839 else => {},
1632 std.elf.SHT_SYMTAB => {
1840 .SYMTAB => {
16331841 if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))
16341842 return diags.failParse(path, "unsupported symtab entsize", .{});
16351843 const strtab = strtab: {
16361844 if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)
16371845 return diags.failParse(path, "missing symbol names", .{});
16381846 const shdr = &sections[symtab.shdr.link].shdr;
1639 if (shdr.type != std.elf.SHT_STRTAB)
1847 if (shdr.type != .STRTAB)
16401848 return diags.failParse(path, "invalid strtab type", .{});
16411849 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
16421850 errdefer gpa.free(strtab);
......@@ -1683,9 +1891,7 @@ fn loadObject(
16831891 .type = input_sym.info.type,
16841892 .bind = input_sym.info.bind,
16851893 .visibility = input_sym.other.visibility,
1686 .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) {
1687 inline else => |parent_sym| &parent_sym.shndx,
1688 }),
1894 .shndx = parent_si.shndx(elf),
16891895 });
16901896 si.get(elf).ni = parent_si.get(elf).ni;
16911897 switch (input_sym.info.bind) {
......@@ -1719,13 +1925,13 @@ fn loadObject(
17191925 }
17201926 for (sections[1..]) |*rels| switch (rels.shdr.type) {
17211927 else => {},
1722 inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| {
1928 inline .REL, .RELA => |sht| {
17231929 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
17241930 rels.shdr.info >= ehdr.shnum) continue;
17251931 const Rel = switch (sht) {
17261932 else => comptime unreachable,
1727 std.elf.SHT_REL => ElfN.Rel,
1728 std.elf.SHT_RELA => ElfN.Rela,
1933 .REL => ElfN.Rel,
1934 .RELA => ElfN.Rela,
17291935 };
17301936 if (rels.shdr.entsize < @sizeOf(Rel))
17311937 return diags.failParse(path, "unsupported rel entsize", .{});
......@@ -1740,7 +1946,7 @@ fn loadObject(
17401946 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
17411947 .{ rels.shdr.size, rels.shdr.entsize },
17421948 );
1743 try elf.relocs.ensureUnusedCapacity(gpa, relnum);
1949 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
17441950 try fr.seekTo(fl.offset + rels.shdr.offset);
17451951 for (0..relnum) |_| {
17461952 const rel = try r.peekStruct(Rel, target_endian);
......@@ -1753,18 +1959,7 @@ fn loadObject(
17531959 rel.offset - loc_sec.shdr.addr,
17541960 target_si,
17551961 rel.addend,
1756 switch (elf.ehdrField(.machine)) {
1757 else => unreachable,
1758 inline .AARCH64,
1759 .PPC64,
1760 .RISCV,
1761 .X86_64,
1762 => |machine| @unionInit(
1763 Reloc.Type,
1764 @tagName(machine),
1765 @enumFromInt(rel.info.type),
1766 ),
1767 },
1962 .wrap(rel.info.type, elf),
17681963 );
17691964 }
17701965 },
......@@ -1800,7 +1995,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
18001995 try r.discardAll(ehdr.phentsize);
18011996 switch (ph.type) {
18021997 else => {},
1803 std.elf.PT_DYNAMIC => break ph,
1998 .DYNAMIC => break ph,
18041999 }
18052000 } else return diags.failParse(path, "no dynamic segment", .{});
18062001 const dynnum = std.math.divExact(
......@@ -1817,13 +2012,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
18172012 var soname: ?ElfN.Addr = null;
18182013 try fr.seekTo(dynamic_ph.offset);
18192014 for (0..dynnum) |_| {
1820 const key = try r.takeInt(ElfN.Addr, target_endian);
1821 const value = try r.takeInt(ElfN.Addr, target_endian);
1822 switch (key) {
2015 const tag = try r.takeInt(ElfN.Addr, target_endian);
2016 const val = try r.takeInt(ElfN.Addr, target_endian);
2017 switch (tag) {
18232018 else => {},
1824 std.elf.DT_STRTAB => strtab = value,
1825 std.elf.DT_STRSZ => strsz = value,
1826 std.elf.DT_SONAME => soname = value,
2019 std.elf.DT_STRTAB => strtab = val,
2020 std.elf.DT_STRSZ => strsz = val,
2021 std.elf.DT_SONAME => soname = val,
18272022 }
18282023 }
18292024 if (strtab == null or soname == null)
......@@ -1836,7 +2031,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
18362031 try r.discardAll(ehdr.phentsize);
18372032 switch (ph.type) {
18382033 else => {},
1839 std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and
2034 .LOAD => if (strtab.? >= ph.vaddr and
18402035 strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,
18412036 }
18422037 } else return diags.failParse(path, "strtab not part of a loaded segment", .{});
......@@ -1868,11 +2063,7 @@ fn prelinkInner(elf: *Elf) !void {
18682063 std.fs.path.stem(elf.base.emit.sub_path),
18692064 });
18702065 defer gpa.free(zcu_name);
1871 const si = try elf.initSymbolAssumeCapacity(.{
1872 .name = zcu_name,
1873 .type = .FILE,
1874 .shndx = std.elf.SHN_ABS,
1875 });
2066 const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });
18762067 elf.inputs.addOneAssumeCapacity().* = .{
18772068 .path = elf.base.emit,
18782069 .member = null,
......@@ -1972,63 +2163,87 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
19722163
19732164fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
19742165 name: []const u8 = "",
1975 type: std.elf.Word = std.elf.SHT_NULL,
2166 type: std.elf.SHT = .NULL,
19762167 flags: std.elf.SHF = .{},
1977 size: std.elf.Word = 0,
2168 size: std.elf.Xword = 0,
2169 link: std.elf.Word = 0,
2170 info: std.elf.Word = 0,
19782171 addralign: std.mem.Alignment = .@"1",
19792172 entsize: std.elf.Word = 0,
2173 node_align: std.mem.Alignment = .@"1",
19802174}) !Symbol.Index {
19812175 switch (opts.type) {
1982 std.elf.SHT_NULL => assert(opts.size == 0),
1983 std.elf.SHT_PROGBITS => assert(opts.size > 0),
2176 .NULL => assert(opts.size == 0),
2177 .PROGBITS => assert(opts.size > 0),
19842178 else => {},
19852179 }
19862180 const gpa = elf.base.comp.gpa;
19872181 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2182 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
19882183 try elf.symtab.ensureUnusedCapacity(gpa, 1);
19892184
19902185 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
1991 const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) {
1992 inline else => |ehdr| {
1993 const shndx = elf.targetLoad(&ehdr.shnum);
1994 const shnum = shndx + 1;
1995 elf.targetStore(&ehdr.shnum, shnum);
1996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
2186 const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
2187 inline else => |ehdr, class| {
2188 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
2189 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
2190 const shnum = shndx + 1;
2191 elf.targetStore(&ehdr.shnum, shnum);
2192 break :alloc_shndx .{ shndx, shnum };
2193 },
2194 std.elf.SHN_LORESERVE - 1 => |shndx| {
2195 const shnum = shndx + 1;
2196 elf.targetStore(&ehdr.shnum, 0);
2197 elf.targetStore(&@field(elf.shdrPtr(.UNDEF), @tagName(class)).size, shnum);
2198 break :alloc_shndx .{ shndx, shnum };
2199 },
2200 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => unreachable,
2201 0 => {
2202 const shnum_ptr = &@field(elf.shdrPtr(.UNDEF), @tagName(class)).size;
2203 const shndx: u32 = @intCast(elf.targetLoad(shnum_ptr));
2204 const shnum = shndx + 1;
2205 elf.targetStore(shnum_ptr, shnum);
2206 break :alloc_shndx .{ shndx, shnum };
2207 },
2208 };
2209 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));
2210 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
19972211 },
19982212 };
1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
2000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
2001 .alignment = opts.addralign,
2213 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
2214 if (new_shdr_size > shdr_node_size)
2215 try elf.ni.shdr.resize(&elf.mf, gpa, new_shdr_size +| new_shdr_size / MappedFile.growth_factor);
2216 const ni = try elf.mf.addLastChildNode(gpa, switch (elf.ehdrField(.type)) {
2217 .NONE, .CORE, _ => unreachable,
2218 .REL => elf.ni.file,
2219 .EXEC, .DYN => segment_ni,
2220 }, .{
2221 .alignment = opts.addralign.max(opts.node_align),
20022222 .size = opts.size,
20032223 .resized = opts.size > 0,
20042224 });
20052225 const si = elf.addSymbolAssumeCapacity();
20062226 elf.nodes.appendAssumeCapacity(.{ .section = si });
2227 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
20072228 si.get(elf).ni = ni;
20082229 const addr = elf.computeNodeVAddr(ni);
20092230 const offset = ni.fileLocation(&elf.mf, false).offset;
2010 try si.init(elf, .{
2011 .value = addr,
2012 .size = opts.size,
2013 .type = .SECTION,
2014 .shndx = shndx,
2015 });
2016 switch (elf.shdrSlice()) {
2017 inline else => |shdr| {
2018 const sh = &shdr[shndx];
2019 sh.* = .{
2231 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
2232 switch (elf.shdrPtr(shndx)) {
2233 inline else => |shdr, class| {
2234 shdr.* = .{
20202235 .name = shstrtab_entry,
20212236 .type = opts.type,
20222237 .flags = .{ .shf = opts.flags },
20232238 .addr = @intCast(addr),
20242239 .offset = @intCast(offset),
2025 .size = opts.size,
2026 .link = 0,
2027 .info = 0,
2240 .size = @intCast(opts.size),
2241 .link = opts.link,
2242 .info = opts.info,
20282243 .addralign = @intCast(opts.addralign.toByteUnits()),
20292244 .entsize = opts.entsize,
20302245 };
2031 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh);
2246 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
20322247 },
20332248 }
20342249 return si;
......@@ -2036,39 +2251,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
20362251
20372252fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
20382253 const shstrtab_entry = try elf.string(.shstrtab, name);
2039 switch (elf.shdrSlice()) {
2040 inline else => |shdr, class| elf.targetStore(
2041 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2042 shstrtab_entry,
2043 ),
2254 switch (elf.shdrPtr(si.shndx(elf))) {
2255 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
20442256 }
20452257}
20462258
20472259fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
2048 switch (elf.shdrSlice()) {
2049 inline else => |shdr, class| shdr[
2050 elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)
2051 ].link = @field(elf.symPtr(link_si), @tagName(class)).shndx,
2260 switch (elf.shdrPtr(si.shndx(elf))) {
2261 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
20522262 }
20532263}
20542264
20552265fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2056 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {
2057 inline else => |shndx, class| elf.targetLoad(
2058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2059 ),
2266 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2267 inline else => |shdr| elf.targetLoad(&shdr.name),
20602268 }..];
20612269 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
20622270}
20632271
20642272fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
20652273 if (key.len == 0) return 0;
2066 return @field(elf, @tagName(section)).get(
2067 elf.base.comp.gpa,
2068 &elf.mf,
2069 @field(elf.si, @tagName(section)).node(elf),
2070 key,
2071 );
2274 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
20722275}
20732276
20742277pub fn addReloc(
......@@ -2079,9 +2282,51 @@ pub fn addReloc(
20792282 addend: i64,
20802283 @"type": Reloc.Type,
20812284) !void {
2082 try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1);
2285 try elf.ensureUnusedRelocCapacity(loc_si, 1);
20832286 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
20842287}
2288pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
2289 if (len == 0) return;
2290 const gpa = elf.base.comp.gpa;
2291
2292 try elf.relocs.ensureUnusedCapacity(gpa, len);
2293 if (elf.ehdrField(.type) != .REL) return;
2294
2295 const shndx = loc_si.shndx(elf);
2296 const sh = shndx.get(elf);
2297 if (sh.rela_si == .null) {
2298 var stack = std.heap.stackFallback(32, gpa);
2299 const allocator = stack.get();
2300
2301 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2302 defer allocator.free(rela_name);
2303
2304 const class = elf.identClass();
2305 sh.rela_si = try elf.addSection(.none, .{
2306 .name = rela_name,
2307 .type = .RELA,
2308 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2309 .info = @intFromEnum(shndx),
2310 .addralign = switch (class) {
2311 .NONE, _ => unreachable,
2312 .@"32" => .@"4",
2313 .@"64" => .@"8",
2314 },
2315 .entsize = switch (class) {
2316 .NONE, _ => unreachable,
2317 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2318 },
2319 .node_align = elf.mf.flags.block_size,
2320 });
2321 }
2322 const rela_ni = sh.rela_si.node(elf);
2323 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2324 const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2325 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len,
2326 };
2327 if (rela_size > rela_node_size)
2328 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
2329}
20852330pub fn addRelocAssumeCapacity(
20862331 elf: *Elf,
20872332 loc_si: Symbol.Index,
......@@ -2098,7 +2343,45 @@ pub fn addRelocAssumeCapacity(
20982343 .next = target.target_relocs,
20992344 .loc = loc_si,
21002345 .target = target_si,
2101 .unused = 0,
2346 .index = index: switch (elf.ehdrField(.type)) {
2347 .NONE, .CORE, _ => unreachable,
2348 .REL => {
2349 const sh = loc_si.shndx(elf).get(elf);
2350 switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2351 inline else => |shdr, class| {
2352 const Rela = class.ElfN().Rela;
2353 const ent_size = elf.targetLoad(&shdr.entsize);
2354 const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
2355 const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
2356 const rela: *Rela = @ptrCast(@alignCast(
2357 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2358 ));
2359 sh.rela_free = @enumFromInt(rela.offset);
2360 break :alloc_index index;
2361 } else alloc_index: {
2362 const old_size = elf.targetLoad(&shdr.size);
2363 const new_size = old_size + ent_size;
2364 elf.targetStore(&shdr.size, @intCast(new_size));
2365 break :alloc_index @intCast(@divExact(old_size, ent_size));
2366 };
2367 const rela: *Rela = @ptrCast(@alignCast(
2368 rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
2369 ));
2370 rela.* = .{
2371 .offset = @intCast(offset),
2372 .info = .{
2373 .type = @intCast(@"type".unwrap(elf)),
2374 .sym = @intCast(@intFromEnum(target_si)),
2375 },
2376 .addend = @intCast(addend),
2377 };
2378 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela);
2379 break :index .wrap(index);
2380 },
2381 }
2382 },
2383 .EXEC, .DYN => .none,
2384 },
21022385 .offset = offset,
21032386 .addend = addend,
21042387 };
......@@ -2464,7 +2747,8 @@ fn flushUav(
24642747 switch (sym.ni) {
24652748 .none => {
24662749 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2467 const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{
2750 const sec_si = elf.si.data;
2751 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
24682752 .alignment = uav_align.toStdMem(),
24692753 .moved = true,
24702754 });
......@@ -2472,7 +2756,7 @@ fn flushUav(
24722756 sym.ni = ni;
24732757 switch (elf.symPtr(si)) {
24742758 inline else => |sym_ptr, class| sym_ptr.shndx =
2475 @field(elf.symPtr(.data), @tagName(class)).shndx,
2759 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
24762760 }
24772761 },
24782762 else => {
......@@ -2596,11 +2880,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
25962880 var child_it = ni.children(&elf.mf);
25972881 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
25982882 },
2599 .section => |si| switch (elf.shdrSlice()) {
2600 inline else => |shdr, class| elf.targetStore(
2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
2602 @intCast(ni.fileLocation(&elf.mf, false).offset),
2603 ),
2883 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
2884 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
2885 ni.fileLocation(&elf.mf, false).offset,
2886 )),
26042887 },
26052888 }
26062889}
......@@ -2616,10 +2899,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
26162899 const ph = &phdr[phndx];
26172900 switch (elf.targetLoad(&ph.type)) {
26182901 else => unreachable,
2619 std.elf.PT_NULL, std.elf.PT_LOAD => return,
2620 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
2621 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2622 std.elf.PT_TLS => {},
2902 .NULL, .LOAD => return,
2903 .DYNAMIC, .INTERP => {},
2904 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2905 .TLS => {},
26232906 }
26242907 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
26252908 ph.paddr = ph.vaddr;
......@@ -2629,14 +2912,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
26292912 .section => |si| {
26302913 try elf.flushFileOffset(ni);
26312914 const addr = elf.computeNodeVAddr(ni);
2632 switch (elf.shdrSlice()) {
2915 switch (elf.shdrPtr(si.shndx(elf))) {
26332916 inline else => |shdr, class| {
2634 const sym = @field(elf.symPtr(si), @tagName(class));
2635 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2636 const flags = elf.targetLoad(&sh.flags).shf;
2917 const flags = elf.targetLoad(&shdr.flags).shf;
26372918 if (flags.ALLOC) {
2638 elf.targetStore(&sh.addr, @intCast(addr));
2639 sym.value = sh.addr;
2919 elf.targetStore(&shdr.addr, @intCast(addr));
2920 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
26402921 }
26412922 },
26422923 }
......@@ -2684,22 +2965,18 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
26842965 elf.targetStore(&ph.memsz, @intCast(memsz));
26852966 switch (elf.targetLoad(&ph.type)) {
26862967 else => unreachable,
2687 std.elf.PT_NULL => if (size > 0) elf.targetStore(&ph.type, std.elf.PT_LOAD),
2688 std.elf.PT_LOAD => if (size == 0) elf.targetStore(&ph.type, std.elf.PT_NULL),
2689 std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => return,
2690 std.elf.PT_TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
2968 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
2969 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
2970 .DYNAMIC, .INTERP, .PHDR => return,
2971 .TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
26912972 }
26922973 var vaddr = elf.targetLoad(&ph.vaddr);
26932974 var new_phndx = phndx;
26942975 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
26952976 switch (elf.targetLoad(&next_ph.type)) {
26962977 else => unreachable,
2697 std.elf.PT_NULL, std.elf.PT_LOAD => {},
2698 std.elf.PT_DYNAMIC,
2699 std.elf.PT_INTERP,
2700 std.elf.PT_PHDR,
2701 std.elf.PT_TLS,
2702 => break,
2978 .NULL, .LOAD => {},
2979 .DYNAMIC, .INTERP, .PHDR, .TLS => break,
27032980 }
27042981 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
27052982 if (vaddr + memsz <= next_vaddr) break;
......@@ -2721,20 +2998,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
27212998 }
27222999 },
27233000 },
2724 .section => |si| switch (elf.symPtr(si)) {
2725 inline else => |sym, class| {
2726 const sh = &@field(elf.shdrSlice(), @tagName(class))[elf.targetLoad(&sym.shndx)];
2727 elf.targetStore(&sh.size, @intCast(size));
2728 switch (elf.targetLoad(&sh.type)) {
3001 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
3002 inline else => |shdr| {
3003 switch (elf.targetLoad(&shdr.type)) {
27293004 else => unreachable,
2730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
2731 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),
2732 std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore(
2733 &sh.info,
2734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
2735 ),
2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
3005 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
3006 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
3007 .SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return,
27373008 }
3009 elf.targetStore(&shdr.size, @intCast(size));
27383010 },
27393011 },
27403012 .input_section => {},
......@@ -2860,6 +3132,26 @@ pub fn printNode(
28603132 try w.writeAll(@tagName(node));
28613133 switch (node) {
28623134 else => {},
3135 .segment => |phndx| switch (elf.phdrSlice()) {
3136 inline else => |phdr| {
3137 const ph = &phdr[phndx];
3138 try w.writeByte('(');
3139 const pt = elf.targetLoad(&ph.type);
3140 if (std.enums.tagName(std.elf.PT, pt)) |pt_name|
3141 try w.writeAll(pt_name)
3142 else inline for (@typeInfo(std.elf.PT).@"enum".decls) |decl| {
3143 const decl_val = @field(std.elf.PT, decl.name);
3144 if (@TypeOf(decl_val) != std.elf.PT) continue;
3145 if (pt == @field(std.elf.PT, decl.name)) break try w.writeAll(decl.name);
3146 } else try w.print("0x{x}", .{pt});
3147 try w.writeAll(", ");
3148 const pf = elf.targetLoad(&ph.flags);
3149 if (pf.R) try w.writeByte('R');
3150 if (pf.W) try w.writeByte('W');
3151 if (pf.X) try w.writeByte('X');
3152 try w.writeByte(')');
3153 },
3154 },
28633155 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
28643156 .input_section => |isi| {
28653157 const ii = isi.input(elf);
src/link/MappedFile.zig+12-25
......@@ -486,6 +486,14 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
486486 break :free .{ free_ni, free_node };
487487 },
488488 };
489 switch (opts.prev) {
490 .none => opts.parent.get(mf).first = free_ni,
491 else => |prev_ni| prev_ni.get(mf).next = free_ni,
492 }
493 switch (opts.next) {
494 .none => opts.parent.get(mf).last = free_ni,
495 else => |next_ni| next_ni.get(mf).prev = free_ni,
496 }
489497 free_node.* = .{
490498 .parent = opts.parent,
491499 .prev = opts.prev,
......@@ -535,13 +543,10 @@ pub fn addOnlyChildNode(
535543 try mf.nodes.ensureUnusedCapacity(gpa, 1);
536544 const parent = parent_ni.get(mf);
537545 assert(parent.first == .none and parent.last == .none);
538 const ni = try mf.addNode(gpa, .{
546 return mf.addNode(gpa, .{
539547 .parent = parent_ni,
540548 .add_node = opts,
541549 });
542 parent.first = ni;
543 parent.last = ni;
544 return ni;
545550}
546551
547552pub fn addFirstChildNode(
......@@ -552,17 +557,11 @@ pub fn addFirstChildNode(
552557) !Node.Index {
553558 try mf.nodes.ensureUnusedCapacity(gpa, 1);
554559 const parent = parent_ni.get(mf);
555 const ni = try mf.addNode(gpa, .{
560 return mf.addNode(gpa, .{
556561 .parent = parent_ni,
557562 .next = parent.first,
558563 .add_node = opts,
559564 });
560 switch (parent.first) {
561 .none => parent.last = ni,
562 else => |first_ni| first_ni.get(mf).prev = ni,
563 }
564 parent.first = ni;
565 return ni;
566565}
567566
568567pub fn addLastChildNode(
......@@ -573,7 +572,7 @@ pub fn addLastChildNode(
573572) !Node.Index {
574573 try mf.nodes.ensureUnusedCapacity(gpa, 1);
575574 const parent = parent_ni.get(mf);
576 const ni = try mf.addNode(gpa, .{
575 return mf.addNode(gpa, .{
577576 .parent = parent_ni,
578577 .prev = parent.last,
579578 .offset = offset: switch (parent.last) {
......@@ -585,12 +584,6 @@ pub fn addLastChildNode(
585584 },
586585 .add_node = opts,
587586 });
588 switch (parent.last) {
589 .none => parent.first = ni,
590 else => |last_ni| last_ni.get(mf).next = ni,
591 }
592 parent.last = ni;
593 return ni;
594587}
595588
596589pub fn addNodeAfter(
......@@ -603,19 +596,13 @@ pub fn addNodeAfter(
603596 try mf.nodes.ensureUnusedCapacity(gpa, 1);
604597 const prev = prev_ni.get(mf);
605598 const prev_offset, const prev_size = prev.location().resolve(mf);
606 const ni = try mf.addNode(gpa, .{
599 return mf.addNode(gpa, .{
607600 .parent = prev.parent,
608601 .prev = prev_ni,
609602 .next = prev.next,
610603 .offset = prev_offset + prev_size,
611604 .add_node = opts,
612605 });
613 switch (prev.next) {
614 .none => prev.parent.get(mf).last = ni,
615 else => |next_ni| next_ni.get(mf).prev = ni,
616 }
617 prev.next = ni;
618 return ni;
619606}
620607
621608fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {