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) {...@@ -3971,7 +3971,7 @@ pub const dl_phdr_info = switch (native_os) {
3971 /// Module name.3971 /// Module name.
3972 name: ?[*:0]const u8,3972 name: ?[*:0]const u8,
3973 /// Pointer to module's phdr.3973 /// Pointer to module's phdr.
3974 phdr: [*]std.elf.Phdr,3974 phdr: [*]std.elf.ElfN.Phdr,
3975 /// Number of entries in phdr.3975 /// Number of entries in phdr.
3976 phnum: u16,3976 phnum: u16,
3977 /// Total number of loads.3977 /// Total number of loads.
...@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {...@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {
3984 .illumos => extern struct {3984 .illumos => extern struct {
3985 addr: std.elf.Addr,3985 addr: std.elf.Addr,
3986 name: ?[*:0]const u8,3986 name: ?[*:0]const u8,
3987 phdr: [*]std.elf.Phdr,3987 phdr: [*]std.elf.ElfN.Phdr,
3988 phnum: std.elf.Half,3988 phnum: std.elf.Half,
3989 /// Incremented when a new object is mapped into the process.3989 /// Incremented when a new object is mapped into the process.
3990 adds: u64,3990 adds: u64,
...@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {...@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {
3995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {3995 .openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {
3996 addr: usize,3996 addr: usize,
3997 name: ?[*:0]const u8,3997 name: ?[*:0]const u8,
3998 phdr: [*]std.elf.Phdr,3998 phdr: [*]std.elf.ElfN.Phdr,
3999 phnum: std.elf.Half,3999 phnum: std.elf.Half,
4000 },4000 },
4001 else => void,4001 else => void,
lib/std/debug/SelfInfo/Elf.zig+10-10
...@@ -441,11 +441,11 @@ const DlIterContext = struct {...@@ -441,11 +441,11 @@ const DlIterContext = struct {
441441
442 // Populate `build_id` and `gnu_eh_frame`442 // Populate `build_id` and `gnu_eh_frame`
443 for (info.phdr[0..info.phnum]) |phdr| {443 for (info.phdr[0..info.phnum]) |phdr| {
444 switch (phdr.p_type) {444 switch (phdr.type) {
445 std.elf.PT_NOTE => {445 .NOTE => {
446 // Look for .note.gnu.build-id446 // Look for .note.gnu.build-id
447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);447 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.p_memsz]);448 var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.memsz]);
449 const name_size = r.takeInt(u32, native_endian) catch continue;449 const name_size = r.takeInt(u32, native_endian) catch continue;
450 const desc_size = r.takeInt(u32, native_endian) catch continue;450 const desc_size = r.takeInt(u32, native_endian) catch continue;
451 const note_type = r.takeInt(u32, native_endian) catch continue;451 const note_type = r.takeInt(u32, native_endian) catch continue;
...@@ -455,9 +455,9 @@ const DlIterContext = struct {...@@ -455,9 +455,9 @@ const DlIterContext = struct {
455 const desc = r.take(desc_size) catch continue;455 const desc = r.take(desc_size) catch continue;
456 build_id = desc;456 build_id = desc;
457 },457 },
458 std.elf.PT_GNU_EH_FRAME => {458 std.elf.PT.GNU_EH_FRAME => {
459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);459 const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
460 gnu_eh_frame = segment_ptr[0..phdr.p_memsz];460 gnu_eh_frame = segment_ptr[0..phdr.memsz];
461 },461 },
462 else => {},462 else => {},
463 }463 }
...@@ -478,11 +478,11 @@ const DlIterContext = struct {...@@ -478,11 +478,11 @@ const DlIterContext = struct {
478 });478 });
479479
480 for (info.phdr[0..info.phnum]) |phdr| {480 for (info.phdr[0..info.phnum]) |phdr| {
481 if (phdr.p_type != std.elf.PT_LOAD) continue;481 if (phdr.type != .LOAD) continue;
482 try context.si.ranges.append(gpa, .{482 try context.si.ranges.append(gpa, .{
483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000483 // Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000
484 .start = info.addr +% phdr.p_vaddr,484 .start = info.addr +% phdr.vaddr,
485 .len = phdr.p_memsz,485 .len = phdr.memsz,
486 .module_index = module_index,486 .module_index = module_index,
487 });487 });
488 }488 }
lib/std/dynamic_library.zig+1-2
...@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {...@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
92 });92 });
93}93}
9494
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {95pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
96 _ = phdrs;
97 const _DYNAMIC = get_DYNAMIC() orelse {96 const _DYNAMIC = get_DYNAMIC() orelse {
98 // No PT_DYNAMIC means this is a statically-linked non-PIE program.97 // No PT_DYNAMIC means this is a statically-linked non-PIE program.
99 return .{ .current = null };98 return .{ .current = null };
lib/std/elf.zig+228-100
...@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;...@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;
50pub const AT_L2_CACHEGEOMETRY = 45;50pub const AT_L2_CACHEGEOMETRY = 45;
51pub const AT_L3_CACHESIZE = 46;51pub const AT_L3_CACHESIZE = 46;
52pub const AT_L3_CACHEGEOMETRY = 47;52pub const AT_L3_CACHEGEOMETRY = 47;
53pub const AT_MINSIGSTKSZ = 51;
5354
54pub const DT_NULL = 0;55pub const DT_NULL = 0;
55pub const DT_NEEDED = 1;56pub const DT_NEEDED = 1;
...@@ -286,105 +287,111 @@ pub const VER_FLG_BASE = 1;...@@ -286,105 +287,111 @@ pub const VER_FLG_BASE = 1;
286/// Weak version identifier287/// Weak version identifier
287pub const VER_FLG_WEAK = 2;288pub const VER_FLG_WEAK = 2;
288289
289/// Program header table entry unused290/// Deprecated, use `@intFromEnum(std.elf.PT.NULL)`
290pub const PT_NULL = 0;291pub const PT_NULL = @intFromEnum(std.elf.PT.NULL);
291/// Loadable program segment292/// Deprecated, use `@intFromEnum(std.elf.PT.LOAD)`
292pub const PT_LOAD = 1;293pub const PT_LOAD = @intFromEnum(std.elf.PT.LOAD);
293/// Dynamic linking information294/// Deprecated, use `@intFromEnum(std.elf.PT.DYNAMIC)`
294pub const PT_DYNAMIC = 2;295pub const PT_DYNAMIC = @intFromEnum(std.elf.PT.DYNAMIC);
295/// Program interpreter296/// Deprecated, use `@intFromEnum(std.elf.PT.INTERP)`
296pub const PT_INTERP = 3;297pub const PT_INTERP = @intFromEnum(std.elf.PT.INTERP);
297/// Auxiliary information298/// Deprecated, use `@intFromEnum(std.elf.PT.NOTE)`
298pub const PT_NOTE = 4;299pub const PT_NOTE = @intFromEnum(std.elf.PT.NOTE);
299/// Reserved300/// Deprecated, use `@intFromEnum(std.elf.PT.SHLIB)`
300pub const PT_SHLIB = 5;301pub const PT_SHLIB = @intFromEnum(std.elf.PT.SHLIB);
301/// Entry for header table itself302/// Deprecated, use `@intFromEnum(std.elf.PT.PHDR)`
302pub const PT_PHDR = 6;303pub const PT_PHDR = @intFromEnum(std.elf.PT.PHDR);
303/// Thread-local storage segment304/// Deprecated, use `@intFromEnum(std.elf.PT.TLS)`
304pub const PT_TLS = 7;305pub const PT_TLS = @intFromEnum(std.elf.PT.TLS);
305/// Number of defined types306/// Deprecated, use `std.elf.PT.NUM`.
306pub const PT_NUM = 8;307pub const PT_NUM = PT.NUM;
307/// Start of OS-specific308/// Deprecated, use `@intFromEnum(std.elf.PT.LOOS)`
308pub const PT_LOOS = 0x60000000;309pub const PT_LOOS = @intFromEnum(std.elf.PT.LOOS);
309/// GCC .eh_frame_hdr segment310/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_EH_FRAME)`
310pub const PT_GNU_EH_FRAME = 0x6474e550;311pub const PT_GNU_EH_FRAME = @intFromEnum(std.elf.PT.GNU_EH_FRAME);
311/// Indicates stack executability312/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_STACK)`
312pub const PT_GNU_STACK = 0x6474e551;313pub const PT_GNU_STACK = @intFromEnum(std.elf.PT.GNU_STACK);
313/// Read-only after relocation314/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_RELRO)`
314pub const PT_GNU_RELRO = 0x6474e552;315pub const PT_GNU_RELRO = @intFromEnum(std.elf.PT.GNU_RELRO);
315pub const PT_LOSUNW = 0x6ffffffa;316/// Deprecated, use `@intFromEnum(std.elf.PT.LOSUNW)`
316/// Sun specific segment317pub const PT_LOSUNW = @intFromEnum(std.elf.PT.LOSUNW);
317pub const PT_SUNWBSS = 0x6ffffffa;318/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWBSS)`
318/// Stack segment319pub const PT_SUNWBSS = @intFromEnum(std.elf.PT.SUNWBSS);
319pub const PT_SUNWSTACK = 0x6ffffffb;320/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWSTACK)`
320pub const PT_HISUNW = 0x6fffffff;321pub const PT_SUNWSTACK = @intFromEnum(std.elf.PT.SUNWSTACK);
321/// End of OS-specific322/// Deprecated, use `@intFromEnum(std.elf.PT.HISUNW)`
322pub const PT_HIOS = 0x6fffffff;323pub const PT_HISUNW = @intFromEnum(std.elf.PT.HISUNW);
323/// Start of processor-specific324/// Deprecated, use `@intFromEnum(std.elf.PT.HIOS)`
324pub const PT_LOPROC = 0x70000000;325pub const PT_HIOS = @intFromEnum(std.elf.PT.HIOS);
325/// End of processor-specific326/// Deprecated, use `@intFromEnum(std.elf.PT.LOPROC)`
326pub const PT_HIPROC = 0x7fffffff;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
328pub const PN_XNUM = 0xffff;331pub const PN_XNUM = 0xffff;
329332
330/// Section header table entry unused333/// Deprecated, use `@intFromEnum(std.elf.SHT.NULL)`
331pub const SHT_NULL = 0;334pub const SHT_NULL = @intFromEnum(std.elf.SHT.NULL);
332/// Program data335/// Deprecated, use `@intFromEnum(std.elf.SHT.PROGBITS)`
333pub const SHT_PROGBITS = 1;336pub const SHT_PROGBITS = @intFromEnum(std.elf.SHT.PROGBITS);
334/// Symbol table337/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB)`
335pub const SHT_SYMTAB = 2;338pub const SHT_SYMTAB = @intFromEnum(std.elf.SHT.SYMTAB);
336/// String table339/// Deprecated, use `@intFromEnum(std.elf.SHT.STRTAB)`
337pub const SHT_STRTAB = 3;340pub const SHT_STRTAB = @intFromEnum(std.elf.SHT.STRTAB);
338/// Relocation entries with addends341/// Deprecated, use `@intFromEnum(std.elf.SHT.RELA)`
339pub const SHT_RELA = 4;342pub const SHT_RELA = @intFromEnum(std.elf.SHT.RELA);
340/// Symbol hash table343/// Deprecated, use `@intFromEnum(std.elf.SHT.HASH)`
341pub const SHT_HASH = 5;344pub const SHT_HASH = @intFromEnum(std.elf.SHT.HASH);
342/// Dynamic linking information345/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNAMIC)`
343pub const SHT_DYNAMIC = 6;346pub const SHT_DYNAMIC = @intFromEnum(std.elf.SHT.DYNAMIC);
344/// Notes347/// Deprecated, use `@intFromEnum(std.elf.SHT.NOTE)`
345pub const SHT_NOTE = 7;348pub const SHT_NOTE = @intFromEnum(std.elf.SHT.NOTE);
346/// Program space with no data (bss)349/// Deprecated, use `@intFromEnum(std.elf.SHT.NOBITS)`
347pub const SHT_NOBITS = 8;350pub const SHT_NOBITS = @intFromEnum(std.elf.SHT.NOBITS);
348/// Relocation entries, no addends351/// Deprecated, use `@intFromEnum(std.elf.SHT.REL)`
349pub const SHT_REL = 9;352pub const SHT_REL = @intFromEnum(std.elf.SHT.REL);
350/// Reserved353/// Deprecated, use `@intFromEnum(std.elf.SHT.SHLIB)`
351pub const SHT_SHLIB = 10;354pub const SHT_SHLIB = @intFromEnum(std.elf.SHT.SHLIB);
352/// Dynamic linker symbol table355/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNSYM)`
353pub const SHT_DYNSYM = 11;356pub const SHT_DYNSYM = @intFromEnum(std.elf.SHT.DYNSYM);
354/// Array of constructors357/// Deprecated, use `@intFromEnum(std.elf.SHT.INIT_ARRAY)`
355pub const SHT_INIT_ARRAY = 14;358pub const SHT_INIT_ARRAY = @intFromEnum(std.elf.SHT.INIT_ARRAY);
356/// Array of destructors359/// Deprecated, use `@intFromEnum(std.elf.SHT.FINI_ARRAY)`
357pub const SHT_FINI_ARRAY = 15;360pub const SHT_FINI_ARRAY = @intFromEnum(std.elf.SHT.FINI_ARRAY);
358/// Array of pre-constructors361/// Deprecated, use `@intFromEnum(std.elf.SHT.PREINIT_ARRAY)`
359pub const SHT_PREINIT_ARRAY = 16;362pub const SHT_PREINIT_ARRAY = @intFromEnum(std.elf.SHT.PREINIT_ARRAY);
360/// Section group363/// Deprecated, use `@intFromEnum(std.elf.SHT.GROUP)`
361pub const SHT_GROUP = 17;364pub const SHT_GROUP = @intFromEnum(std.elf.SHT.GROUP);
362/// Extended section indices365/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB_SHNDX)`
363pub const SHT_SYMTAB_SHNDX = 18;366pub const SHT_SYMTAB_SHNDX = @intFromEnum(std.elf.SHT.SYMTAB_SHNDX);
364/// Start of OS-specific367/// Deprecated, use `@intFromEnum(std.elf.SHT.RELR)`
365pub const SHT_LOOS = 0x60000000;368pub const SHT_RELR = @intFromEnum(std.elf.SHT.RELR);
366/// LLVM address-significance table369/// Deprecated, use `std.elf.SHT.NUM`.
367pub const SHT_LLVM_ADDRSIG = 0x6fff4c03;370pub const SHT_NUM = SHT.NUM;
368/// GNU hash table371/// Deprecated, use `@intFromEnum(std.elf.SHT.LOOS)`
369pub const SHT_GNU_HASH = 0x6ffffff6;372pub const SHT_LOOS = @intFromEnum(std.elf.SHT.LOOS);
370/// GNU version definition table373/// Deprecated, use `@intFromEnum(std.elf.SHT.LLVM_ADDRSIG)`
371pub const SHT_GNU_VERDEF = 0x6ffffffd;374pub const SHT_LLVM_ADDRSIG = @intFromEnum(std.elf.SHT.LLVM_ADDRSIG);
372/// GNU needed versions table375/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_HASH)`
373pub const SHT_GNU_VERNEED = 0x6ffffffe;376pub const SHT_GNU_HASH = @intFromEnum(std.elf.SHT.GNU_HASH);
374/// GNU symbol version table377/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERDEF)`
375pub const SHT_GNU_VERSYM = 0x6fffffff;378pub const SHT_GNU_VERDEF = @intFromEnum(std.elf.SHT.GNU_VERDEF);
376/// End of OS-specific379/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERNEED)`
377pub const SHT_HIOS = 0x6fffffff;380pub const SHT_GNU_VERNEED = @intFromEnum(std.elf.SHT.GNU_VERNEED);
378/// Start of processor-specific381/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERSYM)`
379pub const SHT_LOPROC = 0x70000000;382pub const SHT_GNU_VERSYM = @intFromEnum(std.elf.SHT.GNU_VERSYM);
380/// Unwind information383/// Deprecated, use `@intFromEnum(std.elf.SHT.HIOS)`
381pub const SHT_X86_64_UNWIND = 0x70000001;384pub const SHT_HIOS = @intFromEnum(std.elf.SHT.HIOS);
382/// End of processor-specific385/// Deprecated, use `@intFromEnum(std.elf.SHT.LOPROC)`
383pub const SHT_HIPROC = 0x7fffffff;386pub const SHT_LOPROC = @intFromEnum(std.elf.SHT.LOPROC);
384/// Start of application-specific387/// Deprecated, use `@intFromEnum(std.elf.SHT.X86_64_UNWIND)`
385pub const SHT_LOUSER = 0x80000000;388pub const SHT_X86_64_UNWIND = @intFromEnum(std.elf.SHT.X86_64_UNWIND);
386/// End of application-specific389/// Deprecated, use `@intFromEnum(std.elf.SHT.HIPROC)`
387pub const SHT_HIUSER = 0xffffffff;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
389// Note type for .note.gnu.build_id396// Note type for .note.gnu.build_id
390pub const NT_GNU_BUILD_ID = 3;397pub const NT_GNU_BUILD_ID = 3;
...@@ -454,6 +461,127 @@ pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC);...@@ -454,6 +461,127 @@ pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC);
454/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)`461/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)`
455pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT);462pub 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
457pub const STB = enum(u4) {585pub const STB = enum(u4) {
458 /// Local symbol586 /// Local symbol
459 LOCAL = 0,587 LOCAL = 0,
...@@ -899,7 +1027,7 @@ pub const Elf32 = struct {...@@ -899,7 +1027,7 @@ pub const Elf32 = struct {
899 shstrndx: Half,1027 shstrndx: Half,
900 };1028 };
901 pub const Phdr = extern struct {1029 pub const Phdr = extern struct {
902 type: Word,1030 type: PT,
903 offset: Elf32.Off,1031 offset: Elf32.Off,
904 vaddr: Elf32.Addr,1032 vaddr: Elf32.Addr,
905 paddr: Elf32.Addr,1033 paddr: Elf32.Addr,
...@@ -910,7 +1038,7 @@ pub const Elf32 = struct {...@@ -910,7 +1038,7 @@ pub const Elf32 = struct {
910 };1038 };
911 pub const Shdr = extern struct {1039 pub const Shdr = extern struct {
912 name: Word,1040 name: Word,
913 type: Word,1041 type: SHT,
914 flags: packed struct { shf: SHF },1042 flags: packed struct { shf: SHF },
915 addr: Elf32.Addr,1043 addr: Elf32.Addr,
916 offset: Elf32.Off,1044 offset: Elf32.Off,
...@@ -989,7 +1117,7 @@ pub const Elf64 = struct {...@@ -989,7 +1117,7 @@ pub const Elf64 = struct {
989 shstrndx: Half,1117 shstrndx: Half,
990 };1118 };
991 pub const Phdr = extern struct {1119 pub const Phdr = extern struct {
992 type: Word,1120 type: PT,
993 flags: PF,1121 flags: PF,
994 offset: Elf64.Off,1122 offset: Elf64.Off,
995 vaddr: Elf64.Addr,1123 vaddr: Elf64.Addr,
...@@ -1000,7 +1128,7 @@ pub const Elf64 = struct {...@@ -1000,7 +1128,7 @@ pub const Elf64 = struct {
1000 };1128 };
1001 pub const Shdr = extern struct {1129 pub const Shdr = extern struct {
1002 name: Word,1130 name: Word,
1003 type: Word,1131 type: SHT,
1004 flags: packed struct { shf: SHF, unused: Word = 0 },1132 flags: packed struct { shf: SHF, unused: Word = 0 },
1005 addr: Elf64.Addr,1133 addr: Elf64.Addr,
1006 offset: Elf64.Off,1134 offset: Elf64.Off,
lib/std/os/linux.zig+1-1
...@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {...@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {
6101pub const dl_phdr_info = extern struct {6101pub const dl_phdr_info = extern struct {
6102 addr: usize,6102 addr: usize,
6103 name: ?[*:0]const u8,6103 name: ?[*:0]const u8,
6104 phdr: [*]std.elf.Phdr,6104 phdr: [*]std.elf.ElfN.Phdr,
6105 phnum: u16,6105 phnum: u16,
6106};6106};
61076107
lib/std/posix.zig+30-39
...@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {...@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
5048 }5048 }
5049}5049}
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
5051pub fn dl_iterate_phdr(5058pub fn dl_iterate_phdr(
5052 context: anytype,5059 context: anytype,
5053 comptime Error: type,5060 comptime Error: type,
...@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(...@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(
5075 }5082 }
5076 }5083 }
50775084
5078 const elf_base = std.process.getBaseAddress();5085 var it = dl.linkmap_iterator() catch unreachable;
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;
50865086
5087 // The executable has no dynamic link segment, create a single entry for5087 // The executable has no dynamic link segment, create a single entry for
5088 // the whole ELF image.5088 // the whole ELF image.
5089 if (it.end()) {5089 if (it.end()) {
5090 // Find the base address for the ELF image, if this is a PIE the value5090 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
5091 // is non-zero.5091 const phdrs = getSelfPhdrs();
5092 const base_address = for (phdrs) |*phdr| {5092 var info: dl_phdr_info = .{
5093 if (phdr.p_type == elf.PT_PHDR) {5093 .addr = for (phdrs) |phdr| switch (phdr.type) {
5094 break @intFromPtr(phdrs.ptr) - phdr.p_vaddr;5094 .PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr,
5095 // We could try computing the difference between _DYNAMIC and5095 else => {},
5096 // the p_vaddr of the PT_DYNAMIC section, but using the phdr is5096 } else unreachable,
5097 // good enough (Is it?).5097 .name = switch (getauxval(std.elf.AT_EXECFN)) {
5098 }5098 0 => "/proc/self/exe",
5099 } else unreachable;5099 else => |name| @ptrFromInt(name),
51005100 },
5101 var info = dl_phdr_info{
5102 .addr = base_address,
5103 .name = "/proc/self/exe",
5104 .phdr = phdrs.ptr,5101 .phdr = phdrs.ptr,
5105 .phnum = ehdr.e_phnum,5102 .phnum = @intCast(phdrs.len),
5106 };5103 };
51075104
5108 return callback(&info, @sizeOf(dl_phdr_info), context);5105 return callback(&info, @sizeOf(dl_phdr_info), context);
...@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(...@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(
51105107
5111 // Last return value from the callback function.5108 // Last return value from the callback function.
5112 while (it.next()) |entry| {5109 while (it.next()) |entry| {
5113 var phdr: [*]elf.Phdr = undefined;5110 const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
5114 var phnum: u16 = undefined;5111 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
51155112 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
5116 if (entry.l_addr != 0) {5113 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
5117 const elf_header: *elf.Ehdr = @ptrFromInt(entry.l_addr);5114 break :phdrs phdrs[0..ehdr.phnum];
5118 phdr = @ptrFromInt(entry.l_addr + elf_header.e_phoff);5115 } else getSelfPhdrs();
5119 phnum = elf_header.e_phnum;5116
5120 } else {5117 var info: dl_phdr_info = .{
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{
5127 .addr = entry.l_addr,5118 .addr = entry.l_addr,
5128 .name = entry.l_name,5119 .name = entry.l_name,
5129 .phdr = phdr,5120 .phdr = phdrs.ptr,
5130 .phnum = phnum,5121 .phnum = @intCast(phdrs.len),
5131 };5122 };
51325123
5133 try callback(&info, @sizeOf(dl_phdr_info), context);5124 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 {...@@ -257,11 +257,11 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
257 while (i < info.phnum) : (i += 1) {257 while (i < info.phnum) : (i += 1) {
258 const phdr = info.phdr[i];258 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;
263 // Find the ELF header263 // 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));
265 // Validate the magic265 // Validate the magic
266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;266 if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
267 // Consistency check267 // Consistency check
lib/std/process.zig+7-7
...@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI...@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI
1658pub fn getBaseAddress() usize {1658pub fn getBaseAddress() usize {
1659 switch (native_os) {1659 switch (native_os) {
1660 .linux => {1660 .linux => {
1661 const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;1661 const phdrs = std.posix.getSelfPhdrs();
1662 const base = getauxval(std.elf.AT_BASE);1662 var base: usize = 0;
1663 if (base != 0) {1663 for (phdrs) |phdr| switch (phdr.type) {
1664 return base;1664 .LOAD => return base + phdr.vaddr,
1665 }1665 .PHDR => base = @intFromPtr(phdrs.ptr) - phdr.vaddr,
1666 const phdr = getauxval(std.elf.AT_PHDR);1666 else => {},
1667 return phdr - @sizeOf(std.elf.Ehdr);1667 } else unreachable;
1668 },1668 },
1669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {1669 .driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
1670 return @intFromPtr(&std.c._mh_execute_header);1670 return @intFromPtr(&std.c._mh_execute_header);
src/link/Elf2.zig+682-390
...@@ -3,6 +3,7 @@ options: link.File.OpenOptions,...@@ -3,6 +3,7 @@ options: link.File.OpenOptions,
3mf: MappedFile,3mf: MappedFile,
4ni: Node.Known,4ni: Node.Known,
5nodes: std.MultiArrayList(Node),5nodes: std.MultiArrayList(Node),
6shdrs: std.ArrayList(Section),
6phdrs: std.ArrayList(MappedFile.Node.Index),7phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,8si: Symbol.Known,
8symtab: std.ArrayList(Symbol),9symtab: std.ArrayList(Symbol),
...@@ -163,9 +164,29 @@ pub const Node = union(enum) {...@@ -163,9 +164,29 @@ pub const Node = union(enum) {
163 }164 }
164};165};
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
166pub const StringTable = struct {188pub const StringTable = struct {
167 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),189 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
168 size: u32,
169190
170 const Context = struct {191 const Context = struct {
171 slice: []const u8,192 slice: []const u8,
...@@ -193,14 +214,10 @@ pub const StringTable = struct {...@@ -193,14 +214,10 @@ pub const StringTable = struct {
193 }214 }
194 };215 };
195216
196 pub fn get(217 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
197 st: *StringTable,218 const gpa = elf.base.comp.gpa;
198 gpa: std.mem.Allocator,219 const ni = si.node(elf);
199 mf: *MappedFile,220 const slice_const = ni.sliceConst(&elf.mf);
200 ni: MappedFile.Node.Index,
201 key: []const u8,
202 ) !u32 {
203 const slice_const = ni.sliceConst(mf);
204 const gop = try st.map.getOrPutContextAdapted(221 const gop = try st.map.getOrPutContextAdapted(
205 gpa,222 gpa,
206 key,223 key,
...@@ -208,11 +225,18 @@ pub const StringTable = struct {...@@ -208,11 +225,18 @@ pub const StringTable = struct {
208 .{ .slice = slice_const },225 .{ .slice = slice_const },
209 );226 );
210 if (gop.found_existing) return gop.key_ptr.*;227 if (gop.found_existing) return gop.key_ptr.*;
211 const old_size = st.size;228 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
212 const new_size: u32 = @intCast(old_size + key.len + 1);229 inline else => |shdr| {
213 st.size = new_size;230 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
214 try ni.resize(mf, gpa, new_size);231 const new_size: u32 = @intCast(old_size + key.len + 1);
215 const slice = ni.slice(mf)[old_size..];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..];
216 @memcpy(slice[0..key.len], key);240 @memcpy(slice[0..key.len], key);
217 slice[key.len] = 0;241 slice[key.len] = 0;
218 gop.key_ptr.* = old_size;242 gop.key_ptr.* = old_size;
...@@ -226,7 +250,7 @@ pub const Symbol = struct {...@@ -226,7 +250,7 @@ pub const Symbol = struct {
226 loc_relocs: Reloc.Index,250 loc_relocs: Reloc.Index,
227 /// Relocations targeting this symbol251 /// Relocations targeting this symbol
228 target_relocs: Reloc.Index,252 target_relocs: Reloc.Index,
229 unused: u32 = 0,253 unused: u32,
230254
231 pub const Index = enum(u32) {255 pub const Index = enum(u32) {
232 null,256 null,
...@@ -252,6 +276,52 @@ pub const Symbol = struct {...@@ -252,6 +276,52 @@ pub const Symbol = struct {
252 return @enumFromInt(@intFromEnum(si) + 1);276 return @enumFromInt(@intFromEnum(si) + 1);
253 }277 }
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
255 pub const InitOptions = struct {325 pub const InitOptions = struct {
256 name: []const u8 = "",326 name: []const u8 = "",
257 lib_name: ?[]const u8 = null,327 lib_name: ?[]const u8 = null,
...@@ -260,48 +330,83 @@ pub const Symbol = struct {...@@ -260,48 +330,83 @@ pub const Symbol = struct {
260 type: std.elf.STT,330 type: std.elf.STT,
261 bind: std.elf.STB = .LOCAL,331 bind: std.elf.STB = .LOCAL,
262 visibility: std.elf.STV = .DEFAULT,332 visibility: std.elf.STV = .DEFAULT,
263 shndx: std.elf.Section = std.elf.SHN_UNDEF,333 shndx: Shndx = .UNDEF,
264 };334 };
265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {335 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
266 const gpa = elf.base.comp.gpa;336 const gpa = elf.base.comp.gpa;
267 const target_endian = elf.targetEndian();337 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 };
272 const name_strtab_entry = try elf.string(.strtab, opts.name);338 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 }
274 switch (elf.symPtr(si)) {356 switch (elf.symPtr(si)) {
275 inline else => |sym, class| {357 inline else => |sym, class| {
358 const Sym = class.ElfN().Sym;
276 sym.* = .{359 sym.* = .{
277 .name = name_strtab_entry,360 .name = name_strtab_entry,
278 .value = @intCast(opts.value),361 .value = @intCast(opts.value),
279 .size = @intCast(opts.size),362 .size = @intCast(opts.size),
280 .info = .{ .type = opts.type, .bind = opts.bind },363 .info = .{ .type = opts.type, .bind = opts.bind },
281 .other = .{ .visibility = opts.visibility },364 .other = .{ .visibility = opts.visibility },
282 .shndx = opts.shndx,365 .shndx = opts.shndx.toSection().?,
283 };366 };
284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);367 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym);
285 },368 },
286 }369 }
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 }
287 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;376 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
288 const dsi = elf.dynsym.items.len;377 const dsi = elf.dynsym.items.len;
289 try elf.dynsym.append(gpa, si);378 try elf.dynsym.append(gpa, si);
290 const dynsym_ni = elf.si.dynsym.node(elf);
291 const name_dynstr_entry = try elf.string(.dynstr, opts.name);379 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 }
293 switch (elf.dynsymSlice()) {397 switch (elf.dynsymSlice()) {
294 inline else => |dynsym, class| {398 inline else => |dynsyms, class| {
295 const dsym = &dynsym[dsi];399 const Sym = class.ElfN().Sym;
296 dsym.* = .{400 const dynsym = &dynsyms[dsi];
401 dynsym.* = .{
297 .name = name_dynstr_entry,402 .name = name_dynstr_entry,
298 .value = @intCast(opts.value),403 .value = @intCast(opts.value),
299 .size = @intCast(opts.size),404 .size = @intCast(opts.size),
300 .info = .{ .type = opts.type, .bind = opts.bind },405 .info = .{ .type = opts.type, .bind = opts.bind },
301 .other = .{ .visibility = opts.visibility },406 .other = .{ .visibility = opts.visibility },
302 .shndx = opts.shndx,407 .shndx = opts.shndx.toSection().?,
303 };408 };
304 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);409 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
305 },410 },
306 }411 }
307 }412 }
...@@ -321,6 +426,7 @@ pub const Symbol = struct {...@@ -321,6 +426,7 @@ pub const Symbol = struct {
321 }426 }
322427
323 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {428 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
429 if (elf.ehdrField(.type) == .REL) return;
324 switch (si.get(elf).loc_relocs) {430 switch (si.get(elf).loc_relocs) {
325 .none => {},431 .none => {},
326 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {432 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
...@@ -331,6 +437,7 @@ pub const Symbol = struct {...@@ -331,6 +437,7 @@ pub const Symbol = struct {
331 }437 }
332438
333 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {439 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {
440 if (elf.ehdrField(.type) == .REL) return;
334 var ri = si.get(elf).target_relocs;441 var ri = si.get(elf).target_relocs;
335 while (ri != .none) {442 while (ri != .none) {
336 const reloc = ri.get(elf);443 const reloc = ri.get(elf);
...@@ -374,7 +481,7 @@ pub const Reloc = extern struct {...@@ -374,7 +481,7 @@ pub const Reloc = extern struct {
374 next: Reloc.Index,481 next: Reloc.Index,
375 loc: Symbol.Index,482 loc: Symbol.Index,
376 target: Symbol.Index,483 target: Symbol.Index,
377 unused: u32,484 index: Section.RelIndex,
378 offset: u64,485 offset: u64,
379 addend: i64,486 addend: i64,
380487
...@@ -384,6 +491,16 @@ pub const Reloc = extern struct {...@@ -384,6 +491,16 @@ pub const Reloc = extern struct {
384 RISCV: std.elf.R_RISCV,491 RISCV: std.elf.R_RISCV,
385 PPC64: std.elf.R_PPC64,492 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
387 pub fn absAddr(elf: *Elf) Reloc.Type {504 pub fn absAddr(elf: *Elf) Reloc.Type {
388 return switch (elf.ehdrField(.machine)) {505 return switch (elf.ehdrField(.machine)) {
389 else => unreachable,506 else => unreachable,
...@@ -393,12 +510,35 @@ pub const Reloc = extern struct {...@@ -393,12 +510,35 @@ pub const Reloc = extern struct {
393 .X86_64 => .{ .X86_64 = .@"64" },510 .X86_64 => .{ .X86_64 = .@"64" },
394 };511 };
395 }512 }
513
396 pub fn sizeAddr(elf: *Elf) Reloc.Type {514 pub fn sizeAddr(elf: *Elf) Reloc.Type {
397 return switch (elf.ehdrField(.machine)) {515 return switch (elf.ehdrField(.machine)) {
398 else => unreachable,516 else => unreachable,
399 .X86_64 => .{ .X86_64 = .SIZE64 },517 .X86_64 => .{ .X86_64 = .SIZE64 },
400 };518 };
401 }519 }
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 }
402 };542 };
403543
404 pub const Index = enum(u32) {544 pub const Index = enum(u32) {
...@@ -411,6 +551,7 @@ pub const Reloc = extern struct {...@@ -411,6 +551,7 @@ pub const Reloc = extern struct {
411 };551 };
412552
413 pub fn apply(reloc: *const Reloc, elf: *Elf) void {553 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
554 assert(elf.ehdrField(.type) != .REL);
414 const loc_ni = reloc.loc.get(elf).ni;555 const loc_ni = reloc.loc.get(elf).ni;
415 switch (loc_ni) {556 switch (loc_ni) {
416 .none => return,557 .none => return,
...@@ -462,7 +603,7 @@ pub const Reloc = extern struct {...@@ -462,7 +603,7 @@ pub const Reloc = extern struct {
462 .TPOFF32 => {603 .TPOFF32 => {
463 const phdr = @field(elf.phdrSlice(), @tagName(class));604 const phdr = @field(elf.phdrSlice(), @tagName(class));
464 const ph = &phdr[elf.getNode(elf.ni.tls).segment];605 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);
466 std.mem.writeInt(607 std.mem.writeInt(
467 i32,608 i32,
468 loc_slice[0..4],609 loc_slice[0..4],
...@@ -501,6 +642,33 @@ pub const Reloc = extern struct {...@@ -501,6 +642,33 @@ pub const Reloc = extern struct {
501 .none => {},642 .none => {},
502 else => |next| next.get(elf).prev = reloc.prev,643 else => |next| next.get(elf).prev = reloc.prev,
503 }644 }
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 }
504 reloc.* = undefined;672 reloc.* = undefined;
505 }673 }
506674
...@@ -601,6 +769,7 @@ fn create(...@@ -601,6 +769,7 @@ fn create(
601 .tls = .none,769 .tls = .none,
602 },770 },
603 .nodes = .empty,771 .nodes = .empty,
772 .shdrs = .empty,
604 .phdrs = .empty,773 .phdrs = .empty,
605 .si = .{774 .si = .{
606 .dynsym = .null,775 .dynsym = .null,
...@@ -611,16 +780,13 @@ fn create(...@@ -611,16 +780,13 @@ fn create(
611 .symtab = .empty,780 .symtab = .empty,
612 .shstrtab = .{781 .shstrtab = .{
613 .map = .empty,782 .map = .empty,
614 .size = 1,
615 },783 },
616 .strtab = .{784 .strtab = .{
617 .map = .empty,785 .map = .empty,
618 .size = 1,
619 },786 },
620 .dynsym = .empty,787 .dynsym = .empty,
621 .dynstr = .{788 .dynstr = .{
622 .map = .empty,789 .map = .empty,
623 .size = 1,
624 },790 },
625 .needed = .empty,791 .needed = .empty,
626 .inputs = .empty,792 .inputs = .empty,
...@@ -650,6 +816,7 @@ pub fn deinit(elf: *Elf) void {...@@ -650,6 +816,7 @@ pub fn deinit(elf: *Elf) void {
650 const gpa = elf.base.comp.gpa;816 const gpa = elf.base.comp.gpa;
651 elf.mf.deinit(gpa);817 elf.mf.deinit(gpa);
652 elf.nodes.deinit(gpa);818 elf.nodes.deinit(gpa);
819 elf.shdrs.deinit(gpa);
653 elf.phdrs.deinit(gpa);820 elf.phdrs.deinit(gpa);
654 elf.symtab.deinit(gpa);821 elf.symtab.deinit(gpa);
655 elf.shstrtab.map.deinit(gpa);822 elf.shstrtab.map.deinit(gpa);
...@@ -681,11 +848,10 @@ fn initHeaders(...@@ -681,11 +848,10 @@ fn initHeaders(
681 const comp = elf.base.comp;848 const comp = elf.base.comp;
682 const gpa = comp.gpa;849 const gpa = comp.gpa;
683 const have_dynamic_section = switch (@"type") {850 const have_dynamic_section = switch (@"type") {
684 .NONE => unreachable,851 .NONE, .CORE, _ => unreachable,
685 .REL => false,852 .REL => false,
686 .EXEC => comp.config.link_mode == .dynamic,853 .EXEC => comp.config.link_mode == .dynamic,
687 .DYN => true,854 .DYN => true,
688 .CORE, _ => unreachable,
689 };855 };
690 const addr_align: std.mem.Alignment = switch (class) {856 const addr_align: std.mem.Alignment = switch (class) {
691 .NONE, _ => unreachable,857 .NONE, _ => unreachable,
...@@ -693,6 +859,7 @@ fn initHeaders(...@@ -693,6 +859,7 @@ fn initHeaders(
693 .@"64" => .@"8",859 .@"64" => .@"8",
694 };860 };
695861
862 const shnum: u32 = 1;
696 var phnum: u32 = 0;863 var phnum: u32 = 0;
697 const phdr_phndx = phnum;864 const phdr_phndx = phnum;
698 phnum += 1;865 phnum += 1;
...@@ -715,8 +882,17 @@ fn initHeaders(...@@ -715,8 +882,17 @@ fn initHeaders(
715 break :phndx phnum;882 break :phndx phnum;
716 } else undefined;883 } 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 };
719 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);894 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
895 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
720 try elf.phdrs.resize(gpa, phnum);896 try elf.phdrs.resize(gpa, phnum);
721 elf.nodes.appendAssumeCapacity(.file);897 elf.nodes.appendAssumeCapacity(.file);
722898
...@@ -751,7 +927,7 @@ fn initHeaders(...@@ -751,7 +927,7 @@ fn initHeaders(
751 ehdr.phentsize = @sizeOf(ElfN.Phdr);927 ehdr.phentsize = @sizeOf(ElfN.Phdr);
752 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);928 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
753 ehdr.shentsize = @sizeOf(ElfN.Shdr);929 ehdr.shentsize = @sizeOf(ElfN.Shdr);
754 ehdr.shnum = 1;930 ehdr.shnum = if (shnum < std.elf.SHN_LORESERVE) shnum else 0;
755 ehdr.shstrndx = std.elf.SHN_UNDEF;931 ehdr.shstrndx = std.elf.SHN_UNDEF;
756 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);932 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
757 },933 },
...@@ -759,181 +935,187 @@ fn initHeaders(...@@ -759,181 +935,187 @@ fn initHeaders(
759935
760 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{936 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
761 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),937 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
762 .alignment = addr_align,938 .alignment = elf.mf.flags.block_size,
763 .moved = true,939 .moved = true,
764 .resized = true,940 .resized = true,
765 }));941 }));
766 elf.nodes.appendAssumeCapacity(.shdr);942 elf.nodes.appendAssumeCapacity(.shdr);
767943
768 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{944 var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {
769 .alignment = elf.mf.flags.block_size,945 assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
770 .moved = true,946 .alignment = elf.mf.flags.block_size,
771 .bubbles_moved = false,947 .moved = true,
772 }));948 .bubbles_moved = false,
773 elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });949 }));
774 elf.phdrs.items[rodata_phndx] = elf.ni.rodata;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, .{953 assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
777 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),954 .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
778 .alignment = addr_align,955 .alignment = addr_align,
779 .moved = true,956 .moved = true,
780 .resized = true,957 .resized = true,
781 .bubbles_moved = false,958 .bubbles_moved = false,
782 }));959 }));
783 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });960 elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
784 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;961 elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
785962
786 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{963 assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
787 .alignment = elf.mf.flags.block_size,964 .alignment = elf.mf.flags.block_size,
788 .moved = true,965 .moved = true,
789 .bubbles_moved = false,966 .bubbles_moved = false,
790 }));967 }));
791 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });968 elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
792 elf.phdrs.items[text_phndx] = elf.ni.text;969 elf.phdrs.items[text_phndx] = elf.ni.text;
793970
794 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{971 assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
795 .alignment = elf.mf.flags.block_size,972 .alignment = elf.mf.flags.block_size,
796 .moved = true,973 .moved = true,
797 .bubbles_moved = false,974 .bubbles_moved = false,
798 }));975 }));
799 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });976 elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
800 elf.phdrs.items[data_phndx] = elf.ni.data;977 elf.phdrs.items[data_phndx] = elf.ni.data;
801978
802 var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {979 break :ph_vaddr switch (elf.ehdrField(.type)) {
803 else => 0,980 .NONE, .CORE, _ => unreachable,
804 .EXEC => switch (elf.ehdrField(.machine)) {981 .REL, .DYN => 0,
805 .@"386" => 0x400000,982 .EXEC => switch (elf.ehdrField(.machine)) {
806 .AARCH64, .X86_64 => 0x200000,983 .@"386" => 0x400000,
807 .PPC, .PPC64 => 0x10000000,984 .AARCH64, .X86_64 => 0x200000,
808 .S390, .S390_OLD => 0x1000000,985 .PPC, .PPC64 => 0x10000000,
809 .OLD_SPARCV9, .SPARCV9 => 0x100000,986 .S390, .S390_OLD => 0x1000000,
810 else => 0x10000,987 .OLD_SPARCV9, .SPARCV9 => 0x100000,
811 },988 else => 0x10000,
812 };989 },
990 };
991 } else undefined;
813 switch (class) {992 switch (class) {
814 .NONE, _ => unreachable,993 .NONE, _ => unreachable,
815 inline else => |ct_class| {994 inline else => |ct_class| {
816 const ElfN = ct_class.ElfN();995 const ElfN = ct_class.ElfN();
817 const target_endian = elf.targetEndian();996 const target_endian = elf.targetEndian();
818997
819 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));998 if (@"type" != .REL) {
820 const ph_phdr = &phdr[phdr_phndx];999 const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
821 ph_phdr.* = .{1000 const ph_phdr = &phdr[phdr_phndx];
822 .type = std.elf.PT_PHDR,1001 ph_phdr.* = .{
823 .offset = 0,1002 .type = .PHDR,
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,
837 .offset = 0,1003 .offset = 0,
838 .vaddr = 0,1004 .vaddr = 0,
839 .paddr = 0,1005 .paddr = 0,
840 .filesz = 0,1006 .filesz = 0,
841 .memsz = 0,1007 .memsz = 0,
842 .flags = .{ .R = true },1008 .flags = .{ .R = true },
843 .@"align" = 1,1009 .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
844 };1010 };
845 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);1011 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
846 }1012
8471013 if (maybe_interp) |_| {
848 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);1014 const ph_interp = &phdr[interp_phndx];
849 const ph_rodata = &phdr[rodata_phndx];1015 ph_interp.* = .{
850 ph_rodata.* = .{1016 .type = .INTERP,
851 .type = std.elf.PT_NULL,1017 .offset = 0,
852 .offset = 0,1018 .vaddr = 0,
853 .vaddr = ph_vaddr,1019 .paddr = 0,
854 .paddr = ph_vaddr,1020 .filesz = 0,
855 .filesz = @intCast(rodata_size),1021 .memsz = 0,
856 .memsz = @intCast(rodata_size),1022 .flags = .{ .R = true },
857 .flags = .{ .R = true },1023 .@"align" = 1,
858 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),1024 };
859 };1025 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
860 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);1026 }
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);
8771027
878 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);1028 _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
879 const ph_data = &phdr[data_phndx];1029 const ph_rodata = &phdr[rodata_phndx];
880 ph_data.* = .{1030 ph_rodata.* = .{
881 .type = std.elf.PT_NULL,1031 .type = if (rodata_size == 0) .NULL else .LOAD,
882 .offset = 0,1032 .offset = 0,
883 .vaddr = ph_vaddr,1033 .vaddr = ph_vaddr,
884 .paddr = ph_vaddr,1034 .paddr = ph_vaddr,
885 .filesz = @intCast(data_size),1035 .filesz = @intCast(rodata_size),
886 .memsz = @intCast(data_size),1036 .memsz = @intCast(rodata_size),
887 .flags = .{ .R = true, .W = true },1037 .flags = .{ .R = true },
888 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),1038 .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
889 };1039 };
890 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);1040 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
891 ph_vaddr += @intCast(data_size);1041 ph_vaddr += @intCast(rodata_size);
8921042
893 if (have_dynamic_section) {1043 _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
894 const ph_dynamic = &phdr[dynamic_phndx];1044 const ph_text = &phdr[text_phndx];
895 ph_dynamic.* = .{1045 ph_text.* = .{
896 .type = std.elf.PT_DYNAMIC,1046 .type = if (text_size == 0) .NULL else .LOAD,
897 .offset = 0,1047 .offset = 0,
898 .vaddr = 0,1048 .vaddr = ph_vaddr,
899 .paddr = 0,1049 .paddr = ph_vaddr,
900 .filesz = 0,1050 .filesz = @intCast(text_size),
901 .memsz = 0,1051 .memsz = @intCast(text_size),
902 .flags = .{ .R = true, .W = true },1052 .flags = .{ .R = true, .X = true },
903 .@"align" = @intCast(addr_align.toByteUnits()),1053 .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
904 };1054 };
905 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);1055 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
906 }1056 ph_vaddr += @intCast(text_size);
9071057
908 if (comp.config.any_non_single_threaded) {1058 _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
909 const ph_tls = &phdr[tls_phndx];1059 const ph_data = &phdr[data_phndx];
910 ph_tls.* = .{1060 ph_data.* = .{
911 .type = std.elf.PT_TLS,1061 .type = if (data_size == 0) .NULL else .LOAD,
912 .offset = 0,1062 .offset = 0,
913 .vaddr = 0,1063 .vaddr = ph_vaddr,
914 .paddr = 0,1064 .paddr = ph_vaddr,
915 .filesz = 0,1065 .filesz = @intCast(data_size),
916 .memsz = 0,1066 .memsz = @intCast(data_size),
917 .flags = .{ .R = true },1067 .flags = .{ .R = true, .W = true },
918 .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),1068 .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
919 };1069 };
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 }
921 }1102 }
9221103
923 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));1104 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
924 sh_null.* = .{1105 sh_undef.* = .{
925 .name = try elf.string(.shstrtab, ""),1106 .name = try elf.string(.shstrtab, ""),
926 .type = std.elf.SHT_NULL,1107 .type = .NULL,
927 .flags = .{ .shf = .{} },1108 .flags = .{ .shf = .{} },
928 .addr = 0,1109 .addr = 0,
929 .offset = 0,1110 .offset = 0,
930 .size = 0,1111 .size = if (shnum < std.elf.SHN_LORESERVE) 0 else shnum,
931 .link = 0,1112 .link = 0,
932 .info = if (phnum >= std.elf.PN_XNUM) phnum else 0,1113 .info = if (phnum < std.elf.PN_XNUM) 0 else phnum,
933 .addralign = 0,1114 .addralign = 0,
934 .entsize = 0,1115 .entsize = 0,
935 };1116 };
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
938 try elf.symtab.ensureTotalCapacity(gpa, 1);1120 try elf.symtab.ensureTotalCapacity(gpa, 1);
939 elf.symtab.addOneAssumeCapacity().* = .{1121 elf.symtab.addOneAssumeCapacity().* = .{
...@@ -943,10 +1125,11 @@ fn initHeaders(...@@ -943,10 +1125,11 @@ fn initHeaders(
943 .unused = 0,1125 .unused = 0,
944 };1126 };
945 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{1127 assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
946 .type = std.elf.SHT_SYMTAB,1128 .type = .SYMTAB,
947 .size = @sizeOf(ElfN.Sym) * 1,1129 .size = @sizeOf(ElfN.Sym) * 1,
948 .addralign = addr_align,1130 .addralign = addr_align,
949 .entsize = @sizeOf(ElfN.Sym),1131 .entsize = @sizeOf(ElfN.Sym),
1132 .node_align = elf.mf.flags.block_size,
950 }));1133 }));
951 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));1134 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
952 symtab_null.* = .{1135 symtab_null.* = .{
...@@ -960,13 +1143,14 @@ fn initHeaders(...@@ -960,13 +1143,14 @@ fn initHeaders(
960 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);1143 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
9611144
962 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));1145 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
963 ehdr.shstrndx = ehdr.shnum;1146 elf.targetStore(&ehdr.shstrndx, ehdr.shnum);
964 },1147 },
965 }1148 }
966 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{1149 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
967 .type = std.elf.SHT_STRTAB,1150 .type = .STRTAB,
968 .addralign = elf.mf.flags.block_size,1151 .size = 1,
969 .entsize = 1,1152 .entsize = 1,
1153 .node_align = elf.mf.flags.block_size,
970 }));1154 }));
971 try elf.renameSection(.symtab, ".symtab");1155 try elf.renameSection(.symtab, ".symtab");
972 try elf.renameSection(.shstrtab, ".shstrtab");1156 try elf.renameSection(.shstrtab, ".shstrtab");
...@@ -974,10 +1158,10 @@ fn initHeaders(...@@ -974,10 +1158,10 @@ fn initHeaders(
9741158
975 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{1159 assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
976 .name = ".strtab",1160 .name = ".strtab",
977 .type = std.elf.SHT_STRTAB,1161 .type = .STRTAB,
978 .size = 1,1162 .size = 1,
979 .addralign = elf.mf.flags.block_size,
980 .entsize = 1,1163 .entsize = 1,
1164 .node_align = elf.mf.flags.block_size,
981 }));1165 }));
982 try elf.linkSections(.symtab, .strtab);1166 try elf.linkSections(.symtab, .strtab);
983 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;1167 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
...@@ -997,87 +1181,96 @@ fn initHeaders(...@@ -997,87 +1181,96 @@ fn initHeaders(
997 .flags = .{ .WRITE = true, .ALLOC = true },1181 .flags = .{ .WRITE = true, .ALLOC = true },
998 .addralign = elf.mf.flags.block_size,1182 .addralign = elf.mf.flags.block_size,
999 }));1183 }));
1000 if (maybe_interp) |interp| {1184 if (@"type" != .REL) {
1001 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{1185 if (maybe_interp) |interp| {
1002 .size = interp.len + 1,1186 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1003 .moved = true,1187 .size = interp.len + 1,
1004 .resized = true,1188 .moved = true,
1005 .bubbles_moved = false,1189 .resized = true,
1006 });1190 .bubbles_moved = false,
1007 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });1191 });
1008 elf.phdrs.items[interp_phndx] = interp_ni;1192 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
10091193 elf.phdrs.items[interp_phndx] = interp_ni;
1010 const sec_interp_si = try elf.addSection(interp_ni, .{1194
1011 .name = ".interp",1195 const sec_interp_si = try elf.addSection(interp_ni, .{
1012 .flags = .{ .ALLOC = true },1196 .type = .PROGBITS,
1013 .size = @intCast(interp.len + 1),1197 .name = ".interp",
1014 });1198 .flags = .{ .ALLOC = true },
1015 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);1199 .size = @intCast(interp.len + 1),
1016 @memcpy(sec_interp[0..interp.len], interp);1200 });
1017 sec_interp[interp.len] = 0;1201 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
1018 }1202 @memcpy(sec_interp[0..interp.len], interp);
1019 if (have_dynamic_section) {1203 sec_interp[interp.len] = 0;
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 },
1049 }1204 }
1050 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{1205 if (have_dynamic_section) {
1051 .name = ".dynstr",1206 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1052 .type = std.elf.SHT_STRTAB,1207 .moved = true,
1053 .size = 1,1208 .bubbles_moved = false,
1054 .addralign = elf.mf.flags.block_size,1209 });
1055 .entsize = 1,1210 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1056 });1211 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
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;
10741212
1075 elf.si.tdata = try elf.addSection(elf.ni.tls, .{1213 switch (class) {
1076 .name = ".tdata",1214 .NONE, _ => unreachable,
1077 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },1215 inline else => |ct_class| {
1078 .addralign = elf.mf.flags.block_size,1216 const Sym = ct_class.ElfN().Sym;
1079 });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);
1080 }1268 }
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 });
1081 assert(elf.nodes.len == expected_nodes_len);1274 assert(elf.nodes.len == expected_nodes_len);
1082}1275}
10831276
...@@ -1116,7 +1309,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {...@@ -1116,7 +1309,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
1116 .file => return 0,1309 .file => return 0,
1117 .ehdr, .shdr => unreachable,1310 .ehdr, .shdr => unreachable,
1118 .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {1311 .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),
1120 },1313 },
1121 .section => |si| si,1314 .section => |si| si,
1122 .input_section => unreachable,1315 .input_section => unreachable,
...@@ -1202,6 +1395,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {...@@ -1202,6 +1395,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
1202 @"64": []std.elf.Elf64.Phdr,1395 @"64": []std.elf.Elf64.Phdr,
1203};1396};
1204pub fn phdrSlice(elf: *Elf) PhdrSlice {1397pub fn phdrSlice(elf: *Elf) PhdrSlice {
1398 assert(elf.ehdrField(.type) != .REL);
1205 const slice = elf.ni.phdr.slice(&elf.mf);1399 const slice = elf.ni.phdr.slice(&elf.mf);
1206 return switch (elf.identClass()) {1400 return switch (elf.identClass()) {
1207 .NONE, _ => unreachable,1401 .NONE, _ => unreachable,
...@@ -1230,6 +1424,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {...@@ -1230,6 +1424,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
1230 };1424 };
1231}1425}
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
1233pub const SymtabSlice = union(std.elf.CLASS) {1438pub const SymtabSlice = union(std.elf.CLASS) {
1234 NONE: noreturn,1439 NONE: noreturn,
1235 @"32": []std.elf.Elf32.Sym,1440 @"32": []std.elf.Elf32.Sym,
...@@ -1242,7 +1447,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {...@@ -1242,7 +1447,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {
1242 inline else => |class| @unionInit(1447 inline else => |class| @unionInit(
1243 SymtabSlice,1448 SymtabSlice,
1244 @tagName(class),1449 @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 )])),
1246 ),1455 ),
1247 };1456 };
1248}1457}
...@@ -1254,7 +1463,7 @@ pub const SymPtr = union(std.elf.CLASS) {...@@ -1254,7 +1463,7 @@ pub const SymPtr = union(std.elf.CLASS) {
1254};1463};
1255pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {1464pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1256 return switch (elf.symtabSlice()) {1465 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)]),
1258 };1467 };
1259}1468}
12601469
...@@ -1544,7 +1753,7 @@ fn loadObject(...@@ -1544,7 +1753,7 @@ fn loadObject(
1544 .si = try elf.initSymbolAssumeCapacity(.{1753 .si = try elf.initSymbolAssumeCapacity(.{
1545 .name = std.fs.path.stem(member orelse path.sub_path),1754 .name = std.fs.path.stem(member orelse path.sub_path),
1546 .type = .FILE,1755 .type = .FILE,
1547 .shndx = std.elf.SHN_ABS,1756 .shndx = .ABS,
1548 }),1757 }),
1549 };1758 };
1550 const target_endian = elf.targetEndian();1759 const target_endian = elf.targetEndian();
...@@ -1571,7 +1780,7 @@ fn loadObject(...@@ -1571,7 +1780,7 @@ fn loadObject(
1571 };1780 };
1572 try r.discardAll(ehdr.shentsize);1781 try r.discardAll(ehdr.shentsize);
1573 switch (section.shdr.type) {1782 switch (section.shdr.type) {
1574 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},1783 .NULL, .NOBITS => {},
1575 else => if (section.shdr.offset + section.shdr.size > fl.size)1784 else => if (section.shdr.offset + section.shdr.size > fl.size)
1576 return diags.failParse(path, "bad section location", .{}),1785 return diags.failParse(path, "bad section location", .{}),
1577 }1786 }
...@@ -1580,8 +1789,7 @@ fn loadObject(...@@ -1580,8 +1789,7 @@ fn loadObject(
1580 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)1789 if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
1581 return diags.failParse(path, "missing section names", .{});1790 return diags.failParse(path, "missing section names", .{});
1582 const shdr = &sections[ehdr.shstrndx].shdr;1791 const shdr = &sections[ehdr.shstrndx].shdr;
1583 if (shdr.type != std.elf.SHT_STRTAB)1792 if (shdr.type != .STRTAB) return diags.failParse(path, "invalid shstrtab type", .{});
1584 return diags.failParse(path, "invalid shstrtab type", .{});
1585 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));1793 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
1586 errdefer gpa.free(shstrtab);1794 errdefer gpa.free(shstrtab);
1587 try fr.seekTo(fl.offset + shdr.offset);1795 try fr.seekTo(fl.offset + shdr.offset);
...@@ -1594,7 +1802,7 @@ fn loadObject(...@@ -1594,7 +1802,7 @@ fn loadObject(
1594 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);1802 try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
1595 for (sections[1..]) |*section| switch (section.shdr.type) {1803 for (sections[1..]) |*section| switch (section.shdr.type) {
1596 else => {},1804 else => {},
1597 std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {1805 .PROGBITS, .NOBITS => {
1598 if (section.shdr.name >= shstrtab.len) continue;1806 if (section.shdr.name >= shstrtab.len) continue;
1599 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);1807 const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
1600 const parent_si = elf.namedSection(name) orelse continue;1808 const parent_si = elf.namedSection(name) orelse continue;
...@@ -1611,7 +1819,7 @@ fn loadObject(...@@ -1611,7 +1819,7 @@ fn loadObject(
1611 });1819 });
1612 section.si = try elf.initSymbolAssumeCapacity(.{1820 section.si = try elf.initSymbolAssumeCapacity(.{
1613 .type = .SECTION,1821 .type = .SECTION,
1614 .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx),1822 .shndx = parent_si.shndx(elf),
1615 });1823 });
1616 section.si.get(elf).ni = ni;1824 section.si.get(elf).ni = ni;
1617 elf.input_sections.addOneAssumeCapacity().* = .{1825 elf.input_sections.addOneAssumeCapacity().* = .{
...@@ -1629,14 +1837,14 @@ fn loadObject(...@@ -1629,14 +1837,14 @@ fn loadObject(
1629 defer symmap.deinit(gpa);1837 defer symmap.deinit(gpa);
1630 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {1838 for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
1631 else => {},1839 else => {},
1632 std.elf.SHT_SYMTAB => {1840 .SYMTAB => {
1633 if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))1841 if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))
1634 return diags.failParse(path, "unsupported symtab entsize", .{});1842 return diags.failParse(path, "unsupported symtab entsize", .{});
1635 const strtab = strtab: {1843 const strtab = strtab: {
1636 if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)1844 if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)
1637 return diags.failParse(path, "missing symbol names", .{});1845 return diags.failParse(path, "missing symbol names", .{});
1638 const shdr = &sections[symtab.shdr.link].shdr;1846 const shdr = &sections[symtab.shdr.link].shdr;
1639 if (shdr.type != std.elf.SHT_STRTAB)1847 if (shdr.type != .STRTAB)
1640 return diags.failParse(path, "invalid strtab type", .{});1848 return diags.failParse(path, "invalid strtab type", .{});
1641 const strtab = try gpa.alloc(u8, @intCast(shdr.size));1849 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
1642 errdefer gpa.free(strtab);1850 errdefer gpa.free(strtab);
...@@ -1683,9 +1891,7 @@ fn loadObject(...@@ -1683,9 +1891,7 @@ fn loadObject(
1683 .type = input_sym.info.type,1891 .type = input_sym.info.type,
1684 .bind = input_sym.info.bind,1892 .bind = input_sym.info.bind,
1685 .visibility = input_sym.other.visibility,1893 .visibility = input_sym.other.visibility,
1686 .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) {1894 .shndx = parent_si.shndx(elf),
1687 inline else => |parent_sym| &parent_sym.shndx,
1688 }),
1689 });1895 });
1690 si.get(elf).ni = parent_si.get(elf).ni;1896 si.get(elf).ni = parent_si.get(elf).ni;
1691 switch (input_sym.info.bind) {1897 switch (input_sym.info.bind) {
...@@ -1719,13 +1925,13 @@ fn loadObject(...@@ -1719,13 +1925,13 @@ fn loadObject(
1719 }1925 }
1720 for (sections[1..]) |*rels| switch (rels.shdr.type) {1926 for (sections[1..]) |*rels| switch (rels.shdr.type) {
1721 else => {},1927 else => {},
1722 inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| {1928 inline .REL, .RELA => |sht| {
1723 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or1929 if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
1724 rels.shdr.info >= ehdr.shnum) continue;1930 rels.shdr.info >= ehdr.shnum) continue;
1725 const Rel = switch (sht) {1931 const Rel = switch (sht) {
1726 else => comptime unreachable,1932 else => comptime unreachable,
1727 std.elf.SHT_REL => ElfN.Rel,1933 .REL => ElfN.Rel,
1728 std.elf.SHT_RELA => ElfN.Rela,1934 .RELA => ElfN.Rela,
1729 };1935 };
1730 if (rels.shdr.entsize < @sizeOf(Rel))1936 if (rels.shdr.entsize < @sizeOf(Rel))
1731 return diags.failParse(path, "unsupported rel entsize", .{});1937 return diags.failParse(path, "unsupported rel entsize", .{});
...@@ -1740,7 +1946,7 @@ fn loadObject(...@@ -1740,7 +1946,7 @@ fn loadObject(
1740 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",1946 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
1741 .{ rels.shdr.size, rels.shdr.entsize },1947 .{ rels.shdr.size, rels.shdr.entsize },
1742 );1948 );
1743 try elf.relocs.ensureUnusedCapacity(gpa, relnum);1949 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
1744 try fr.seekTo(fl.offset + rels.shdr.offset);1950 try fr.seekTo(fl.offset + rels.shdr.offset);
1745 for (0..relnum) |_| {1951 for (0..relnum) |_| {
1746 const rel = try r.peekStruct(Rel, target_endian);1952 const rel = try r.peekStruct(Rel, target_endian);
...@@ -1753,18 +1959,7 @@ fn loadObject(...@@ -1753,18 +1959,7 @@ fn loadObject(
1753 rel.offset - loc_sec.shdr.addr,1959 rel.offset - loc_sec.shdr.addr,
1754 target_si,1960 target_si,
1755 rel.addend,1961 rel.addend,
1756 switch (elf.ehdrField(.machine)) {1962 .wrap(rel.info.type, elf),
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 },
1768 );1963 );
1769 }1964 }
1770 },1965 },
...@@ -1800,7 +1995,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void...@@ -1800,7 +1995,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
1800 try r.discardAll(ehdr.phentsize);1995 try r.discardAll(ehdr.phentsize);
1801 switch (ph.type) {1996 switch (ph.type) {
1802 else => {},1997 else => {},
1803 std.elf.PT_DYNAMIC => break ph,1998 .DYNAMIC => break ph,
1804 }1999 }
1805 } else return diags.failParse(path, "no dynamic segment", .{});2000 } else return diags.failParse(path, "no dynamic segment", .{});
1806 const dynnum = std.math.divExact(2001 const dynnum = std.math.divExact(
...@@ -1817,13 +2012,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void...@@ -1817,13 +2012,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
1817 var soname: ?ElfN.Addr = null;2012 var soname: ?ElfN.Addr = null;
1818 try fr.seekTo(dynamic_ph.offset);2013 try fr.seekTo(dynamic_ph.offset);
1819 for (0..dynnum) |_| {2014 for (0..dynnum) |_| {
1820 const key = try r.takeInt(ElfN.Addr, target_endian);2015 const tag = try r.takeInt(ElfN.Addr, target_endian);
1821 const value = try r.takeInt(ElfN.Addr, target_endian);2016 const val = try r.takeInt(ElfN.Addr, target_endian);
1822 switch (key) {2017 switch (tag) {
1823 else => {},2018 else => {},
1824 std.elf.DT_STRTAB => strtab = value,2019 std.elf.DT_STRTAB => strtab = val,
1825 std.elf.DT_STRSZ => strsz = value,2020 std.elf.DT_STRSZ => strsz = val,
1826 std.elf.DT_SONAME => soname = value,2021 std.elf.DT_SONAME => soname = val,
1827 }2022 }
1828 }2023 }
1829 if (strtab == null or soname == null)2024 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...@@ -1836,7 +2031,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
1836 try r.discardAll(ehdr.phentsize);2031 try r.discardAll(ehdr.phentsize);
1837 switch (ph.type) {2032 switch (ph.type) {
1838 else => {},2033 else => {},
1839 std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and2034 .LOAD => if (strtab.? >= ph.vaddr and
1840 strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,2035 strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,
1841 }2036 }
1842 } else return diags.failParse(path, "strtab not part of a loaded segment", .{});2037 } else return diags.failParse(path, "strtab not part of a loaded segment", .{});
...@@ -1868,11 +2063,7 @@ fn prelinkInner(elf: *Elf) !void {...@@ -1868,11 +2063,7 @@ fn prelinkInner(elf: *Elf) !void {
1868 std.fs.path.stem(elf.base.emit.sub_path),2063 std.fs.path.stem(elf.base.emit.sub_path),
1869 });2064 });
1870 defer gpa.free(zcu_name);2065 defer gpa.free(zcu_name);
1871 const si = try elf.initSymbolAssumeCapacity(.{2066 const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });
1872 .name = zcu_name,
1873 .type = .FILE,
1874 .shndx = std.elf.SHN_ABS,
1875 });
1876 elf.inputs.addOneAssumeCapacity().* = .{2067 elf.inputs.addOneAssumeCapacity().* = .{
1877 .path = elf.base.emit,2068 .path = elf.base.emit,
1878 .member = null,2069 .member = null,
...@@ -1972,63 +2163,87 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In...@@ -1972,63 +2163,87 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
19722163
1973fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {2164fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1974 name: []const u8 = "",2165 name: []const u8 = "",
1975 type: std.elf.Word = std.elf.SHT_NULL,2166 type: std.elf.SHT = .NULL,
1976 flags: std.elf.SHF = .{},2167 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,
1978 addralign: std.mem.Alignment = .@"1",2171 addralign: std.mem.Alignment = .@"1",
1979 entsize: std.elf.Word = 0,2172 entsize: std.elf.Word = 0,
2173 node_align: std.mem.Alignment = .@"1",
1980}) !Symbol.Index {2174}) !Symbol.Index {
1981 switch (opts.type) {2175 switch (opts.type) {
1982 std.elf.SHT_NULL => assert(opts.size == 0),2176 .NULL => assert(opts.size == 0),
1983 std.elf.SHT_PROGBITS => assert(opts.size > 0),2177 .PROGBITS => assert(opts.size > 0),
1984 else => {},2178 else => {},
1985 }2179 }
1986 const gpa = elf.base.comp.gpa;2180 const gpa = elf.base.comp.gpa;
1987 try elf.nodes.ensureUnusedCapacity(gpa, 1);2181 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2182 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
1988 try elf.symtab.ensureUnusedCapacity(gpa, 1);2183 try elf.symtab.ensureUnusedCapacity(gpa, 1);
19892184
1990 const shstrtab_entry = try elf.string(.shstrtab, opts.name);2185 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
1991 const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) {2186 const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
1992 inline else => |ehdr| {2187 inline else => |ehdr, class| {
1993 const shndx = elf.targetLoad(&ehdr.shnum);2188 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
1994 const shnum = shndx + 1;2189 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
1995 elf.targetStore(&ehdr.shnum, shnum);2190 const shnum = shndx + 1;
1996 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };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 };
1997 },2211 },
1998 };2212 };
1999 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);2213 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
2000 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{2214 if (new_shdr_size > shdr_node_size)
2001 .alignment = opts.addralign,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),
2002 .size = opts.size,2222 .size = opts.size,
2003 .resized = opts.size > 0,2223 .resized = opts.size > 0,
2004 });2224 });
2005 const si = elf.addSymbolAssumeCapacity();2225 const si = elf.addSymbolAssumeCapacity();
2006 elf.nodes.appendAssumeCapacity(.{ .section = si });2226 elf.nodes.appendAssumeCapacity(.{ .section = si });
2227 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
2007 si.get(elf).ni = ni;2228 si.get(elf).ni = ni;
2008 const addr = elf.computeNodeVAddr(ni);2229 const addr = elf.computeNodeVAddr(ni);
2009 const offset = ni.fileLocation(&elf.mf, false).offset;2230 const offset = ni.fileLocation(&elf.mf, false).offset;
2010 try si.init(elf, .{2231 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
2011 .value = addr,2232 switch (elf.shdrPtr(shndx)) {
2012 .size = opts.size,2233 inline else => |shdr, class| {
2013 .type = .SECTION,2234 shdr.* = .{
2014 .shndx = shndx,
2015 });
2016 switch (elf.shdrSlice()) {
2017 inline else => |shdr| {
2018 const sh = &shdr[shndx];
2019 sh.* = .{
2020 .name = shstrtab_entry,2235 .name = shstrtab_entry,
2021 .type = opts.type,2236 .type = opts.type,
2022 .flags = .{ .shf = opts.flags },2237 .flags = .{ .shf = opts.flags },
2023 .addr = @intCast(addr),2238 .addr = @intCast(addr),
2024 .offset = @intCast(offset),2239 .offset = @intCast(offset),
2025 .size = opts.size,2240 .size = @intCast(opts.size),
2026 .link = 0,2241 .link = opts.link,
2027 .info = 0,2242 .info = opts.info,
2028 .addralign = @intCast(opts.addralign.toByteUnits()),2243 .addralign = @intCast(opts.addralign.toByteUnits()),
2029 .entsize = opts.entsize,2244 .entsize = opts.entsize,
2030 };2245 };
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);
2032 },2247 },
2033 }2248 }
2034 return si;2249 return si;
...@@ -2036,39 +2251,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2036,39 +2251,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
20362251
2037fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {2252fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2038 const shstrtab_entry = try elf.string(.shstrtab, name);2253 const shstrtab_entry = try elf.string(.shstrtab, name);
2039 switch (elf.shdrSlice()) {2254 switch (elf.shdrPtr(si.shndx(elf))) {
2040 inline else => |shdr, class| elf.targetStore(2255 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
2041 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2042 shstrtab_entry,
2043 ),
2044 }2256 }
2045}2257}
20462258
2047fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {2259fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
2048 switch (elf.shdrSlice()) {2260 switch (elf.shdrPtr(si.shndx(elf))) {
2049 inline else => |shdr, class| shdr[2261 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
2050 elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)
2051 ].link = @field(elf.symPtr(link_si), @tagName(class)).shndx,
2052 }2262 }
2053}2263}
20542264
2055fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {2265fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2056 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {2266 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2057 inline else => |shndx, class| elf.targetLoad(2267 inline else => |shdr| elf.targetLoad(&shdr.name),
2058 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2059 ),
2060 }..];2268 }..];
2061 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];2269 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
2062}2270}
20632271
2064fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {2272fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
2065 if (key.len == 0) return 0;2273 if (key.len == 0) return 0;
2066 return @field(elf, @tagName(section)).get(2274 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
2067 elf.base.comp.gpa,
2068 &elf.mf,
2069 @field(elf.si, @tagName(section)).node(elf),
2070 key,
2071 );
2072}2275}
20732276
2074pub fn addReloc(2277pub fn addReloc(
...@@ -2079,9 +2282,51 @@ pub fn addReloc(...@@ -2079,9 +2282,51 @@ pub fn addReloc(
2079 addend: i64,2282 addend: i64,
2080 @"type": Reloc.Type,2283 @"type": Reloc.Type,
2081) !void {2284) !void {
2082 try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1);2285 try elf.ensureUnusedRelocCapacity(loc_si, 1);
2083 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");2286 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2084}2287}
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}
2085pub fn addRelocAssumeCapacity(2330pub fn addRelocAssumeCapacity(
2086 elf: *Elf,2331 elf: *Elf,
2087 loc_si: Symbol.Index,2332 loc_si: Symbol.Index,
...@@ -2098,7 +2343,45 @@ pub fn addRelocAssumeCapacity(...@@ -2098,7 +2343,45 @@ pub fn addRelocAssumeCapacity(
2098 .next = target.target_relocs,2343 .next = target.target_relocs,
2099 .loc = loc_si,2344 .loc = loc_si,
2100 .target = target_si,2345 .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 },
2102 .offset = offset,2385 .offset = offset,
2103 .addend = addend,2386 .addend = addend,
2104 };2387 };
...@@ -2464,7 +2747,8 @@ fn flushUav(...@@ -2464,7 +2747,8 @@ fn flushUav(
2464 switch (sym.ni) {2747 switch (sym.ni) {
2465 .none => {2748 .none => {
2466 try elf.nodes.ensureUnusedCapacity(gpa, 1);2749 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), .{
2468 .alignment = uav_align.toStdMem(),2752 .alignment = uav_align.toStdMem(),
2469 .moved = true,2753 .moved = true,
2470 });2754 });
...@@ -2472,7 +2756,7 @@ fn flushUav(...@@ -2472,7 +2756,7 @@ fn flushUav(
2472 sym.ni = ni;2756 sym.ni = ni;
2473 switch (elf.symPtr(si)) {2757 switch (elf.symPtr(si)) {
2474 inline else => |sym_ptr, class| sym_ptr.shndx =2758 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,
2476 }2760 }
2477 },2761 },
2478 else => {2762 else => {
...@@ -2596,11 +2880,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2596,11 +2880,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
2596 var child_it = ni.children(&elf.mf);2880 var child_it = ni.children(&elf.mf);
2597 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);2881 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
2598 },2882 },
2599 .section => |si| switch (elf.shdrSlice()) {2883 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
2600 inline else => |shdr, class| elf.targetStore(2884 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
2601 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,2885 ni.fileLocation(&elf.mf, false).offset,
2602 @intCast(ni.fileLocation(&elf.mf, false).offset),2886 )),
2603 ),
2604 },2887 },
2605 }2888 }
2606}2889}
...@@ -2616,10 +2899,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2616,10 +2899,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2616 const ph = &phdr[phndx];2899 const ph = &phdr[phndx];
2617 switch (elf.targetLoad(&ph.type)) {2900 switch (elf.targetLoad(&ph.type)) {
2618 else => unreachable,2901 else => unreachable,
2619 std.elf.PT_NULL, std.elf.PT_LOAD => return,2902 .NULL, .LOAD => return,
2620 std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},2903 .DYNAMIC, .INTERP => {},
2621 std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,2904 .PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
2622 std.elf.PT_TLS => {},2905 .TLS => {},
2623 }2906 }
2624 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));2907 elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
2625 ph.paddr = ph.vaddr;2908 ph.paddr = ph.vaddr;
...@@ -2629,14 +2912,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2629,14 +2912,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2629 .section => |si| {2912 .section => |si| {
2630 try elf.flushFileOffset(ni);2913 try elf.flushFileOffset(ni);
2631 const addr = elf.computeNodeVAddr(ni);2914 const addr = elf.computeNodeVAddr(ni);
2632 switch (elf.shdrSlice()) {2915 switch (elf.shdrPtr(si.shndx(elf))) {
2633 inline else => |shdr, class| {2916 inline else => |shdr, class| {
2634 const sym = @field(elf.symPtr(si), @tagName(class));2917 const flags = elf.targetLoad(&shdr.flags).shf;
2635 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2636 const flags = elf.targetLoad(&sh.flags).shf;
2637 if (flags.ALLOC) {2918 if (flags.ALLOC) {
2638 elf.targetStore(&sh.addr, @intCast(addr));2919 elf.targetStore(&shdr.addr, @intCast(addr));
2639 sym.value = sh.addr;2920 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
2640 }2921 }
2641 },2922 },
2642 }2923 }
...@@ -2684,22 +2965,18 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2684,22 +2965,18 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2684 elf.targetStore(&ph.memsz, @intCast(memsz));2965 elf.targetStore(&ph.memsz, @intCast(memsz));
2685 switch (elf.targetLoad(&ph.type)) {2966 switch (elf.targetLoad(&ph.type)) {
2686 else => unreachable,2967 else => unreachable,
2687 std.elf.PT_NULL => if (size > 0) elf.targetStore(&ph.type, std.elf.PT_LOAD),2968 .NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
2688 std.elf.PT_LOAD => if (size == 0) elf.targetStore(&ph.type, std.elf.PT_NULL),2969 .LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
2689 std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => return,2970 .DYNAMIC, .INTERP, .PHDR => return,
2690 std.elf.PT_TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),2971 .TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
2691 }2972 }
2692 var vaddr = elf.targetLoad(&ph.vaddr);2973 var vaddr = elf.targetLoad(&ph.vaddr);
2693 var new_phndx = phndx;2974 var new_phndx = phndx;
2694 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {2975 for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
2695 switch (elf.targetLoad(&next_ph.type)) {2976 switch (elf.targetLoad(&next_ph.type)) {
2696 else => unreachable,2977 else => unreachable,
2697 std.elf.PT_NULL, std.elf.PT_LOAD => {},2978 .NULL, .LOAD => {},
2698 std.elf.PT_DYNAMIC,2979 .DYNAMIC, .INTERP, .PHDR, .TLS => break,
2699 std.elf.PT_INTERP,
2700 std.elf.PT_PHDR,
2701 std.elf.PT_TLS,
2702 => break,
2703 }2980 }
2704 const next_vaddr = elf.targetLoad(&next_ph.vaddr);2981 const next_vaddr = elf.targetLoad(&next_ph.vaddr);
2705 if (vaddr + memsz <= next_vaddr) break;2982 if (vaddr + memsz <= next_vaddr) break;
...@@ -2721,20 +2998,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2721,20 +2998,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2721 }2998 }
2722 },2999 },
2723 },3000 },
2724 .section => |si| switch (elf.symPtr(si)) {3001 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
2725 inline else => |sym, class| {3002 inline else => |shdr| {
2726 const sh = &@field(elf.shdrSlice(), @tagName(class))[elf.targetLoad(&sym.shndx)];3003 switch (elf.targetLoad(&shdr.type)) {
2727 elf.targetStore(&sh.size, @intCast(size));
2728 switch (elf.targetLoad(&sh.type)) {
2729 else => unreachable,3004 else => unreachable,
2730 std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),3005 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
2731 std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),3006 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
2732 std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore(3007 .SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return,
2733 &sh.info,
2734 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
2735 ),
2736 std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
2737 }3008 }
3009 elf.targetStore(&shdr.size, @intCast(size));
2738 },3010 },
2739 },3011 },
2740 .input_section => {},3012 .input_section => {},
...@@ -2860,6 +3132,26 @@ pub fn printNode(...@@ -2860,6 +3132,26 @@ pub fn printNode(
2860 try w.writeAll(@tagName(node));3132 try w.writeAll(@tagName(node));
2861 switch (node) {3133 switch (node) {
2862 else => {},3134 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 },
2863 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),3155 .section => |si| try w.print("({s})", .{elf.sectionName(si)}),
2864 .input_section => |isi| {3156 .input_section => |isi| {
2865 const ii = isi.input(elf);3157 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 {...@@ -486,6 +486,14 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
486 break :free .{ free_ni, free_node };486 break :free .{ free_ni, free_node };
487 },487 },
488 };488 };
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 }
489 free_node.* = .{497 free_node.* = .{
490 .parent = opts.parent,498 .parent = opts.parent,
491 .prev = opts.prev,499 .prev = opts.prev,
...@@ -535,13 +543,10 @@ pub fn addOnlyChildNode(...@@ -535,13 +543,10 @@ pub fn addOnlyChildNode(
535 try mf.nodes.ensureUnusedCapacity(gpa, 1);543 try mf.nodes.ensureUnusedCapacity(gpa, 1);
536 const parent = parent_ni.get(mf);544 const parent = parent_ni.get(mf);
537 assert(parent.first == .none and parent.last == .none);545 assert(parent.first == .none and parent.last == .none);
538 const ni = try mf.addNode(gpa, .{546 return mf.addNode(gpa, .{
539 .parent = parent_ni,547 .parent = parent_ni,
540 .add_node = opts,548 .add_node = opts,
541 });549 });
542 parent.first = ni;
543 parent.last = ni;
544 return ni;
545}550}
546551
547pub fn addFirstChildNode(552pub fn addFirstChildNode(
...@@ -552,17 +557,11 @@ pub fn addFirstChildNode(...@@ -552,17 +557,11 @@ pub fn addFirstChildNode(
552) !Node.Index {557) !Node.Index {
553 try mf.nodes.ensureUnusedCapacity(gpa, 1);558 try mf.nodes.ensureUnusedCapacity(gpa, 1);
554 const parent = parent_ni.get(mf);559 const parent = parent_ni.get(mf);
555 const ni = try mf.addNode(gpa, .{560 return mf.addNode(gpa, .{
556 .parent = parent_ni,561 .parent = parent_ni,
557 .next = parent.first,562 .next = parent.first,
558 .add_node = opts,563 .add_node = opts,
559 });564 });
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;
566}565}
567566
568pub fn addLastChildNode(567pub fn addLastChildNode(
...@@ -573,7 +572,7 @@ pub fn addLastChildNode(...@@ -573,7 +572,7 @@ pub fn addLastChildNode(
573) !Node.Index {572) !Node.Index {
574 try mf.nodes.ensureUnusedCapacity(gpa, 1);573 try mf.nodes.ensureUnusedCapacity(gpa, 1);
575 const parent = parent_ni.get(mf);574 const parent = parent_ni.get(mf);
576 const ni = try mf.addNode(gpa, .{575 return mf.addNode(gpa, .{
577 .parent = parent_ni,576 .parent = parent_ni,
578 .prev = parent.last,577 .prev = parent.last,
579 .offset = offset: switch (parent.last) {578 .offset = offset: switch (parent.last) {
...@@ -585,12 +584,6 @@ pub fn addLastChildNode(...@@ -585,12 +584,6 @@ pub fn addLastChildNode(
585 },584 },
586 .add_node = opts,585 .add_node = opts,
587 });586 });
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;
594}587}
595588
596pub fn addNodeAfter(589pub fn addNodeAfter(
...@@ -603,19 +596,13 @@ pub fn addNodeAfter(...@@ -603,19 +596,13 @@ pub fn addNodeAfter(
603 try mf.nodes.ensureUnusedCapacity(gpa, 1);596 try mf.nodes.ensureUnusedCapacity(gpa, 1);
604 const prev = prev_ni.get(mf);597 const prev = prev_ni.get(mf);
605 const prev_offset, const prev_size = prev.location().resolve(mf);598 const prev_offset, const prev_size = prev.location().resolve(mf);
606 const ni = try mf.addNode(gpa, .{599 return mf.addNode(gpa, .{
607 .parent = prev.parent,600 .parent = prev.parent,
608 .prev = prev_ni,601 .prev = prev_ni,
609 .next = prev.next,602 .next = prev.next,
610 .offset = prev_offset + prev_size,603 .offset = prev_offset + prev_size,
611 .add_node = opts,604 .add_node = opts,
612 });605 });
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;
619}606}
620607
621fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {608fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {