mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
Merge pull request #25819 from jacobly0/elfv2-emit-obj
This commit is contained in:
+3
-3
@@ -3971,7 +3971,7 @@ pub const dl_phdr_info = switch (native_os) {
|
||||
/// Module name.
|
||||
name: ?[*:0]const u8,
|
||||
/// Pointer to module's phdr.
|
||||
phdr: [*]std.elf.Phdr,
|
||||
phdr: [*]std.elf.ElfN.Phdr,
|
||||
/// Number of entries in phdr.
|
||||
phnum: u16,
|
||||
/// Total number of loads.
|
||||
@@ -3984,7 +3984,7 @@ pub const dl_phdr_info = switch (native_os) {
|
||||
.illumos => extern struct {
|
||||
addr: std.elf.Addr,
|
||||
name: ?[*:0]const u8,
|
||||
phdr: [*]std.elf.Phdr,
|
||||
phdr: [*]std.elf.ElfN.Phdr,
|
||||
phnum: std.elf.Half,
|
||||
/// Incremented when a new object is mapped into the process.
|
||||
adds: u64,
|
||||
@@ -3995,7 +3995,7 @@ pub const dl_phdr_info = switch (native_os) {
|
||||
.openbsd, .haiku, .dragonfly, .netbsd, .serenity => extern struct {
|
||||
addr: usize,
|
||||
name: ?[*:0]const u8,
|
||||
phdr: [*]std.elf.Phdr,
|
||||
phdr: [*]std.elf.ElfN.Phdr,
|
||||
phnum: std.elf.Half,
|
||||
},
|
||||
else => void,
|
||||
|
||||
@@ -441,11 +441,11 @@ const DlIterContext = struct {
|
||||
|
||||
// Populate `build_id` and `gnu_eh_frame`
|
||||
for (info.phdr[0..info.phnum]) |phdr| {
|
||||
switch (phdr.p_type) {
|
||||
std.elf.PT_NOTE => {
|
||||
switch (phdr.type) {
|
||||
.NOTE => {
|
||||
// Look for .note.gnu.build-id
|
||||
const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
|
||||
var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.p_memsz]);
|
||||
const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
|
||||
var r: std.Io.Reader = .fixed(segment_ptr[0..phdr.memsz]);
|
||||
const name_size = r.takeInt(u32, native_endian) catch continue;
|
||||
const desc_size = r.takeInt(u32, native_endian) catch continue;
|
||||
const note_type = r.takeInt(u32, native_endian) catch continue;
|
||||
@@ -455,9 +455,9 @@ const DlIterContext = struct {
|
||||
const desc = r.take(desc_size) catch continue;
|
||||
build_id = desc;
|
||||
},
|
||||
std.elf.PT_GNU_EH_FRAME => {
|
||||
const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.p_vaddr);
|
||||
gnu_eh_frame = segment_ptr[0..phdr.p_memsz];
|
||||
std.elf.PT.GNU_EH_FRAME => {
|
||||
const segment_ptr: [*]const u8 = @ptrFromInt(info.addr + phdr.vaddr);
|
||||
gnu_eh_frame = segment_ptr[0..phdr.memsz];
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@@ -478,11 +478,11 @@ const DlIterContext = struct {
|
||||
});
|
||||
|
||||
for (info.phdr[0..info.phnum]) |phdr| {
|
||||
if (phdr.p_type != std.elf.PT_LOAD) continue;
|
||||
if (phdr.type != .LOAD) continue;
|
||||
try context.si.ranges.append(gpa, .{
|
||||
// Overflowing addition handles VSDOs having p_vaddr = 0xffffffffff700000
|
||||
.start = info.addr +% phdr.p_vaddr,
|
||||
.len = phdr.p_memsz,
|
||||
.start = info.addr +% phdr.vaddr,
|
||||
.len = phdr.memsz,
|
||||
.module_index = module_index,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,8 +92,7 @@ pub fn get_DYNAMIC() ?[*]const elf.Dyn {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
|
||||
_ = phdrs;
|
||||
pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
|
||||
const _DYNAMIC = get_DYNAMIC() orelse {
|
||||
// No PT_DYNAMIC means this is a statically-linked non-PIE program.
|
||||
return .{ .current = null };
|
||||
|
||||
+228
-100
@@ -50,6 +50,7 @@ pub const AT_L2_CACHESIZE = 44;
|
||||
pub const AT_L2_CACHEGEOMETRY = 45;
|
||||
pub const AT_L3_CACHESIZE = 46;
|
||||
pub const AT_L3_CACHEGEOMETRY = 47;
|
||||
pub const AT_MINSIGSTKSZ = 51;
|
||||
|
||||
pub const DT_NULL = 0;
|
||||
pub const DT_NEEDED = 1;
|
||||
@@ -286,105 +287,111 @@ pub const VER_FLG_BASE = 1;
|
||||
/// Weak version identifier
|
||||
pub const VER_FLG_WEAK = 2;
|
||||
|
||||
/// Program header table entry unused
|
||||
pub const PT_NULL = 0;
|
||||
/// Loadable program segment
|
||||
pub const PT_LOAD = 1;
|
||||
/// Dynamic linking information
|
||||
pub const PT_DYNAMIC = 2;
|
||||
/// Program interpreter
|
||||
pub const PT_INTERP = 3;
|
||||
/// Auxiliary information
|
||||
pub const PT_NOTE = 4;
|
||||
/// Reserved
|
||||
pub const PT_SHLIB = 5;
|
||||
/// Entry for header table itself
|
||||
pub const PT_PHDR = 6;
|
||||
/// Thread-local storage segment
|
||||
pub const PT_TLS = 7;
|
||||
/// Number of defined types
|
||||
pub const PT_NUM = 8;
|
||||
/// Start of OS-specific
|
||||
pub const PT_LOOS = 0x60000000;
|
||||
/// GCC .eh_frame_hdr segment
|
||||
pub const PT_GNU_EH_FRAME = 0x6474e550;
|
||||
/// Indicates stack executability
|
||||
pub const PT_GNU_STACK = 0x6474e551;
|
||||
/// Read-only after relocation
|
||||
pub const PT_GNU_RELRO = 0x6474e552;
|
||||
pub const PT_LOSUNW = 0x6ffffffa;
|
||||
/// Sun specific segment
|
||||
pub const PT_SUNWBSS = 0x6ffffffa;
|
||||
/// Stack segment
|
||||
pub const PT_SUNWSTACK = 0x6ffffffb;
|
||||
pub const PT_HISUNW = 0x6fffffff;
|
||||
/// End of OS-specific
|
||||
pub const PT_HIOS = 0x6fffffff;
|
||||
/// Start of processor-specific
|
||||
pub const PT_LOPROC = 0x70000000;
|
||||
/// End of processor-specific
|
||||
pub const PT_HIPROC = 0x7fffffff;
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.NULL)`
|
||||
pub const PT_NULL = @intFromEnum(std.elf.PT.NULL);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.LOAD)`
|
||||
pub const PT_LOAD = @intFromEnum(std.elf.PT.LOAD);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.DYNAMIC)`
|
||||
pub const PT_DYNAMIC = @intFromEnum(std.elf.PT.DYNAMIC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.INTERP)`
|
||||
pub const PT_INTERP = @intFromEnum(std.elf.PT.INTERP);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.NOTE)`
|
||||
pub const PT_NOTE = @intFromEnum(std.elf.PT.NOTE);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.SHLIB)`
|
||||
pub const PT_SHLIB = @intFromEnum(std.elf.PT.SHLIB);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.PHDR)`
|
||||
pub const PT_PHDR = @intFromEnum(std.elf.PT.PHDR);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.TLS)`
|
||||
pub const PT_TLS = @intFromEnum(std.elf.PT.TLS);
|
||||
/// Deprecated, use `std.elf.PT.NUM`.
|
||||
pub const PT_NUM = PT.NUM;
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.LOOS)`
|
||||
pub const PT_LOOS = @intFromEnum(std.elf.PT.LOOS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_EH_FRAME)`
|
||||
pub const PT_GNU_EH_FRAME = @intFromEnum(std.elf.PT.GNU_EH_FRAME);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_STACK)`
|
||||
pub const PT_GNU_STACK = @intFromEnum(std.elf.PT.GNU_STACK);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.GNU_RELRO)`
|
||||
pub const PT_GNU_RELRO = @intFromEnum(std.elf.PT.GNU_RELRO);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.LOSUNW)`
|
||||
pub const PT_LOSUNW = @intFromEnum(std.elf.PT.LOSUNW);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWBSS)`
|
||||
pub const PT_SUNWBSS = @intFromEnum(std.elf.PT.SUNWBSS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.SUNWSTACK)`
|
||||
pub const PT_SUNWSTACK = @intFromEnum(std.elf.PT.SUNWSTACK);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.HISUNW)`
|
||||
pub const PT_HISUNW = @intFromEnum(std.elf.PT.HISUNW);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.HIOS)`
|
||||
pub const PT_HIOS = @intFromEnum(std.elf.PT.HIOS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.LOPROC)`
|
||||
pub const PT_LOPROC = @intFromEnum(std.elf.PT.LOPROC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.PT.HIPROC)`
|
||||
pub const PT_HIPROC = @intFromEnum(std.elf.PT.HIPROC);
|
||||
|
||||
pub const PN_XNUM = 0xffff;
|
||||
|
||||
/// Section header table entry unused
|
||||
pub const SHT_NULL = 0;
|
||||
/// Program data
|
||||
pub const SHT_PROGBITS = 1;
|
||||
/// Symbol table
|
||||
pub const SHT_SYMTAB = 2;
|
||||
/// String table
|
||||
pub const SHT_STRTAB = 3;
|
||||
/// Relocation entries with addends
|
||||
pub const SHT_RELA = 4;
|
||||
/// Symbol hash table
|
||||
pub const SHT_HASH = 5;
|
||||
/// Dynamic linking information
|
||||
pub const SHT_DYNAMIC = 6;
|
||||
/// Notes
|
||||
pub const SHT_NOTE = 7;
|
||||
/// Program space with no data (bss)
|
||||
pub const SHT_NOBITS = 8;
|
||||
/// Relocation entries, no addends
|
||||
pub const SHT_REL = 9;
|
||||
/// Reserved
|
||||
pub const SHT_SHLIB = 10;
|
||||
/// Dynamic linker symbol table
|
||||
pub const SHT_DYNSYM = 11;
|
||||
/// Array of constructors
|
||||
pub const SHT_INIT_ARRAY = 14;
|
||||
/// Array of destructors
|
||||
pub const SHT_FINI_ARRAY = 15;
|
||||
/// Array of pre-constructors
|
||||
pub const SHT_PREINIT_ARRAY = 16;
|
||||
/// Section group
|
||||
pub const SHT_GROUP = 17;
|
||||
/// Extended section indices
|
||||
pub const SHT_SYMTAB_SHNDX = 18;
|
||||
/// Start of OS-specific
|
||||
pub const SHT_LOOS = 0x60000000;
|
||||
/// LLVM address-significance table
|
||||
pub const SHT_LLVM_ADDRSIG = 0x6fff4c03;
|
||||
/// GNU hash table
|
||||
pub const SHT_GNU_HASH = 0x6ffffff6;
|
||||
/// GNU version definition table
|
||||
pub const SHT_GNU_VERDEF = 0x6ffffffd;
|
||||
/// GNU needed versions table
|
||||
pub const SHT_GNU_VERNEED = 0x6ffffffe;
|
||||
/// GNU symbol version table
|
||||
pub const SHT_GNU_VERSYM = 0x6fffffff;
|
||||
/// End of OS-specific
|
||||
pub const SHT_HIOS = 0x6fffffff;
|
||||
/// Start of processor-specific
|
||||
pub const SHT_LOPROC = 0x70000000;
|
||||
/// Unwind information
|
||||
pub const SHT_X86_64_UNWIND = 0x70000001;
|
||||
/// End of processor-specific
|
||||
pub const SHT_HIPROC = 0x7fffffff;
|
||||
/// Start of application-specific
|
||||
pub const SHT_LOUSER = 0x80000000;
|
||||
/// End of application-specific
|
||||
pub const SHT_HIUSER = 0xffffffff;
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.NULL)`
|
||||
pub const SHT_NULL = @intFromEnum(std.elf.SHT.NULL);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.PROGBITS)`
|
||||
pub const SHT_PROGBITS = @intFromEnum(std.elf.SHT.PROGBITS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB)`
|
||||
pub const SHT_SYMTAB = @intFromEnum(std.elf.SHT.SYMTAB);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.STRTAB)`
|
||||
pub const SHT_STRTAB = @intFromEnum(std.elf.SHT.STRTAB);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.RELA)`
|
||||
pub const SHT_RELA = @intFromEnum(std.elf.SHT.RELA);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.HASH)`
|
||||
pub const SHT_HASH = @intFromEnum(std.elf.SHT.HASH);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNAMIC)`
|
||||
pub const SHT_DYNAMIC = @intFromEnum(std.elf.SHT.DYNAMIC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.NOTE)`
|
||||
pub const SHT_NOTE = @intFromEnum(std.elf.SHT.NOTE);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.NOBITS)`
|
||||
pub const SHT_NOBITS = @intFromEnum(std.elf.SHT.NOBITS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.REL)`
|
||||
pub const SHT_REL = @intFromEnum(std.elf.SHT.REL);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.SHLIB)`
|
||||
pub const SHT_SHLIB = @intFromEnum(std.elf.SHT.SHLIB);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.DYNSYM)`
|
||||
pub const SHT_DYNSYM = @intFromEnum(std.elf.SHT.DYNSYM);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.INIT_ARRAY)`
|
||||
pub const SHT_INIT_ARRAY = @intFromEnum(std.elf.SHT.INIT_ARRAY);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.FINI_ARRAY)`
|
||||
pub const SHT_FINI_ARRAY = @intFromEnum(std.elf.SHT.FINI_ARRAY);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.PREINIT_ARRAY)`
|
||||
pub const SHT_PREINIT_ARRAY = @intFromEnum(std.elf.SHT.PREINIT_ARRAY);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.GROUP)`
|
||||
pub const SHT_GROUP = @intFromEnum(std.elf.SHT.GROUP);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.SYMTAB_SHNDX)`
|
||||
pub const SHT_SYMTAB_SHNDX = @intFromEnum(std.elf.SHT.SYMTAB_SHNDX);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.RELR)`
|
||||
pub const SHT_RELR = @intFromEnum(std.elf.SHT.RELR);
|
||||
/// Deprecated, use `std.elf.SHT.NUM`.
|
||||
pub const SHT_NUM = SHT.NUM;
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.LOOS)`
|
||||
pub const SHT_LOOS = @intFromEnum(std.elf.SHT.LOOS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.LLVM_ADDRSIG)`
|
||||
pub const SHT_LLVM_ADDRSIG = @intFromEnum(std.elf.SHT.LLVM_ADDRSIG);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_HASH)`
|
||||
pub const SHT_GNU_HASH = @intFromEnum(std.elf.SHT.GNU_HASH);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERDEF)`
|
||||
pub const SHT_GNU_VERDEF = @intFromEnum(std.elf.SHT.GNU_VERDEF);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERNEED)`
|
||||
pub const SHT_GNU_VERNEED = @intFromEnum(std.elf.SHT.GNU_VERNEED);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.GNU_VERSYM)`
|
||||
pub const SHT_GNU_VERSYM = @intFromEnum(std.elf.SHT.GNU_VERSYM);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.HIOS)`
|
||||
pub const SHT_HIOS = @intFromEnum(std.elf.SHT.HIOS);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.LOPROC)`
|
||||
pub const SHT_LOPROC = @intFromEnum(std.elf.SHT.LOPROC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.X86_64_UNWIND)`
|
||||
pub const SHT_X86_64_UNWIND = @intFromEnum(std.elf.SHT.X86_64_UNWIND);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.HIPROC)`
|
||||
pub const SHT_HIPROC = @intFromEnum(std.elf.SHT.HIPROC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.LOUSER)`
|
||||
pub const SHT_LOUSER = @intFromEnum(std.elf.SHT.LOUSER);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.SHT.HIUSER)`
|
||||
pub const SHT_HIUSER = @intFromEnum(std.elf.SHT.HIUSER);
|
||||
|
||||
// Note type for .note.gnu.build_id
|
||||
pub const NT_GNU_BUILD_ID = 3;
|
||||
@@ -454,6 +461,127 @@ pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC);
|
||||
/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)`
|
||||
pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT);
|
||||
|
||||
pub const PT = enum(Word) {
|
||||
/// Program header table entry unused
|
||||
NULL = 0,
|
||||
/// Loadable program segment
|
||||
LOAD = 1,
|
||||
/// Dynamic linking information
|
||||
DYNAMIC = 2,
|
||||
/// Program interpreter
|
||||
INTERP = 3,
|
||||
/// Auxiliary information
|
||||
NOTE = 4,
|
||||
/// Reserved
|
||||
SHLIB = 5,
|
||||
/// Entry for header table itself
|
||||
PHDR = 6,
|
||||
/// Thread-local storage segment
|
||||
TLS = 7,
|
||||
_,
|
||||
|
||||
/// Number of defined types
|
||||
pub const NUM = @typeInfo(PT).@"enum".fields.len;
|
||||
|
||||
/// Start of OS-specific
|
||||
pub const LOOS: PT = @enumFromInt(0x60000000);
|
||||
/// End of OS-specific
|
||||
pub const HIOS: PT = @enumFromInt(0x6fffffff);
|
||||
|
||||
/// GCC .eh_frame_hdr segment
|
||||
pub const GNU_EH_FRAME: PT = @enumFromInt(0x6474e550);
|
||||
/// Indicates stack executability
|
||||
pub const GNU_STACK: PT = @enumFromInt(0x6474e551);
|
||||
/// Read-only after relocation
|
||||
pub const GNU_RELRO: PT = @enumFromInt(0x6474e552);
|
||||
|
||||
pub const LOSUNW: PT = @enumFromInt(0x6ffffffa);
|
||||
pub const HISUNW: PT = @enumFromInt(0x6fffffff);
|
||||
|
||||
/// Sun specific segment
|
||||
pub const SUNWBSS: PT = @enumFromInt(0x6ffffffa);
|
||||
/// Stack segment
|
||||
pub const SUNWSTACK: PT = @enumFromInt(0x6ffffffb);
|
||||
|
||||
/// Start of processor-specific
|
||||
pub const LOPROC: PT = @enumFromInt(0x70000000);
|
||||
/// End of processor-specific
|
||||
pub const HIPROC: PT = @enumFromInt(0x7fffffff);
|
||||
};
|
||||
|
||||
pub const SHT = enum(Word) {
|
||||
/// Section header table entry unused
|
||||
NULL = 0,
|
||||
/// Program data
|
||||
PROGBITS = 1,
|
||||
/// Symbol table
|
||||
SYMTAB = 2,
|
||||
/// String table
|
||||
STRTAB = 3,
|
||||
/// Relocation entries with addends
|
||||
RELA = 4,
|
||||
/// Symbol hash table
|
||||
HASH = 5,
|
||||
/// Dynamic linking information
|
||||
DYNAMIC = 6,
|
||||
/// Notes
|
||||
NOTE = 7,
|
||||
/// Program space with no data (bss)
|
||||
NOBITS = 8,
|
||||
/// Relocation entries, no addends
|
||||
REL = 9,
|
||||
/// Reserved
|
||||
SHLIB = 10,
|
||||
/// Dynamic linker symbol table
|
||||
DYNSYM = 11,
|
||||
/// Array of constructors
|
||||
INIT_ARRAY = 14,
|
||||
/// Array of destructors
|
||||
FINI_ARRAY = 15,
|
||||
/// Array of pre-constructors
|
||||
PREINIT_ARRAY = 16,
|
||||
/// Section group
|
||||
GROUP = 17,
|
||||
/// Extended section indices
|
||||
SYMTAB_SHNDX = 18,
|
||||
/// RELR relative relocations
|
||||
RELR = 19,
|
||||
_,
|
||||
|
||||
/// Number of defined types
|
||||
pub const NUM = @typeInfo(SHT).@"enum".fields.len;
|
||||
|
||||
/// Start of OS-specific
|
||||
pub const LOOS: SHT = @enumFromInt(0x60000000);
|
||||
/// End of OS-specific
|
||||
pub const HIOS: SHT = @enumFromInt(0x6fffffff);
|
||||
|
||||
/// LLVM address-significance table
|
||||
pub const LLVM_ADDRSIG: SHT = @enumFromInt(0x6fff4c03);
|
||||
|
||||
/// GNU hash table
|
||||
pub const GNU_HASH: SHT = @enumFromInt(0x6ffffff6);
|
||||
/// GNU version definition table
|
||||
pub const GNU_VERDEF: SHT = @enumFromInt(0x6ffffffd);
|
||||
/// GNU needed versions table
|
||||
pub const GNU_VERNEED: SHT = @enumFromInt(0x6ffffffe);
|
||||
/// GNU symbol version table
|
||||
pub const GNU_VERSYM: SHT = @enumFromInt(0x6fffffff);
|
||||
|
||||
/// Start of processor-specific
|
||||
pub const LOPROC: SHT = @enumFromInt(0x70000000);
|
||||
/// End of processor-specific
|
||||
pub const HIPROC: SHT = @enumFromInt(0x7fffffff);
|
||||
|
||||
/// Unwind information
|
||||
pub const X86_64_UNWIND: SHT = @enumFromInt(0x70000001);
|
||||
|
||||
/// Start of application-specific
|
||||
pub const LOUSER: SHT = @enumFromInt(0x80000000);
|
||||
/// End of application-specific
|
||||
pub const HIUSER: SHT = @enumFromInt(0xffffffff);
|
||||
};
|
||||
|
||||
pub const STB = enum(u4) {
|
||||
/// Local symbol
|
||||
LOCAL = 0,
|
||||
@@ -899,7 +1027,7 @@ pub const Elf32 = struct {
|
||||
shstrndx: Half,
|
||||
};
|
||||
pub const Phdr = extern struct {
|
||||
type: Word,
|
||||
type: PT,
|
||||
offset: Elf32.Off,
|
||||
vaddr: Elf32.Addr,
|
||||
paddr: Elf32.Addr,
|
||||
@@ -910,7 +1038,7 @@ pub const Elf32 = struct {
|
||||
};
|
||||
pub const Shdr = extern struct {
|
||||
name: Word,
|
||||
type: Word,
|
||||
type: SHT,
|
||||
flags: packed struct { shf: SHF },
|
||||
addr: Elf32.Addr,
|
||||
offset: Elf32.Off,
|
||||
@@ -989,7 +1117,7 @@ pub const Elf64 = struct {
|
||||
shstrndx: Half,
|
||||
};
|
||||
pub const Phdr = extern struct {
|
||||
type: Word,
|
||||
type: PT,
|
||||
flags: PF,
|
||||
offset: Elf64.Off,
|
||||
vaddr: Elf64.Addr,
|
||||
@@ -1000,7 +1128,7 @@ pub const Elf64 = struct {
|
||||
};
|
||||
pub const Shdr = extern struct {
|
||||
name: Word,
|
||||
type: Word,
|
||||
type: SHT,
|
||||
flags: packed struct { shf: SHF, unused: Word = 0 },
|
||||
addr: Elf64.Addr,
|
||||
offset: Elf64.Off,
|
||||
|
||||
@@ -6101,7 +6101,7 @@ pub const dirent64 = extern struct {
|
||||
pub const dl_phdr_info = extern struct {
|
||||
addr: usize,
|
||||
name: ?[*:0]const u8,
|
||||
phdr: [*]std.elf.Phdr,
|
||||
phdr: [*]std.elf.ElfN.Phdr,
|
||||
phnum: u16,
|
||||
};
|
||||
|
||||
|
||||
+29
-38
@@ -5048,6 +5048,13 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getSelfPhdrs() []std.elf.ElfN.Phdr {
|
||||
const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
|
||||
assert(getauxval(std.elf.AT_PHENT) == @sizeOf(std.elf.ElfN.Phdr));
|
||||
const phdrs: [*]std.elf.ElfN.Phdr = @ptrFromInt(getauxval(std.elf.AT_PHDR));
|
||||
return phdrs[0..getauxval(std.elf.AT_PHNUM)];
|
||||
}
|
||||
|
||||
pub fn dl_iterate_phdr(
|
||||
context: anytype,
|
||||
comptime Error: type,
|
||||
@@ -5075,34 +5082,24 @@ pub fn dl_iterate_phdr(
|
||||
}
|
||||
}
|
||||
|
||||
const elf_base = std.process.getBaseAddress();
|
||||
const ehdr: *elf.Ehdr = @ptrFromInt(elf_base);
|
||||
// Make sure the base address points to an ELF image.
|
||||
assert(mem.eql(u8, ehdr.e_ident[0..4], elf.MAGIC));
|
||||
const n_phdr = ehdr.e_phnum;
|
||||
const phdrs = (@as([*]elf.Phdr, @ptrFromInt(elf_base + ehdr.e_phoff)))[0..n_phdr];
|
||||
|
||||
var it = dl.linkmap_iterator(phdrs) catch unreachable;
|
||||
var it = dl.linkmap_iterator() catch unreachable;
|
||||
|
||||
// The executable has no dynamic link segment, create a single entry for
|
||||
// the whole ELF image.
|
||||
if (it.end()) {
|
||||
// Find the base address for the ELF image, if this is a PIE the value
|
||||
// is non-zero.
|
||||
const base_address = for (phdrs) |*phdr| {
|
||||
if (phdr.p_type == elf.PT_PHDR) {
|
||||
break @intFromPtr(phdrs.ptr) - phdr.p_vaddr;
|
||||
// We could try computing the difference between _DYNAMIC and
|
||||
// the p_vaddr of the PT_DYNAMIC section, but using the phdr is
|
||||
// good enough (Is it?).
|
||||
}
|
||||
} else unreachable;
|
||||
|
||||
var info = dl_phdr_info{
|
||||
.addr = base_address,
|
||||
.name = "/proc/self/exe",
|
||||
const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
|
||||
const phdrs = getSelfPhdrs();
|
||||
var info: dl_phdr_info = .{
|
||||
.addr = for (phdrs) |phdr| switch (phdr.type) {
|
||||
.PHDR => break @intFromPtr(phdrs.ptr) - phdr.vaddr,
|
||||
else => {},
|
||||
} else unreachable,
|
||||
.name = switch (getauxval(std.elf.AT_EXECFN)) {
|
||||
0 => "/proc/self/exe",
|
||||
else => |name| @ptrFromInt(name),
|
||||
},
|
||||
.phdr = phdrs.ptr,
|
||||
.phnum = ehdr.e_phnum,
|
||||
.phnum = @intCast(phdrs.len),
|
||||
};
|
||||
|
||||
return callback(&info, @sizeOf(dl_phdr_info), context);
|
||||
@@ -5110,24 +5107,18 @@ pub fn dl_iterate_phdr(
|
||||
|
||||
// Last return value from the callback function.
|
||||
while (it.next()) |entry| {
|
||||
var phdr: [*]elf.Phdr = undefined;
|
||||
var phnum: u16 = undefined;
|
||||
const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
|
||||
const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
|
||||
assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
|
||||
const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
|
||||
break :phdrs phdrs[0..ehdr.phnum];
|
||||
} else getSelfPhdrs();
|
||||
|
||||
if (entry.l_addr != 0) {
|
||||
const elf_header: *elf.Ehdr = @ptrFromInt(entry.l_addr);
|
||||
phdr = @ptrFromInt(entry.l_addr + elf_header.e_phoff);
|
||||
phnum = elf_header.e_phnum;
|
||||
} else {
|
||||
// This is the running ELF image
|
||||
phdr = @ptrFromInt(elf_base + ehdr.e_phoff);
|
||||
phnum = ehdr.e_phnum;
|
||||
}
|
||||
|
||||
var info = dl_phdr_info{
|
||||
var info: dl_phdr_info = .{
|
||||
.addr = entry.l_addr,
|
||||
.name = entry.l_name,
|
||||
.phdr = phdr,
|
||||
.phnum = phnum,
|
||||
.phdr = phdrs.ptr,
|
||||
.phnum = @intCast(phdrs.len),
|
||||
};
|
||||
|
||||
try callback(&info, @sizeOf(dl_phdr_info), context);
|
||||
|
||||
@@ -257,11 +257,11 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
|
||||
while (i < info.phnum) : (i += 1) {
|
||||
const phdr = info.phdr[i];
|
||||
|
||||
if (phdr.p_type != elf.PT_LOAD) continue;
|
||||
if (phdr.type != .LOAD) continue;
|
||||
|
||||
const reloc_addr = info.addr + phdr.p_vaddr;
|
||||
const reloc_addr = info.addr + phdr.vaddr;
|
||||
// Find the ELF header
|
||||
const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.p_offset));
|
||||
const elf_header = @as(*elf.Ehdr, @ptrFromInt(reloc_addr - phdr.offset));
|
||||
// Validate the magic
|
||||
if (!mem.eql(u8, elf_header.e_ident[0..4], elf.MAGIC)) return error.BadElfMagic;
|
||||
// Consistency check
|
||||
|
||||
+7
-7
@@ -1658,13 +1658,13 @@ fn posixGetUserInfoPasswdStream(name: []const u8, reader: *std.Io.Reader) !UserI
|
||||
pub fn getBaseAddress() usize {
|
||||
switch (native_os) {
|
||||
.linux => {
|
||||
const getauxval = if (builtin.link_libc) std.c.getauxval else std.os.linux.getauxval;
|
||||
const base = getauxval(std.elf.AT_BASE);
|
||||
if (base != 0) {
|
||||
return base;
|
||||
}
|
||||
const phdr = getauxval(std.elf.AT_PHDR);
|
||||
return phdr - @sizeOf(std.elf.Ehdr);
|
||||
const phdrs = std.posix.getSelfPhdrs();
|
||||
var base: usize = 0;
|
||||
for (phdrs) |phdr| switch (phdr.type) {
|
||||
.LOAD => return base + phdr.vaddr,
|
||||
.PHDR => base = @intFromPtr(phdrs.ptr) - phdr.vaddr,
|
||||
else => {},
|
||||
} else unreachable;
|
||||
},
|
||||
.driverkit, .ios, .macos, .tvos, .visionos, .watchos => {
|
||||
return @intFromPtr(&std.c._mh_execute_header);
|
||||
|
||||
+682
-390
@@ -3,6 +3,7 @@ options: link.File.OpenOptions,
|
||||
mf: MappedFile,
|
||||
ni: Node.Known,
|
||||
nodes: std.MultiArrayList(Node),
|
||||
shdrs: std.ArrayList(Section),
|
||||
phdrs: std.ArrayList(MappedFile.Node.Index),
|
||||
si: Symbol.Known,
|
||||
symtab: std.ArrayList(Symbol),
|
||||
@@ -163,9 +164,29 @@ pub const Node = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
pub const Section = struct {
|
||||
si: Symbol.Index,
|
||||
rela_si: Symbol.Index,
|
||||
rela_free: RelIndex,
|
||||
|
||||
pub const RelIndex = enum(u32) {
|
||||
none,
|
||||
_,
|
||||
|
||||
pub fn wrap(i: ?u32) RelIndex {
|
||||
return @enumFromInt((i orelse return .none) + 1);
|
||||
}
|
||||
pub fn unwrap(ri: RelIndex) ?u32 {
|
||||
return switch (ri) {
|
||||
.none => null,
|
||||
else => @intFromEnum(ri) - 1,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const StringTable = struct {
|
||||
map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
|
||||
size: u32,
|
||||
|
||||
const Context = struct {
|
||||
slice: []const u8,
|
||||
@@ -193,14 +214,10 @@ pub const StringTable = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn get(
|
||||
st: *StringTable,
|
||||
gpa: std.mem.Allocator,
|
||||
mf: *MappedFile,
|
||||
ni: MappedFile.Node.Index,
|
||||
key: []const u8,
|
||||
) !u32 {
|
||||
const slice_const = ni.sliceConst(mf);
|
||||
pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
|
||||
const gpa = elf.base.comp.gpa;
|
||||
const ni = si.node(elf);
|
||||
const slice_const = ni.sliceConst(&elf.mf);
|
||||
const gop = try st.map.getOrPutContextAdapted(
|
||||
gpa,
|
||||
key,
|
||||
@@ -208,11 +225,18 @@ pub const StringTable = struct {
|
||||
.{ .slice = slice_const },
|
||||
);
|
||||
if (gop.found_existing) return gop.key_ptr.*;
|
||||
const old_size = st.size;
|
||||
const new_size: u32 = @intCast(old_size + key.len + 1);
|
||||
st.size = new_size;
|
||||
try ni.resize(mf, gpa, new_size);
|
||||
const slice = ni.slice(mf)[old_size..];
|
||||
const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| {
|
||||
const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
|
||||
const new_size: u32 = @intCast(old_size + key.len + 1);
|
||||
elf.targetStore(&shdr.size, new_size);
|
||||
break :size .{ old_size, new_size };
|
||||
},
|
||||
};
|
||||
_, const node_size = ni.location(&elf.mf).resolve(&elf.mf);
|
||||
if (new_size > node_size)
|
||||
try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor);
|
||||
const slice = ni.slice(&elf.mf)[old_size..];
|
||||
@memcpy(slice[0..key.len], key);
|
||||
slice[key.len] = 0;
|
||||
gop.key_ptr.* = old_size;
|
||||
@@ -226,7 +250,7 @@ pub const Symbol = struct {
|
||||
loc_relocs: Reloc.Index,
|
||||
/// Relocations targeting this symbol
|
||||
target_relocs: Reloc.Index,
|
||||
unused: u32 = 0,
|
||||
unused: u32,
|
||||
|
||||
pub const Index = enum(u32) {
|
||||
null,
|
||||
@@ -252,6 +276,52 @@ pub const Symbol = struct {
|
||||
return @enumFromInt(@intFromEnum(si) + 1);
|
||||
}
|
||||
|
||||
pub const Shndx = enum(Tag) {
|
||||
UNDEF = std.elf.SHN_UNDEF,
|
||||
LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
|
||||
ABS = reserve(std.elf.SHN_ABS),
|
||||
COMMON = reserve(std.elf.SHN_COMMON),
|
||||
_,
|
||||
|
||||
pub const Tag = u32;
|
||||
|
||||
pub const LORESERVE: Shndx = .fromSection(std.elf.SHN_LORESERVE);
|
||||
pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE);
|
||||
comptime {
|
||||
assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));
|
||||
}
|
||||
|
||||
fn reserve(sec: std.elf.Section) Tag {
|
||||
assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
|
||||
return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
|
||||
}
|
||||
|
||||
pub fn fromSection(sec: std.elf.Section) Shndx {
|
||||
return switch (sec) {
|
||||
std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),
|
||||
std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),
|
||||
};
|
||||
}
|
||||
pub fn toSection(s: Shndx) ?std.elf.Section {
|
||||
return switch (@intFromEnum(s)) {
|
||||
std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
|
||||
std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
|
||||
reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
|
||||
sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get(s: Shndx, elf: *Elf) *Section {
|
||||
return &elf.shdrs.items[@intFromEnum(s)];
|
||||
}
|
||||
};
|
||||
pub fn shndx(si: Symbol.Index, elf: *Elf) Shndx {
|
||||
return .fromSection(switch (elf.symPtr(si)) {
|
||||
inline else => |sym| elf.targetLoad(&sym.shndx),
|
||||
});
|
||||
}
|
||||
|
||||
pub const InitOptions = struct {
|
||||
name: []const u8 = "",
|
||||
lib_name: ?[]const u8 = null,
|
||||
@@ -260,48 +330,83 @@ pub const Symbol = struct {
|
||||
type: std.elf.STT,
|
||||
bind: std.elf.STB = .LOCAL,
|
||||
visibility: std.elf.STV = .DEFAULT,
|
||||
shndx: std.elf.Section = std.elf.SHN_UNDEF,
|
||||
shndx: Shndx = .UNDEF,
|
||||
};
|
||||
pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
|
||||
const gpa = elf.base.comp.gpa;
|
||||
const target_endian = elf.targetEndian();
|
||||
const sym_size: usize = switch (elf.identClass()) {
|
||||
.NONE, _ => unreachable,
|
||||
inline else => |class| @sizeOf(class.ElfN().Sym),
|
||||
};
|
||||
const name_strtab_entry = try elf.string(.strtab, opts.name);
|
||||
try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);
|
||||
switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
|
||||
inline else => |shdr| {
|
||||
const old_size = elf.targetLoad(&shdr.size);
|
||||
const ent_size = elf.targetLoad(&shdr.entsize);
|
||||
const new_size = ent_size * elf.symtab.items.len;
|
||||
if (new_size > old_size) {
|
||||
elf.targetStore(&shdr.size, @intCast(new_size));
|
||||
const symtab_ni = elf.si.symtab.node(elf);
|
||||
_, const node_size = symtab_ni.location(&elf.mf).resolve(&elf.mf);
|
||||
if (new_size > node_size) try symtab_ni.resize(
|
||||
&elf.mf,
|
||||
gpa,
|
||||
new_size +| new_size / MappedFile.growth_factor,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
switch (elf.symPtr(si)) {
|
||||
inline else => |sym, class| {
|
||||
const Sym = class.ElfN().Sym;
|
||||
sym.* = .{
|
||||
.name = name_strtab_entry,
|
||||
.value = @intCast(opts.value),
|
||||
.size = @intCast(opts.size),
|
||||
.info = .{ .type = opts.type, .bind = opts.bind },
|
||||
.other = .{ .visibility = opts.visibility },
|
||||
.shndx = opts.shndx,
|
||||
.shndx = opts.shndx.toSection().?,
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym);
|
||||
},
|
||||
}
|
||||
switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetStore(&shdr.info, @max(
|
||||
elf.targetLoad(&shdr.info),
|
||||
@intFromEnum(si) + 1,
|
||||
)),
|
||||
}
|
||||
if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
|
||||
const dsi = elf.dynsym.items.len;
|
||||
try elf.dynsym.append(gpa, si);
|
||||
const dynsym_ni = elf.si.dynsym.node(elf);
|
||||
const name_dynstr_entry = try elf.string(.dynstr, opts.name);
|
||||
try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len);
|
||||
switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
|
||||
inline else => |shdr| {
|
||||
const old_size = elf.targetLoad(&shdr.size);
|
||||
const ent_size = elf.targetLoad(&shdr.entsize);
|
||||
const new_size = ent_size * elf.dynsym.items.len;
|
||||
if (new_size > old_size) {
|
||||
elf.targetStore(&shdr.size, @intCast(new_size));
|
||||
const dynsym_ni = elf.si.dynsym.node(elf);
|
||||
_, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);
|
||||
if (new_size > node_size) try dynsym_ni.resize(
|
||||
&elf.mf,
|
||||
gpa,
|
||||
new_size +| new_size / MappedFile.growth_factor,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
switch (elf.dynsymSlice()) {
|
||||
inline else => |dynsym, class| {
|
||||
const dsym = &dynsym[dsi];
|
||||
dsym.* = .{
|
||||
inline else => |dynsyms, class| {
|
||||
const Sym = class.ElfN().Sym;
|
||||
const dynsym = &dynsyms[dsi];
|
||||
dynsym.* = .{
|
||||
.name = name_dynstr_entry,
|
||||
.value = @intCast(opts.value),
|
||||
.size = @intCast(opts.size),
|
||||
.info = .{ .type = opts.type, .bind = opts.bind },
|
||||
.other = .{ .visibility = opts.visibility },
|
||||
.shndx = opts.shndx,
|
||||
.shndx = opts.shndx.toSection().?,
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -321,6 +426,7 @@ pub const Symbol = struct {
|
||||
}
|
||||
|
||||
pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
|
||||
if (elf.ehdrField(.type) == .REL) return;
|
||||
switch (si.get(elf).loc_relocs) {
|
||||
.none => {},
|
||||
else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
|
||||
@@ -331,6 +437,7 @@ pub const Symbol = struct {
|
||||
}
|
||||
|
||||
pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {
|
||||
if (elf.ehdrField(.type) == .REL) return;
|
||||
var ri = si.get(elf).target_relocs;
|
||||
while (ri != .none) {
|
||||
const reloc = ri.get(elf);
|
||||
@@ -374,7 +481,7 @@ pub const Reloc = extern struct {
|
||||
next: Reloc.Index,
|
||||
loc: Symbol.Index,
|
||||
target: Symbol.Index,
|
||||
unused: u32,
|
||||
index: Section.RelIndex,
|
||||
offset: u64,
|
||||
addend: i64,
|
||||
|
||||
@@ -384,6 +491,16 @@ pub const Reloc = extern struct {
|
||||
RISCV: std.elf.R_RISCV,
|
||||
PPC64: std.elf.R_PPC64,
|
||||
|
||||
pub fn none(elf: *Elf) Reloc.Type {
|
||||
return switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
.AARCH64 => .{ .AARCH64 = .NONE },
|
||||
.PPC64 => .{ .PPC64 = .NONE },
|
||||
.RISCV => .{ .RISCV = .NONE },
|
||||
.X86_64 => .{ .X86_64 = .NONE },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn absAddr(elf: *Elf) Reloc.Type {
|
||||
return switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
@@ -393,12 +510,35 @@ pub const Reloc = extern struct {
|
||||
.X86_64 => .{ .X86_64 = .@"64" },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sizeAddr(elf: *Elf) Reloc.Type {
|
||||
return switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
.X86_64 => .{ .X86_64 = .SIZE64 },
|
||||
};
|
||||
}
|
||||
|
||||
pub fn wrap(int: u32, elf: *Elf) Reloc.Type {
|
||||
return switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
inline .AARCH64,
|
||||
.PPC64,
|
||||
.RISCV,
|
||||
.X86_64,
|
||||
=> |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 {
|
||||
return switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
inline .AARCH64,
|
||||
.PPC64,
|
||||
.RISCV,
|
||||
.X86_64,
|
||||
=> |machine| @intFromEnum(@field(rt, @tagName(machine))),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Index = enum(u32) {
|
||||
@@ -411,6 +551,7 @@ pub const Reloc = extern struct {
|
||||
};
|
||||
|
||||
pub fn apply(reloc: *const Reloc, elf: *Elf) void {
|
||||
assert(elf.ehdrField(.type) != .REL);
|
||||
const loc_ni = reloc.loc.get(elf).ni;
|
||||
switch (loc_ni) {
|
||||
.none => return,
|
||||
@@ -462,7 +603,7 @@ pub const Reloc = extern struct {
|
||||
.TPOFF32 => {
|
||||
const phdr = @field(elf.phdrSlice(), @tagName(class));
|
||||
const ph = &phdr[elf.getNode(elf.ni.tls).segment];
|
||||
assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS);
|
||||
assert(elf.targetLoad(&ph.type) == .TLS);
|
||||
std.mem.writeInt(
|
||||
i32,
|
||||
loc_slice[0..4],
|
||||
@@ -501,6 +642,33 @@ pub const Reloc = extern struct {
|
||||
.none => {},
|
||||
else => |next| next.get(elf).prev = reloc.prev,
|
||||
}
|
||||
switch (elf.ehdrField(.type)) {
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL => {
|
||||
const sh = reloc.loc.shndx(elf).get(elf);
|
||||
switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
|
||||
inline else => |shdr, class| {
|
||||
const Rela = class.ElfN().Rela;
|
||||
const ent_size = elf.targetLoad(&shdr.entsize);
|
||||
const start = ent_size * reloc.index.unwrap().?;
|
||||
const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
|
||||
const rela: *Rela = @ptrCast(@alignCast(
|
||||
rela_slice[@intCast(start)..][0..@intCast(ent_size)],
|
||||
));
|
||||
rela.* = .{
|
||||
.offset = @intFromEnum(sh.rela_free),
|
||||
.info = .{
|
||||
.type = @intCast(Reloc.Type.none(elf).unwrap(elf)),
|
||||
.sym = 0,
|
||||
},
|
||||
.addend = 0,
|
||||
};
|
||||
},
|
||||
}
|
||||
sh.rela_free = reloc.index;
|
||||
},
|
||||
.EXEC, .DYN => assert(reloc.index == .none),
|
||||
}
|
||||
reloc.* = undefined;
|
||||
}
|
||||
|
||||
@@ -601,6 +769,7 @@ fn create(
|
||||
.tls = .none,
|
||||
},
|
||||
.nodes = .empty,
|
||||
.shdrs = .empty,
|
||||
.phdrs = .empty,
|
||||
.si = .{
|
||||
.dynsym = .null,
|
||||
@@ -611,16 +780,13 @@ fn create(
|
||||
.symtab = .empty,
|
||||
.shstrtab = .{
|
||||
.map = .empty,
|
||||
.size = 1,
|
||||
},
|
||||
.strtab = .{
|
||||
.map = .empty,
|
||||
.size = 1,
|
||||
},
|
||||
.dynsym = .empty,
|
||||
.dynstr = .{
|
||||
.map = .empty,
|
||||
.size = 1,
|
||||
},
|
||||
.needed = .empty,
|
||||
.inputs = .empty,
|
||||
@@ -650,6 +816,7 @@ pub fn deinit(elf: *Elf) void {
|
||||
const gpa = elf.base.comp.gpa;
|
||||
elf.mf.deinit(gpa);
|
||||
elf.nodes.deinit(gpa);
|
||||
elf.shdrs.deinit(gpa);
|
||||
elf.phdrs.deinit(gpa);
|
||||
elf.symtab.deinit(gpa);
|
||||
elf.shstrtab.map.deinit(gpa);
|
||||
@@ -681,11 +848,10 @@ fn initHeaders(
|
||||
const comp = elf.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const have_dynamic_section = switch (@"type") {
|
||||
.NONE => unreachable,
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL => false,
|
||||
.EXEC => comp.config.link_mode == .dynamic,
|
||||
.DYN => true,
|
||||
.CORE, _ => unreachable,
|
||||
};
|
||||
const addr_align: std.mem.Alignment = switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
@@ -693,6 +859,7 @@ fn initHeaders(
|
||||
.@"64" => .@"8",
|
||||
};
|
||||
|
||||
const shnum: u32 = 1;
|
||||
var phnum: u32 = 0;
|
||||
const phdr_phndx = phnum;
|
||||
phnum += 1;
|
||||
@@ -715,8 +882,17 @@ fn initHeaders(
|
||||
break :phndx phnum;
|
||||
} else undefined;
|
||||
|
||||
const expected_nodes_len = 5 + phnum * 2 + @as(usize, 2) * @intFromBool(have_dynamic_section);
|
||||
const expected_nodes_len = expected_nodes_len: switch (@"type") {
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL => {
|
||||
defer phnum = 0;
|
||||
break :expected_nodes_len 5 + phnum;
|
||||
},
|
||||
.EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +
|
||||
@as(usize, 2) * @intFromBool(have_dynamic_section),
|
||||
};
|
||||
try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
|
||||
try elf.shdrs.ensureTotalCapacity(gpa, shnum);
|
||||
try elf.phdrs.resize(gpa, phnum);
|
||||
elf.nodes.appendAssumeCapacity(.file);
|
||||
|
||||
@@ -751,7 +927,7 @@ fn initHeaders(
|
||||
ehdr.phentsize = @sizeOf(ElfN.Phdr);
|
||||
ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
|
||||
ehdr.shentsize = @sizeOf(ElfN.Shdr);
|
||||
ehdr.shnum = 1;
|
||||
ehdr.shnum = if (shnum < std.elf.SHN_LORESERVE) shnum else 0;
|
||||
ehdr.shstrndx = std.elf.SHN_UNDEF;
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
|
||||
},
|
||||
@@ -759,181 +935,187 @@ fn initHeaders(
|
||||
|
||||
assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
|
||||
.alignment = addr_align,
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.resized = true,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.shdr);
|
||||
|
||||
assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
|
||||
elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
|
||||
var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: {
|
||||
assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx });
|
||||
elf.phdrs.items[rodata_phndx] = elf.ni.rodata;
|
||||
|
||||
assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
|
||||
.size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
|
||||
.alignment = addr_align,
|
||||
.moved = true,
|
||||
.resized = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
|
||||
elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
|
||||
assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{
|
||||
.size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum),
|
||||
.alignment = addr_align,
|
||||
.moved = true,
|
||||
.resized = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx });
|
||||
elf.phdrs.items[phdr_phndx] = elf.ni.phdr;
|
||||
|
||||
assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
|
||||
elf.phdrs.items[text_phndx] = elf.ni.text;
|
||||
assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx });
|
||||
elf.phdrs.items[text_phndx] = elf.ni.text;
|
||||
|
||||
assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
|
||||
elf.phdrs.items[data_phndx] = elf.ni.data;
|
||||
assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
}));
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx });
|
||||
elf.phdrs.items[data_phndx] = elf.ni.data;
|
||||
|
||||
var ph_vaddr: u32 = switch (elf.ehdrField(.type)) {
|
||||
else => 0,
|
||||
.EXEC => switch (elf.ehdrField(.machine)) {
|
||||
.@"386" => 0x400000,
|
||||
.AARCH64, .X86_64 => 0x200000,
|
||||
.PPC, .PPC64 => 0x10000000,
|
||||
.S390, .S390_OLD => 0x1000000,
|
||||
.OLD_SPARCV9, .SPARCV9 => 0x100000,
|
||||
else => 0x10000,
|
||||
},
|
||||
};
|
||||
break :ph_vaddr switch (elf.ehdrField(.type)) {
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL, .DYN => 0,
|
||||
.EXEC => switch (elf.ehdrField(.machine)) {
|
||||
.@"386" => 0x400000,
|
||||
.AARCH64, .X86_64 => 0x200000,
|
||||
.PPC, .PPC64 => 0x10000000,
|
||||
.S390, .S390_OLD => 0x1000000,
|
||||
.OLD_SPARCV9, .SPARCV9 => 0x100000,
|
||||
else => 0x10000,
|
||||
},
|
||||
};
|
||||
} else undefined;
|
||||
switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
inline else => |ct_class| {
|
||||
const ElfN = ct_class.ElfN();
|
||||
const target_endian = elf.targetEndian();
|
||||
|
||||
const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
|
||||
const ph_phdr = &phdr[phdr_phndx];
|
||||
ph_phdr.* = .{
|
||||
.type = std.elf.PT_PHDR,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
|
||||
|
||||
if (maybe_interp) |_| {
|
||||
const ph_interp = &phdr[interp_phndx];
|
||||
ph_interp.* = .{
|
||||
.type = std.elf.PT_INTERP,
|
||||
if (@"type" != .REL) {
|
||||
const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf)));
|
||||
const ph_phdr = &phdr[phdr_phndx];
|
||||
ph_phdr.* = .{
|
||||
.type = .PHDR,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = 1,
|
||||
.@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
|
||||
}
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr);
|
||||
|
||||
_, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_rodata = &phdr[rodata_phndx];
|
||||
ph_rodata.* = .{
|
||||
.type = std.elf.PT_NULL,
|
||||
.offset = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(rodata_size),
|
||||
.memsz = @intCast(rodata_size),
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
|
||||
ph_vaddr += @intCast(rodata_size);
|
||||
if (maybe_interp) |_| {
|
||||
const ph_interp = &phdr[interp_phndx];
|
||||
ph_interp.* = .{
|
||||
.type = .INTERP,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = 1,
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp);
|
||||
}
|
||||
|
||||
_, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_text = &phdr[text_phndx];
|
||||
ph_text.* = .{
|
||||
.type = std.elf.PT_NULL,
|
||||
.offset = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(text_size),
|
||||
.memsz = @intCast(text_size),
|
||||
.flags = .{ .R = true, .X = true },
|
||||
.@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
|
||||
ph_vaddr += @intCast(text_size);
|
||||
|
||||
_, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_data = &phdr[data_phndx];
|
||||
ph_data.* = .{
|
||||
.type = std.elf.PT_NULL,
|
||||
.offset = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(data_size),
|
||||
.memsz = @intCast(data_size),
|
||||
.flags = .{ .R = true, .W = true },
|
||||
.@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
|
||||
ph_vaddr += @intCast(data_size);
|
||||
|
||||
if (have_dynamic_section) {
|
||||
const ph_dynamic = &phdr[dynamic_phndx];
|
||||
ph_dynamic.* = .{
|
||||
.type = std.elf.PT_DYNAMIC,
|
||||
_, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_rodata = &phdr[rodata_phndx];
|
||||
ph_rodata.* = .{
|
||||
.type = if (rodata_size == 0) .NULL else .LOAD,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(rodata_size),
|
||||
.memsz = @intCast(rodata_size),
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata);
|
||||
ph_vaddr += @intCast(rodata_size);
|
||||
|
||||
_, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_text = &phdr[text_phndx];
|
||||
ph_text.* = .{
|
||||
.type = if (text_size == 0) .NULL else .LOAD,
|
||||
.offset = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(text_size),
|
||||
.memsz = @intCast(text_size),
|
||||
.flags = .{ .R = true, .X = true },
|
||||
.@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text);
|
||||
ph_vaddr += @intCast(text_size);
|
||||
|
||||
_, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf);
|
||||
const ph_data = &phdr[data_phndx];
|
||||
ph_data.* = .{
|
||||
.type = if (data_size == 0) .NULL else .LOAD,
|
||||
.offset = 0,
|
||||
.vaddr = ph_vaddr,
|
||||
.paddr = ph_vaddr,
|
||||
.filesz = @intCast(data_size),
|
||||
.memsz = @intCast(data_size),
|
||||
.flags = .{ .R = true, .W = true },
|
||||
.@"align" = @intCast(addr_align.toByteUnits()),
|
||||
.@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data);
|
||||
ph_vaddr += @intCast(data_size);
|
||||
|
||||
if (have_dynamic_section) {
|
||||
const ph_dynamic = &phdr[dynamic_phndx];
|
||||
ph_dynamic.* = .{
|
||||
.type = .DYNAMIC,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true, .W = true },
|
||||
.@"align" = @intCast(addr_align.toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic);
|
||||
}
|
||||
|
||||
if (comp.config.any_non_single_threaded) {
|
||||
const ph_tls = &phdr[tls_phndx];
|
||||
ph_tls.* = .{
|
||||
.type = .TLS,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
|
||||
}
|
||||
}
|
||||
|
||||
if (comp.config.any_non_single_threaded) {
|
||||
const ph_tls = &phdr[tls_phndx];
|
||||
ph_tls.* = .{
|
||||
.type = std.elf.PT_TLS,
|
||||
.offset = 0,
|
||||
.vaddr = 0,
|
||||
.paddr = 0,
|
||||
.filesz = 0,
|
||||
.memsz = 0,
|
||||
.flags = .{ .R = true },
|
||||
.@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()),
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls);
|
||||
}
|
||||
|
||||
const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
|
||||
sh_null.* = .{
|
||||
const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
|
||||
sh_undef.* = .{
|
||||
.name = try elf.string(.shstrtab, ""),
|
||||
.type = std.elf.SHT_NULL,
|
||||
.type = .NULL,
|
||||
.flags = .{ .shf = .{} },
|
||||
.addr = 0,
|
||||
.offset = 0,
|
||||
.size = 0,
|
||||
.size = if (shnum < std.elf.SHN_LORESERVE) 0 else shnum,
|
||||
.link = 0,
|
||||
.info = if (phnum >= std.elf.PN_XNUM) phnum else 0,
|
||||
.info = if (phnum < std.elf.PN_XNUM) 0 else phnum,
|
||||
.addralign = 0,
|
||||
.entsize = 0,
|
||||
};
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null);
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
|
||||
elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none });
|
||||
|
||||
try elf.symtab.ensureTotalCapacity(gpa, 1);
|
||||
elf.symtab.addOneAssumeCapacity().* = .{
|
||||
@@ -943,10 +1125,11 @@ fn initHeaders(
|
||||
.unused = 0,
|
||||
};
|
||||
assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{
|
||||
.type = std.elf.SHT_SYMTAB,
|
||||
.type = .SYMTAB,
|
||||
.size = @sizeOf(ElfN.Sym) * 1,
|
||||
.addralign = addr_align,
|
||||
.entsize = @sizeOf(ElfN.Sym),
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
}));
|
||||
const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
|
||||
symtab_null.* = .{
|
||||
@@ -960,13 +1143,14 @@ fn initHeaders(
|
||||
if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
|
||||
|
||||
const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
|
||||
ehdr.shstrndx = ehdr.shnum;
|
||||
elf.targetStore(&ehdr.shstrndx, ehdr.shnum);
|
||||
},
|
||||
}
|
||||
assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
|
||||
.type = std.elf.SHT_STRTAB,
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
.type = .STRTAB,
|
||||
.size = 1,
|
||||
.entsize = 1,
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
}));
|
||||
try elf.renameSection(.symtab, ".symtab");
|
||||
try elf.renameSection(.shstrtab, ".shstrtab");
|
||||
@@ -974,10 +1158,10 @@ fn initHeaders(
|
||||
|
||||
assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{
|
||||
.name = ".strtab",
|
||||
.type = std.elf.SHT_STRTAB,
|
||||
.type = .STRTAB,
|
||||
.size = 1,
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
.entsize = 1,
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
}));
|
||||
try elf.linkSections(.symtab, .strtab);
|
||||
elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
|
||||
@@ -997,87 +1181,96 @@ fn initHeaders(
|
||||
.flags = .{ .WRITE = true, .ALLOC = true },
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
}));
|
||||
if (maybe_interp) |interp| {
|
||||
const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
|
||||
.size = interp.len + 1,
|
||||
.moved = true,
|
||||
.resized = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
|
||||
elf.phdrs.items[interp_phndx] = interp_ni;
|
||||
if (@"type" != .REL) {
|
||||
if (maybe_interp) |interp| {
|
||||
const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
|
||||
.size = interp.len + 1,
|
||||
.moved = true,
|
||||
.resized = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
|
||||
elf.phdrs.items[interp_phndx] = interp_ni;
|
||||
|
||||
const sec_interp_si = try elf.addSection(interp_ni, .{
|
||||
.name = ".interp",
|
||||
.flags = .{ .ALLOC = true },
|
||||
.size = @intCast(interp.len + 1),
|
||||
});
|
||||
const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
|
||||
@memcpy(sec_interp[0..interp.len], interp);
|
||||
sec_interp[interp.len] = 0;
|
||||
}
|
||||
if (have_dynamic_section) {
|
||||
const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
|
||||
elf.phdrs.items[dynamic_phndx] = dynamic_ni;
|
||||
|
||||
switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
inline else => |ct_class| {
|
||||
const ElfN = ct_class.ElfN();
|
||||
elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
|
||||
.name = ".dynsym",
|
||||
.type = std.elf.SHT_DYNSYM,
|
||||
.size = @sizeOf(ElfN.Sym) * 1,
|
||||
.addralign = addr_align,
|
||||
.entsize = @sizeOf(ElfN.Sym),
|
||||
});
|
||||
const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
|
||||
dynsym_null.* = .{
|
||||
.name = try elf.string(.dynstr, ""),
|
||||
.value = 0,
|
||||
.size = 0,
|
||||
.info = .{ .type = .NOTYPE, .bind = .LOCAL },
|
||||
.other = .{ .visibility = .DEFAULT },
|
||||
.shndx = std.elf.SHN_UNDEF,
|
||||
};
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null);
|
||||
},
|
||||
const sec_interp_si = try elf.addSection(interp_ni, .{
|
||||
.type = .PROGBITS,
|
||||
.name = ".interp",
|
||||
.flags = .{ .ALLOC = true },
|
||||
.size = @intCast(interp.len + 1),
|
||||
});
|
||||
const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
|
||||
@memcpy(sec_interp[0..interp.len], interp);
|
||||
sec_interp[interp.len] = 0;
|
||||
}
|
||||
elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
|
||||
.name = ".dynstr",
|
||||
.type = std.elf.SHT_STRTAB,
|
||||
.size = 1,
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
.entsize = 1,
|
||||
});
|
||||
elf.si.dynamic = try elf.addSection(dynamic_ni, .{
|
||||
.name = ".dynamic",
|
||||
.type = std.elf.SHT_DYNAMIC,
|
||||
.flags = .{ .ALLOC = true, .WRITE = true },
|
||||
.addralign = addr_align,
|
||||
});
|
||||
try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
|
||||
try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
|
||||
}
|
||||
if (comp.config.any_non_single_threaded) {
|
||||
elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
|
||||
elf.phdrs.items[tls_phndx] = elf.ni.tls;
|
||||
if (have_dynamic_section) {
|
||||
const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
|
||||
elf.phdrs.items[dynamic_phndx] = dynamic_ni;
|
||||
|
||||
elf.si.tdata = try elf.addSection(elf.ni.tls, .{
|
||||
.name = ".tdata",
|
||||
.flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
});
|
||||
switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
inline else => |ct_class| {
|
||||
const Sym = ct_class.ElfN().Sym;
|
||||
elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
|
||||
.name = ".dynsym",
|
||||
.type = .DYNSYM,
|
||||
.size = @sizeOf(Sym) * 1,
|
||||
.addralign = addr_align,
|
||||
.entsize = @sizeOf(Sym),
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
});
|
||||
const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
|
||||
dynsym_null.* = .{
|
||||
.name = try elf.string(.dynstr, ""),
|
||||
.value = 0,
|
||||
.size = 0,
|
||||
.info = .{ .type = .NOTYPE, .bind = .LOCAL },
|
||||
.other = .{ .visibility = .DEFAULT },
|
||||
.shndx = std.elf.SHN_UNDEF,
|
||||
};
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(
|
||||
Sym,
|
||||
dynsym_null,
|
||||
);
|
||||
},
|
||||
}
|
||||
elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
|
||||
.name = ".dynstr",
|
||||
.type = .STRTAB,
|
||||
.size = 1,
|
||||
.entsize = 1,
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
});
|
||||
elf.si.dynamic = try elf.addSection(dynamic_ni, .{
|
||||
.name = ".dynamic",
|
||||
.type = .DYNAMIC,
|
||||
.flags = .{ .ALLOC = true, .WRITE = true },
|
||||
.node_align = addr_align,
|
||||
});
|
||||
try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
|
||||
try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
|
||||
}
|
||||
if (comp.config.any_non_single_threaded) {
|
||||
elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
|
||||
.alignment = elf.mf.flags.block_size,
|
||||
.moved = true,
|
||||
.bubbles_moved = false,
|
||||
});
|
||||
elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
|
||||
elf.phdrs.items[tls_phndx] = elf.ni.tls;
|
||||
}
|
||||
} else {
|
||||
assert(maybe_interp == null);
|
||||
assert(!have_dynamic_section);
|
||||
}
|
||||
if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{
|
||||
.name = ".tdata",
|
||||
.flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
|
||||
.addralign = elf.mf.flags.block_size,
|
||||
});
|
||||
assert(elf.nodes.len == expected_nodes_len);
|
||||
}
|
||||
|
||||
@@ -1116,7 +1309,7 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 {
|
||||
.file => return 0,
|
||||
.ehdr, .shdr => unreachable,
|
||||
.segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) {
|
||||
inline else => |ph| elf.targetLoad(&ph[phndx].vaddr),
|
||||
inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr),
|
||||
},
|
||||
.section => |si| si,
|
||||
.input_section => unreachable,
|
||||
@@ -1202,6 +1395,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
|
||||
@"64": []std.elf.Elf64.Phdr,
|
||||
};
|
||||
pub fn phdrSlice(elf: *Elf) PhdrSlice {
|
||||
assert(elf.ehdrField(.type) != .REL);
|
||||
const slice = elf.ni.phdr.slice(&elf.mf);
|
||||
return switch (elf.identClass()) {
|
||||
.NONE, _ => unreachable,
|
||||
@@ -1230,6 +1424,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
|
||||
};
|
||||
}
|
||||
|
||||
pub const ShdrPtr = union(std.elf.CLASS) {
|
||||
NONE: noreturn,
|
||||
@"32": *std.elf.Elf32.Shdr,
|
||||
@"64": *std.elf.Elf64.Shdr,
|
||||
};
|
||||
pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {
|
||||
return switch (elf.shdrSlice()) {
|
||||
inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),
|
||||
};
|
||||
}
|
||||
|
||||
pub const SymtabSlice = union(std.elf.CLASS) {
|
||||
NONE: noreturn,
|
||||
@"32": []std.elf.Elf32.Sym,
|
||||
@@ -1242,7 +1447,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {
|
||||
inline else => |class| @unionInit(
|
||||
SymtabSlice,
|
||||
@tagName(class),
|
||||
@ptrCast(@alignCast(slice)),
|
||||
@ptrCast(@alignCast(slice[0..std.mem.alignBackwardAnyAlign(
|
||||
usize,
|
||||
slice.len,
|
||||
@sizeOf(class.ElfN().Sym),
|
||||
)])),
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -1254,7 +1463,7 @@ pub const SymPtr = union(std.elf.CLASS) {
|
||||
};
|
||||
pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
|
||||
return switch (elf.symtabSlice()) {
|
||||
inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]),
|
||||
inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1544,7 +1753,7 @@ fn loadObject(
|
||||
.si = try elf.initSymbolAssumeCapacity(.{
|
||||
.name = std.fs.path.stem(member orelse path.sub_path),
|
||||
.type = .FILE,
|
||||
.shndx = std.elf.SHN_ABS,
|
||||
.shndx = .ABS,
|
||||
}),
|
||||
};
|
||||
const target_endian = elf.targetEndian();
|
||||
@@ -1571,7 +1780,7 @@ fn loadObject(
|
||||
};
|
||||
try r.discardAll(ehdr.shentsize);
|
||||
switch (section.shdr.type) {
|
||||
std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
|
||||
.NULL, .NOBITS => {},
|
||||
else => if (section.shdr.offset + section.shdr.size > fl.size)
|
||||
return diags.failParse(path, "bad section location", .{}),
|
||||
}
|
||||
@@ -1580,8 +1789,7 @@ fn loadObject(
|
||||
if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum)
|
||||
return diags.failParse(path, "missing section names", .{});
|
||||
const shdr = §ions[ehdr.shstrndx].shdr;
|
||||
if (shdr.type != std.elf.SHT_STRTAB)
|
||||
return diags.failParse(path, "invalid shstrtab type", .{});
|
||||
if (shdr.type != .STRTAB) return diags.failParse(path, "invalid shstrtab type", .{});
|
||||
const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
|
||||
errdefer gpa.free(shstrtab);
|
||||
try fr.seekTo(fl.offset + shdr.offset);
|
||||
@@ -1594,7 +1802,7 @@ fn loadObject(
|
||||
try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1);
|
||||
for (sections[1..]) |*section| switch (section.shdr.type) {
|
||||
else => {},
|
||||
std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => {
|
||||
.PROGBITS, .NOBITS => {
|
||||
if (section.shdr.name >= shstrtab.len) continue;
|
||||
const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0);
|
||||
const parent_si = elf.namedSection(name) orelse continue;
|
||||
@@ -1611,7 +1819,7 @@ fn loadObject(
|
||||
});
|
||||
section.si = try elf.initSymbolAssumeCapacity(.{
|
||||
.type = .SECTION,
|
||||
.shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx),
|
||||
.shndx = parent_si.shndx(elf),
|
||||
});
|
||||
section.si.get(elf).ni = ni;
|
||||
elf.input_sections.addOneAssumeCapacity().* = .{
|
||||
@@ -1629,14 +1837,14 @@ fn loadObject(
|
||||
defer symmap.deinit(gpa);
|
||||
for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) {
|
||||
else => {},
|
||||
std.elf.SHT_SYMTAB => {
|
||||
.SYMTAB => {
|
||||
if (symtab.shdr.entsize < @sizeOf(ElfN.Sym))
|
||||
return diags.failParse(path, "unsupported symtab entsize", .{});
|
||||
const strtab = strtab: {
|
||||
if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum)
|
||||
return diags.failParse(path, "missing symbol names", .{});
|
||||
const shdr = §ions[symtab.shdr.link].shdr;
|
||||
if (shdr.type != std.elf.SHT_STRTAB)
|
||||
if (shdr.type != .STRTAB)
|
||||
return diags.failParse(path, "invalid strtab type", .{});
|
||||
const strtab = try gpa.alloc(u8, @intCast(shdr.size));
|
||||
errdefer gpa.free(strtab);
|
||||
@@ -1683,9 +1891,7 @@ fn loadObject(
|
||||
.type = input_sym.info.type,
|
||||
.bind = input_sym.info.bind,
|
||||
.visibility = input_sym.other.visibility,
|
||||
.shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) {
|
||||
inline else => |parent_sym| &parent_sym.shndx,
|
||||
}),
|
||||
.shndx = parent_si.shndx(elf),
|
||||
});
|
||||
si.get(elf).ni = parent_si.get(elf).ni;
|
||||
switch (input_sym.info.bind) {
|
||||
@@ -1719,13 +1925,13 @@ fn loadObject(
|
||||
}
|
||||
for (sections[1..]) |*rels| switch (rels.shdr.type) {
|
||||
else => {},
|
||||
inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| {
|
||||
inline .REL, .RELA => |sht| {
|
||||
if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or
|
||||
rels.shdr.info >= ehdr.shnum) continue;
|
||||
const Rel = switch (sht) {
|
||||
else => comptime unreachable,
|
||||
std.elf.SHT_REL => ElfN.Rel,
|
||||
std.elf.SHT_RELA => ElfN.Rela,
|
||||
.REL => ElfN.Rel,
|
||||
.RELA => ElfN.Rela,
|
||||
};
|
||||
if (rels.shdr.entsize < @sizeOf(Rel))
|
||||
return diags.failParse(path, "unsupported rel entsize", .{});
|
||||
@@ -1740,7 +1946,7 @@ fn loadObject(
|
||||
"relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
|
||||
.{ rels.shdr.size, rels.shdr.entsize },
|
||||
);
|
||||
try elf.relocs.ensureUnusedCapacity(gpa, relnum);
|
||||
try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
|
||||
try fr.seekTo(fl.offset + rels.shdr.offset);
|
||||
for (0..relnum) |_| {
|
||||
const rel = try r.peekStruct(Rel, target_endian);
|
||||
@@ -1753,18 +1959,7 @@ fn loadObject(
|
||||
rel.offset - loc_sec.shdr.addr,
|
||||
target_si,
|
||||
rel.addend,
|
||||
switch (elf.ehdrField(.machine)) {
|
||||
else => unreachable,
|
||||
inline .AARCH64,
|
||||
.PPC64,
|
||||
.RISCV,
|
||||
.X86_64,
|
||||
=> |machine| @unionInit(
|
||||
Reloc.Type,
|
||||
@tagName(machine),
|
||||
@enumFromInt(rel.info.type),
|
||||
),
|
||||
},
|
||||
.wrap(rel.info.type, elf),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -1800,7 +1995,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
|
||||
try r.discardAll(ehdr.phentsize);
|
||||
switch (ph.type) {
|
||||
else => {},
|
||||
std.elf.PT_DYNAMIC => break ph,
|
||||
.DYNAMIC => break ph,
|
||||
}
|
||||
} else return diags.failParse(path, "no dynamic segment", .{});
|
||||
const dynnum = std.math.divExact(
|
||||
@@ -1817,13 +2012,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
|
||||
var soname: ?ElfN.Addr = null;
|
||||
try fr.seekTo(dynamic_ph.offset);
|
||||
for (0..dynnum) |_| {
|
||||
const key = try r.takeInt(ElfN.Addr, target_endian);
|
||||
const value = try r.takeInt(ElfN.Addr, target_endian);
|
||||
switch (key) {
|
||||
const tag = try r.takeInt(ElfN.Addr, target_endian);
|
||||
const val = try r.takeInt(ElfN.Addr, target_endian);
|
||||
switch (tag) {
|
||||
else => {},
|
||||
std.elf.DT_STRTAB => strtab = value,
|
||||
std.elf.DT_STRSZ => strsz = value,
|
||||
std.elf.DT_SONAME => soname = value,
|
||||
std.elf.DT_STRTAB => strtab = val,
|
||||
std.elf.DT_STRSZ => strsz = val,
|
||||
std.elf.DT_SONAME => soname = val,
|
||||
}
|
||||
}
|
||||
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
|
||||
try r.discardAll(ehdr.phentsize);
|
||||
switch (ph.type) {
|
||||
else => {},
|
||||
std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and
|
||||
.LOAD => if (strtab.? >= ph.vaddr and
|
||||
strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph,
|
||||
}
|
||||
} else return diags.failParse(path, "strtab not part of a loaded segment", .{});
|
||||
@@ -1868,11 +2063,7 @@ fn prelinkInner(elf: *Elf) !void {
|
||||
std.fs.path.stem(elf.base.emit.sub_path),
|
||||
});
|
||||
defer gpa.free(zcu_name);
|
||||
const si = try elf.initSymbolAssumeCapacity(.{
|
||||
.name = zcu_name,
|
||||
.type = .FILE,
|
||||
.shndx = std.elf.SHN_ABS,
|
||||
});
|
||||
const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });
|
||||
elf.inputs.addOneAssumeCapacity().* = .{
|
||||
.path = elf.base.emit,
|
||||
.member = null,
|
||||
@@ -1972,63 +2163,87 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In
|
||||
|
||||
fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
|
||||
name: []const u8 = "",
|
||||
type: std.elf.Word = std.elf.SHT_NULL,
|
||||
type: std.elf.SHT = .NULL,
|
||||
flags: std.elf.SHF = .{},
|
||||
size: std.elf.Word = 0,
|
||||
size: std.elf.Xword = 0,
|
||||
link: std.elf.Word = 0,
|
||||
info: std.elf.Word = 0,
|
||||
addralign: std.mem.Alignment = .@"1",
|
||||
entsize: std.elf.Word = 0,
|
||||
node_align: std.mem.Alignment = .@"1",
|
||||
}) !Symbol.Index {
|
||||
switch (opts.type) {
|
||||
std.elf.SHT_NULL => assert(opts.size == 0),
|
||||
std.elf.SHT_PROGBITS => assert(opts.size > 0),
|
||||
.NULL => assert(opts.size == 0),
|
||||
.PROGBITS => assert(opts.size > 0),
|
||||
else => {},
|
||||
}
|
||||
const gpa = elf.base.comp.gpa;
|
||||
try elf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
try elf.shdrs.ensureUnusedCapacity(gpa, 1);
|
||||
try elf.symtab.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const shstrtab_entry = try elf.string(.shstrtab, opts.name);
|
||||
const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) {
|
||||
inline else => |ehdr| {
|
||||
const shndx = elf.targetLoad(&ehdr.shnum);
|
||||
const shnum = shndx + 1;
|
||||
elf.targetStore(&ehdr.shnum, shnum);
|
||||
break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };
|
||||
const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
|
||||
inline else => |ehdr, class| {
|
||||
const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
|
||||
1...std.elf.SHN_LORESERVE - 2 => |shndx| {
|
||||
const shnum = shndx + 1;
|
||||
elf.targetStore(&ehdr.shnum, shnum);
|
||||
break :alloc_shndx .{ shndx, shnum };
|
||||
},
|
||||
std.elf.SHN_LORESERVE - 1 => |shndx| {
|
||||
const shnum = shndx + 1;
|
||||
elf.targetStore(&ehdr.shnum, 0);
|
||||
elf.targetStore(&@field(elf.shdrPtr(.UNDEF), @tagName(class)).size, shnum);
|
||||
break :alloc_shndx .{ shndx, shnum };
|
||||
},
|
||||
std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => unreachable,
|
||||
0 => {
|
||||
const shnum_ptr = &@field(elf.shdrPtr(.UNDEF), @tagName(class)).size;
|
||||
const shndx: u32 = @intCast(elf.targetLoad(shnum_ptr));
|
||||
const shnum = shndx + 1;
|
||||
elf.targetStore(shnum_ptr, shnum);
|
||||
break :alloc_shndx .{ shndx, shnum };
|
||||
},
|
||||
};
|
||||
assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));
|
||||
break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
|
||||
},
|
||||
};
|
||||
try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);
|
||||
const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{
|
||||
.alignment = opts.addralign,
|
||||
_, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
|
||||
if (new_shdr_size > shdr_node_size)
|
||||
try elf.ni.shdr.resize(&elf.mf, gpa, new_shdr_size +| new_shdr_size / MappedFile.growth_factor);
|
||||
const ni = try elf.mf.addLastChildNode(gpa, switch (elf.ehdrField(.type)) {
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL => elf.ni.file,
|
||||
.EXEC, .DYN => segment_ni,
|
||||
}, .{
|
||||
.alignment = opts.addralign.max(opts.node_align),
|
||||
.size = opts.size,
|
||||
.resized = opts.size > 0,
|
||||
});
|
||||
const si = elf.addSymbolAssumeCapacity();
|
||||
elf.nodes.appendAssumeCapacity(.{ .section = si });
|
||||
elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none });
|
||||
si.get(elf).ni = ni;
|
||||
const addr = elf.computeNodeVAddr(ni);
|
||||
const offset = ni.fileLocation(&elf.mf, false).offset;
|
||||
try si.init(elf, .{
|
||||
.value = addr,
|
||||
.size = opts.size,
|
||||
.type = .SECTION,
|
||||
.shndx = shndx,
|
||||
});
|
||||
switch (elf.shdrSlice()) {
|
||||
inline else => |shdr| {
|
||||
const sh = &shdr[shndx];
|
||||
sh.* = .{
|
||||
try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
|
||||
switch (elf.shdrPtr(shndx)) {
|
||||
inline else => |shdr, class| {
|
||||
shdr.* = .{
|
||||
.name = shstrtab_entry,
|
||||
.type = opts.type,
|
||||
.flags = .{ .shf = opts.flags },
|
||||
.addr = @intCast(addr),
|
||||
.offset = @intCast(offset),
|
||||
.size = opts.size,
|
||||
.link = 0,
|
||||
.info = 0,
|
||||
.size = @intCast(opts.size),
|
||||
.link = opts.link,
|
||||
.info = opts.info,
|
||||
.addralign = @intCast(opts.addralign.toByteUnits()),
|
||||
.entsize = opts.entsize,
|
||||
};
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh);
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
|
||||
},
|
||||
}
|
||||
return si;
|
||||
@@ -2036,39 +2251,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
|
||||
|
||||
fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
|
||||
const shstrtab_entry = try elf.string(.shstrtab, name);
|
||||
switch (elf.shdrSlice()) {
|
||||
inline else => |shdr, class| elf.targetStore(
|
||||
&shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
|
||||
shstrtab_entry,
|
||||
),
|
||||
switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
|
||||
}
|
||||
}
|
||||
|
||||
fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
|
||||
switch (elf.shdrSlice()) {
|
||||
inline else => |shdr, class| shdr[
|
||||
elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)
|
||||
].link = @field(elf.symPtr(link_si), @tagName(class)).shndx,
|
||||
switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
|
||||
}
|
||||
}
|
||||
|
||||
fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
|
||||
const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {
|
||||
inline else => |shndx, class| elf.targetLoad(
|
||||
&shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
|
||||
),
|
||||
const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetLoad(&shdr.name),
|
||||
}..];
|
||||
return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
|
||||
}
|
||||
|
||||
fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
|
||||
if (key.len == 0) return 0;
|
||||
return @field(elf, @tagName(section)).get(
|
||||
elf.base.comp.gpa,
|
||||
&elf.mf,
|
||||
@field(elf.si, @tagName(section)).node(elf),
|
||||
key,
|
||||
);
|
||||
return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
|
||||
}
|
||||
|
||||
pub fn addReloc(
|
||||
@@ -2079,9 +2282,51 @@ pub fn addReloc(
|
||||
addend: i64,
|
||||
@"type": Reloc.Type,
|
||||
) !void {
|
||||
try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1);
|
||||
try elf.ensureUnusedRelocCapacity(loc_si, 1);
|
||||
elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
|
||||
}
|
||||
pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
|
||||
if (len == 0) return;
|
||||
const gpa = elf.base.comp.gpa;
|
||||
|
||||
try elf.relocs.ensureUnusedCapacity(gpa, len);
|
||||
if (elf.ehdrField(.type) != .REL) return;
|
||||
|
||||
const shndx = loc_si.shndx(elf);
|
||||
const sh = shndx.get(elf);
|
||||
if (sh.rela_si == .null) {
|
||||
var stack = std.heap.stackFallback(32, gpa);
|
||||
const allocator = stack.get();
|
||||
|
||||
const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
|
||||
defer allocator.free(rela_name);
|
||||
|
||||
const class = elf.identClass();
|
||||
sh.rela_si = try elf.addSection(.none, .{
|
||||
.name = rela_name,
|
||||
.type = .RELA,
|
||||
.link = @intFromEnum(elf.si.symtab.shndx(elf)),
|
||||
.info = @intFromEnum(shndx),
|
||||
.addralign = switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
.@"32" => .@"4",
|
||||
.@"64" => .@"8",
|
||||
},
|
||||
.entsize = switch (class) {
|
||||
.NONE, _ => unreachable,
|
||||
inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
|
||||
},
|
||||
.node_align = elf.mf.flags.block_size,
|
||||
});
|
||||
}
|
||||
const rela_ni = sh.rela_si.node(elf);
|
||||
_, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
|
||||
const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len,
|
||||
};
|
||||
if (rela_size > rela_node_size)
|
||||
try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
|
||||
}
|
||||
pub fn addRelocAssumeCapacity(
|
||||
elf: *Elf,
|
||||
loc_si: Symbol.Index,
|
||||
@@ -2098,7 +2343,45 @@ pub fn addRelocAssumeCapacity(
|
||||
.next = target.target_relocs,
|
||||
.loc = loc_si,
|
||||
.target = target_si,
|
||||
.unused = 0,
|
||||
.index = index: switch (elf.ehdrField(.type)) {
|
||||
.NONE, .CORE, _ => unreachable,
|
||||
.REL => {
|
||||
const sh = loc_si.shndx(elf).get(elf);
|
||||
switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
|
||||
inline else => |shdr, class| {
|
||||
const Rela = class.ElfN().Rela;
|
||||
const ent_size = elf.targetLoad(&shdr.entsize);
|
||||
const rela_slice = sh.rela_si.node(elf).slice(&elf.mf);
|
||||
const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: {
|
||||
const rela: *Rela = @ptrCast(@alignCast(
|
||||
rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
|
||||
));
|
||||
sh.rela_free = @enumFromInt(rela.offset);
|
||||
break :alloc_index index;
|
||||
} else alloc_index: {
|
||||
const old_size = elf.targetLoad(&shdr.size);
|
||||
const new_size = old_size + ent_size;
|
||||
elf.targetStore(&shdr.size, @intCast(new_size));
|
||||
break :alloc_index @intCast(@divExact(old_size, ent_size));
|
||||
};
|
||||
const rela: *Rela = @ptrCast(@alignCast(
|
||||
rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)],
|
||||
));
|
||||
rela.* = .{
|
||||
.offset = @intCast(offset),
|
||||
.info = .{
|
||||
.type = @intCast(@"type".unwrap(elf)),
|
||||
.sym = @intCast(@intFromEnum(target_si)),
|
||||
},
|
||||
.addend = @intCast(addend),
|
||||
};
|
||||
if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela);
|
||||
break :index .wrap(index);
|
||||
},
|
||||
}
|
||||
},
|
||||
.EXEC, .DYN => .none,
|
||||
},
|
||||
.offset = offset,
|
||||
.addend = addend,
|
||||
};
|
||||
@@ -2464,7 +2747,8 @@ fn flushUav(
|
||||
switch (sym.ni) {
|
||||
.none => {
|
||||
try elf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{
|
||||
const sec_si = elf.si.data;
|
||||
const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
|
||||
.alignment = uav_align.toStdMem(),
|
||||
.moved = true,
|
||||
});
|
||||
@@ -2472,7 +2756,7 @@ fn flushUav(
|
||||
sym.ni = ni;
|
||||
switch (elf.symPtr(si)) {
|
||||
inline else => |sym_ptr, class| sym_ptr.shndx =
|
||||
@field(elf.symPtr(.data), @tagName(class)).shndx,
|
||||
@field(elf.symPtr(sec_si), @tagName(class)).shndx,
|
||||
}
|
||||
},
|
||||
else => {
|
||||
@@ -2596,11 +2880,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
|
||||
var child_it = ni.children(&elf.mf);
|
||||
while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
|
||||
},
|
||||
.section => |si| switch (elf.shdrSlice()) {
|
||||
inline else => |shdr, class| elf.targetStore(
|
||||
&shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,
|
||||
@intCast(ni.fileLocation(&elf.mf, false).offset),
|
||||
),
|
||||
.section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
|
||||
ni.fileLocation(&elf.mf, false).offset,
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -2616,10 +2899,10 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
|
||||
const ph = &phdr[phndx];
|
||||
switch (elf.targetLoad(&ph.type)) {
|
||||
else => unreachable,
|
||||
std.elf.PT_NULL, std.elf.PT_LOAD => return,
|
||||
std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {},
|
||||
std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
|
||||
std.elf.PT_TLS => {},
|
||||
.NULL, .LOAD => return,
|
||||
.DYNAMIC, .INTERP => {},
|
||||
.PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset,
|
||||
.TLS => {},
|
||||
}
|
||||
elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni)));
|
||||
ph.paddr = ph.vaddr;
|
||||
@@ -2629,14 +2912,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
|
||||
.section => |si| {
|
||||
try elf.flushFileOffset(ni);
|
||||
const addr = elf.computeNodeVAddr(ni);
|
||||
switch (elf.shdrSlice()) {
|
||||
switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr, class| {
|
||||
const sym = @field(elf.symPtr(si), @tagName(class));
|
||||
const sh = &shdr[elf.targetLoad(&sym.shndx)];
|
||||
const flags = elf.targetLoad(&sh.flags).shf;
|
||||
const flags = elf.targetLoad(&shdr.flags).shf;
|
||||
if (flags.ALLOC) {
|
||||
elf.targetStore(&sh.addr, @intCast(addr));
|
||||
sym.value = sh.addr;
|
||||
elf.targetStore(&shdr.addr, @intCast(addr));
|
||||
@field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -2684,22 +2965,18 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
|
||||
elf.targetStore(&ph.memsz, @intCast(memsz));
|
||||
switch (elf.targetLoad(&ph.type)) {
|
||||
else => unreachable,
|
||||
std.elf.PT_NULL => if (size > 0) elf.targetStore(&ph.type, std.elf.PT_LOAD),
|
||||
std.elf.PT_LOAD => if (size == 0) elf.targetStore(&ph.type, std.elf.PT_NULL),
|
||||
std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => return,
|
||||
std.elf.PT_TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
|
||||
.NULL => if (size > 0) elf.targetStore(&ph.type, .LOAD),
|
||||
.LOAD => if (size == 0) elf.targetStore(&ph.type, .NULL),
|
||||
.DYNAMIC, .INTERP, .PHDR => return,
|
||||
.TLS => return ni.childrenMoved(elf.base.comp.gpa, &elf.mf),
|
||||
}
|
||||
var vaddr = elf.targetLoad(&ph.vaddr);
|
||||
var new_phndx = phndx;
|
||||
for (phdr[phndx + 1 ..], phndx + 1..) |*next_ph, next_phndx| {
|
||||
switch (elf.targetLoad(&next_ph.type)) {
|
||||
else => unreachable,
|
||||
std.elf.PT_NULL, std.elf.PT_LOAD => {},
|
||||
std.elf.PT_DYNAMIC,
|
||||
std.elf.PT_INTERP,
|
||||
std.elf.PT_PHDR,
|
||||
std.elf.PT_TLS,
|
||||
=> break,
|
||||
.NULL, .LOAD => {},
|
||||
.DYNAMIC, .INTERP, .PHDR, .TLS => break,
|
||||
}
|
||||
const next_vaddr = elf.targetLoad(&next_ph.vaddr);
|
||||
if (vaddr + memsz <= next_vaddr) break;
|
||||
@@ -2721,20 +2998,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
|
||||
}
|
||||
},
|
||||
},
|
||||
.section => |si| switch (elf.symPtr(si)) {
|
||||
inline else => |sym, class| {
|
||||
const sh = &@field(elf.shdrSlice(), @tagName(class))[elf.targetLoad(&sym.shndx)];
|
||||
elf.targetStore(&sh.size, @intCast(size));
|
||||
switch (elf.targetLoad(&sh.type)) {
|
||||
.section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
|
||||
inline else => |shdr| {
|
||||
switch (elf.targetLoad(&shdr.type)) {
|
||||
else => unreachable,
|
||||
std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS),
|
||||
std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL),
|
||||
std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore(
|
||||
&sh.info,
|
||||
@intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
|
||||
),
|
||||
std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {},
|
||||
.NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
|
||||
.PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
|
||||
.SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return,
|
||||
}
|
||||
elf.targetStore(&shdr.size, @intCast(size));
|
||||
},
|
||||
},
|
||||
.input_section => {},
|
||||
@@ -2860,6 +3132,26 @@ pub fn printNode(
|
||||
try w.writeAll(@tagName(node));
|
||||
switch (node) {
|
||||
else => {},
|
||||
.segment => |phndx| switch (elf.phdrSlice()) {
|
||||
inline else => |phdr| {
|
||||
const ph = &phdr[phndx];
|
||||
try w.writeByte('(');
|
||||
const pt = elf.targetLoad(&ph.type);
|
||||
if (std.enums.tagName(std.elf.PT, pt)) |pt_name|
|
||||
try w.writeAll(pt_name)
|
||||
else inline for (@typeInfo(std.elf.PT).@"enum".decls) |decl| {
|
||||
const decl_val = @field(std.elf.PT, decl.name);
|
||||
if (@TypeOf(decl_val) != std.elf.PT) continue;
|
||||
if (pt == @field(std.elf.PT, decl.name)) break try w.writeAll(decl.name);
|
||||
} else try w.print("0x{x}", .{pt});
|
||||
try w.writeAll(", ");
|
||||
const pf = elf.targetLoad(&ph.flags);
|
||||
if (pf.R) try w.writeByte('R');
|
||||
if (pf.W) try w.writeByte('W');
|
||||
if (pf.X) try w.writeByte('X');
|
||||
try w.writeByte(')');
|
||||
},
|
||||
},
|
||||
.section => |si| try w.print("({s})", .{elf.sectionName(si)}),
|
||||
.input_section => |isi| {
|
||||
const ii = isi.input(elf);
|
||||
|
||||
+12
-25
@@ -486,6 +486,14 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
|
||||
break :free .{ free_ni, free_node };
|
||||
},
|
||||
};
|
||||
switch (opts.prev) {
|
||||
.none => opts.parent.get(mf).first = free_ni,
|
||||
else => |prev_ni| prev_ni.get(mf).next = free_ni,
|
||||
}
|
||||
switch (opts.next) {
|
||||
.none => opts.parent.get(mf).last = free_ni,
|
||||
else => |next_ni| next_ni.get(mf).prev = free_ni,
|
||||
}
|
||||
free_node.* = .{
|
||||
.parent = opts.parent,
|
||||
.prev = opts.prev,
|
||||
@@ -535,13 +543,10 @@ pub fn addOnlyChildNode(
|
||||
try mf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
const parent = parent_ni.get(mf);
|
||||
assert(parent.first == .none and parent.last == .none);
|
||||
const ni = try mf.addNode(gpa, .{
|
||||
return mf.addNode(gpa, .{
|
||||
.parent = parent_ni,
|
||||
.add_node = opts,
|
||||
});
|
||||
parent.first = ni;
|
||||
parent.last = ni;
|
||||
return ni;
|
||||
}
|
||||
|
||||
pub fn addFirstChildNode(
|
||||
@@ -552,17 +557,11 @@ pub fn addFirstChildNode(
|
||||
) !Node.Index {
|
||||
try mf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
const parent = parent_ni.get(mf);
|
||||
const ni = try mf.addNode(gpa, .{
|
||||
return mf.addNode(gpa, .{
|
||||
.parent = parent_ni,
|
||||
.next = parent.first,
|
||||
.add_node = opts,
|
||||
});
|
||||
switch (parent.first) {
|
||||
.none => parent.last = ni,
|
||||
else => |first_ni| first_ni.get(mf).prev = ni,
|
||||
}
|
||||
parent.first = ni;
|
||||
return ni;
|
||||
}
|
||||
|
||||
pub fn addLastChildNode(
|
||||
@@ -573,7 +572,7 @@ pub fn addLastChildNode(
|
||||
) !Node.Index {
|
||||
try mf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
const parent = parent_ni.get(mf);
|
||||
const ni = try mf.addNode(gpa, .{
|
||||
return mf.addNode(gpa, .{
|
||||
.parent = parent_ni,
|
||||
.prev = parent.last,
|
||||
.offset = offset: switch (parent.last) {
|
||||
@@ -585,12 +584,6 @@ pub fn addLastChildNode(
|
||||
},
|
||||
.add_node = opts,
|
||||
});
|
||||
switch (parent.last) {
|
||||
.none => parent.first = ni,
|
||||
else => |last_ni| last_ni.get(mf).next = ni,
|
||||
}
|
||||
parent.last = ni;
|
||||
return ni;
|
||||
}
|
||||
|
||||
pub fn addNodeAfter(
|
||||
@@ -603,19 +596,13 @@ pub fn addNodeAfter(
|
||||
try mf.nodes.ensureUnusedCapacity(gpa, 1);
|
||||
const prev = prev_ni.get(mf);
|
||||
const prev_offset, const prev_size = prev.location().resolve(mf);
|
||||
const ni = try mf.addNode(gpa, .{
|
||||
return mf.addNode(gpa, .{
|
||||
.parent = prev.parent,
|
||||
.prev = prev_ni,
|
||||
.next = prev.next,
|
||||
.offset = prev_offset + prev_size,
|
||||
.add_node = opts,
|
||||
});
|
||||
switch (prev.next) {
|
||||
.none => prev.parent.get(mf).last = ni,
|
||||
else => |next_ni| next_ni.get(mf).prev = ni,
|
||||
}
|
||||
prev.next = ni;
|
||||
return ni;
|
||||
}
|
||||
|
||||
fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void {
|
||||
|
||||
Reference in New Issue
Block a user