From ec6f6582eada028b2a592ca5f3ad3e06aa6abd57 Mon Sep 17 00:00:00 2001 From: Carmen Date: Thu, 3 Apr 2025 19:44:45 +0200 Subject: [PATCH 1/2] std.elf: stronger typing --- lib/std/elf.zig | 2459 ++++++++++++++++++++++++++++------------------- lib/std/std.zig | 1 + 2 files changed, 1489 insertions(+), 971 deletions(-) diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 28f7cc248222..8e20f9810896 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -5,278 +5,82 @@ const math = std.math; const mem = std.mem; const assert = std.debug.assert; const native_endian = @import("builtin").target.cpu.arch.endian(); +const Endian = std.builtin.Endian; -pub const AT_NULL = 0; -pub const AT_IGNORE = 1; -pub const AT_EXECFD = 2; -pub const AT_PHDR = 3; -pub const AT_PHENT = 4; -pub const AT_PHNUM = 5; -pub const AT_PAGESZ = 6; -pub const AT_BASE = 7; -pub const AT_FLAGS = 8; -pub const AT_ENTRY = 9; -pub const AT_NOTELF = 10; -pub const AT_UID = 11; -pub const AT_EUID = 12; -pub const AT_GID = 13; -pub const AT_EGID = 14; -pub const AT_CLKTCK = 17; -pub const AT_PLATFORM = 15; -pub const AT_HWCAP = 16; -pub const AT_FPUCW = 18; -pub const AT_DCACHEBSIZE = 19; -pub const AT_ICACHEBSIZE = 20; -pub const AT_UCACHEBSIZE = 21; -pub const AT_IGNOREPPC = 22; -pub const AT_SECURE = 23; -pub const AT_BASE_PLATFORM = 24; -pub const AT_RANDOM = 25; -pub const AT_HWCAP2 = 26; -pub const AT_EXECFN = 31; -pub const AT_SYSINFO = 32; -pub const AT_SYSINFO_EHDR = 33; -pub const AT_L1I_CACHESHAPE = 34; -pub const AT_L1D_CACHESHAPE = 35; -pub const AT_L2_CACHESHAPE = 36; -pub const AT_L3_CACHESHAPE = 37; -pub const AT_L1I_CACHESIZE = 40; -pub const AT_L1I_CACHEGEOMETRY = 41; -pub const AT_L1D_CACHESIZE = 42; -pub const AT_L1D_CACHEGEOMETRY = 43; -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 DT_NULL = 0; -pub const DT_NEEDED = 1; -pub const DT_PLTRELSZ = 2; -pub const DT_PLTGOT = 3; -pub const DT_HASH = 4; -pub const DT_STRTAB = 5; -pub const DT_SYMTAB = 6; -pub const DT_RELA = 7; -pub const DT_RELASZ = 8; -pub const DT_RELAENT = 9; -pub const DT_STRSZ = 10; -pub const DT_SYMENT = 11; -pub const DT_INIT = 12; -pub const DT_FINI = 13; -pub const DT_SONAME = 14; -pub const DT_RPATH = 15; -pub const DT_SYMBOLIC = 16; -pub const DT_REL = 17; -pub const DT_RELSZ = 18; -pub const DT_RELENT = 19; -pub const DT_PLTREL = 20; -pub const DT_DEBUG = 21; -pub const DT_TEXTREL = 22; -pub const DT_JMPREL = 23; -pub const DT_BIND_NOW = 24; -pub const DT_INIT_ARRAY = 25; -pub const DT_FINI_ARRAY = 26; -pub const DT_INIT_ARRAYSZ = 27; -pub const DT_FINI_ARRAYSZ = 28; -pub const DT_RUNPATH = 29; -pub const DT_FLAGS = 30; -pub const DT_ENCODING = 32; -pub const DT_PREINIT_ARRAY = 32; -pub const DT_PREINIT_ARRAYSZ = 33; -pub const DT_SYMTAB_SHNDX = 34; -pub const DT_RELRSZ = 35; -pub const DT_RELR = 36; -pub const DT_RELRENT = 37; -pub const DT_NUM = 38; -pub const DT_LOOS = 0x6000000d; -pub const DT_HIOS = 0x6ffff000; -pub const DT_LOPROC = 0x70000000; -pub const DT_HIPROC = 0x7fffffff; -pub const DT_PROCNUM = DT_MIPS_NUM; - -pub const DT_VALRNGLO = 0x6ffffd00; -pub const DT_GNU_PRELINKED = 0x6ffffdf5; -pub const DT_GNU_CONFLICTSZ = 0x6ffffdf6; -pub const DT_GNU_LIBLISTSZ = 0x6ffffdf7; -pub const DT_CHECKSUM = 0x6ffffdf8; -pub const DT_PLTPADSZ = 0x6ffffdf9; -pub const DT_MOVEENT = 0x6ffffdfa; -pub const DT_MOVESZ = 0x6ffffdfb; -pub const DT_FEATURE_1 = 0x6ffffdfc; -pub const DT_POSFLAG_1 = 0x6ffffdfd; - -pub const DT_SYMINSZ = 0x6ffffdfe; -pub const DT_SYMINENT = 0x6ffffdff; -pub const DT_VALRNGHI = 0x6ffffdff; -pub const DT_VALNUM = 12; - -pub const DT_ADDRRNGLO = 0x6ffffe00; -pub const DT_GNU_HASH = 0x6ffffef5; -pub const DT_TLSDESC_PLT = 0x6ffffef6; -pub const DT_TLSDESC_GOT = 0x6ffffef7; -pub const DT_GNU_CONFLICT = 0x6ffffef8; -pub const DT_GNU_LIBLIST = 0x6ffffef9; -pub const DT_CONFIG = 0x6ffffefa; -pub const DT_DEPAUDIT = 0x6ffffefb; -pub const DT_AUDIT = 0x6ffffefc; -pub const DT_PLTPAD = 0x6ffffefd; -pub const DT_MOVETAB = 0x6ffffefe; -pub const DT_SYMINFO = 0x6ffffeff; -pub const DT_ADDRRNGHI = 0x6ffffeff; -pub const DT_ADDRNUM = 11; - -pub const DT_VERSYM = 0x6ffffff0; - -pub const DT_RELACOUNT = 0x6ffffff9; -pub const DT_RELCOUNT = 0x6ffffffa; - -pub const DT_FLAGS_1 = 0x6ffffffb; -pub const DT_VERDEF = 0x6ffffffc; - -pub const DT_VERDEFNUM = 0x6ffffffd; -pub const DT_VERNEED = 0x6ffffffe; - -pub const DT_VERNEEDNUM = 0x6fffffff; -pub const DT_VERSIONTAGNUM = 16; - -pub const DT_AUXILIARY = 0x7ffffffd; -pub const DT_FILTER = 0x7fffffff; -pub const DT_EXTRANUM = 3; - -pub const DT_SPARC_REGISTER = 0x70000001; -pub const DT_SPARC_NUM = 2; - -pub const DT_MIPS_RLD_VERSION = 0x70000001; -pub const DT_MIPS_TIME_STAMP = 0x70000002; -pub const DT_MIPS_ICHECKSUM = 0x70000003; -pub const DT_MIPS_IVERSION = 0x70000004; -pub const DT_MIPS_FLAGS = 0x70000005; -pub const DT_MIPS_BASE_ADDRESS = 0x70000006; -pub const DT_MIPS_MSYM = 0x70000007; -pub const DT_MIPS_CONFLICT = 0x70000008; -pub const DT_MIPS_LIBLIST = 0x70000009; -pub const DT_MIPS_LOCAL_GOTNO = 0x7000000a; -pub const DT_MIPS_CONFLICTNO = 0x7000000b; -pub const DT_MIPS_LIBLISTNO = 0x70000010; -pub const DT_MIPS_SYMTABNO = 0x70000011; -pub const DT_MIPS_UNREFEXTNO = 0x70000012; -pub const DT_MIPS_GOTSYM = 0x70000013; -pub const DT_MIPS_HIPAGENO = 0x70000014; -pub const DT_MIPS_RLD_MAP = 0x70000016; -pub const DT_MIPS_DELTA_CLASS = 0x70000017; -pub const DT_MIPS_DELTA_CLASS_NO = 0x70000018; - -pub const DT_MIPS_DELTA_INSTANCE = 0x70000019; -pub const DT_MIPS_DELTA_INSTANCE_NO = 0x7000001a; - -pub const DT_MIPS_DELTA_RELOC = 0x7000001b; -pub const DT_MIPS_DELTA_RELOC_NO = 0x7000001c; - -pub const DT_MIPS_DELTA_SYM = 0x7000001d; - -pub const DT_MIPS_DELTA_SYM_NO = 0x7000001e; - -pub const DT_MIPS_DELTA_CLASSSYM = 0x70000020; - -pub const DT_MIPS_DELTA_CLASSSYM_NO = 0x70000021; - -pub const DT_MIPS_CXX_FLAGS = 0x70000022; -pub const DT_MIPS_PIXIE_INIT = 0x70000023; -pub const DT_MIPS_SYMBOL_LIB = 0x70000024; -pub const DT_MIPS_LOCALPAGE_GOTIDX = 0x70000025; -pub const DT_MIPS_LOCAL_GOTIDX = 0x70000026; -pub const DT_MIPS_HIDDEN_GOTIDX = 0x70000027; -pub const DT_MIPS_PROTECTED_GOTIDX = 0x70000028; -pub const DT_MIPS_OPTIONS = 0x70000029; -pub const DT_MIPS_INTERFACE = 0x7000002a; -pub const DT_MIPS_DYNSTR_ALIGN = 0x7000002b; -pub const DT_MIPS_INTERFACE_SIZE = 0x7000002c; -pub const DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 0x7000002d; - -pub const DT_MIPS_PERF_SUFFIX = 0x7000002e; - -pub const DT_MIPS_COMPACT_SIZE = 0x7000002f; -pub const DT_MIPS_GP_VALUE = 0x70000030; -pub const DT_MIPS_AUX_DYNAMIC = 0x70000031; - -pub const DT_MIPS_PLTGOT = 0x70000032; - -pub const DT_MIPS_RWPLT = 0x70000034; -pub const DT_MIPS_RLD_MAP_REL = 0x70000035; -pub const DT_MIPS_NUM = 0x36; - -pub const DT_ALPHA_PLTRO = (DT_LOPROC + 0); -pub const DT_ALPHA_NUM = 1; - -pub const DT_PPC_GOT = (DT_LOPROC + 0); -pub const DT_PPC_OPT = (DT_LOPROC + 1); -pub const DT_PPC_NUM = 2; - -pub const DT_PPC64_GLINK = (DT_LOPROC + 0); -pub const DT_PPC64_OPD = (DT_LOPROC + 1); -pub const DT_PPC64_OPDSZ = (DT_LOPROC + 2); -pub const DT_PPC64_OPT = (DT_LOPROC + 3); -pub const DT_PPC64_NUM = 4; - -pub const DT_IA_64_PLT_RESERVE = (DT_LOPROC + 0); -pub const DT_IA_64_NUM = 1; - -pub const DT_NIOS2_GP = 0x70000002; - -pub const DF_ORIGIN = 0x00000001; -pub const DF_SYMBOLIC = 0x00000002; -pub const DF_TEXTREL = 0x00000004; -pub const DF_BIND_NOW = 0x00000008; -pub const DF_STATIC_TLS = 0x00000010; - -pub const DF_1_NOW = 0x00000001; -pub const DF_1_GLOBAL = 0x00000002; -pub const DF_1_GROUP = 0x00000004; -pub const DF_1_NODELETE = 0x00000008; -pub const DF_1_LOADFLTR = 0x00000010; -pub const DF_1_INITFIRST = 0x00000020; -pub const DF_1_NOOPEN = 0x00000040; -pub const DF_1_ORIGIN = 0x00000080; -pub const DF_1_DIRECT = 0x00000100; -pub const DF_1_TRANS = 0x00000200; -pub const DF_1_INTERPOSE = 0x00000400; -pub const DF_1_NODEFLIB = 0x00000800; -pub const DF_1_NODUMP = 0x00001000; -pub const DF_1_CONFALT = 0x00002000; -pub const DF_1_ENDFILTEE = 0x00004000; -pub const DF_1_DISPRELDNE = 0x00008000; -pub const DF_1_DISPRELPND = 0x00010000; -pub const DF_1_NODIRECT = 0x00020000; -pub const DF_1_IGNMULDEF = 0x00040000; -pub const DF_1_NOKSYMS = 0x00080000; -pub const DF_1_NOHDR = 0x00100000; -pub const DF_1_EDITED = 0x00200000; -pub const DF_1_NORELOC = 0x00400000; -pub const DF_1_SYMINTPOSE = 0x00800000; -pub const DF_1_GLOBAUDIT = 0x01000000; -pub const DF_1_SINGLETON = 0x02000000; -pub const DF_1_STUB = 0x04000000; -pub const DF_1_PIE = 0x08000000; +pub const MAGIC = "\x7fELF"; + +pub const DF = packed struct(u5) { + origin: bool = false, + symbolic: bool = false, + textrel: bool = false, + bind_now: bool = false, + static_tls: bool = false, +}; + +pub const DF1 = packed struct(u28) { + now: bool = false, + global: bool = false, + group: bool = false, + nodelete: bool = false, + loadfltr: bool = false, + initfirst: bool = false, + noopen: bool = false, + origin: bool = false, + direct: bool = false, + trans: bool = false, + interpose: bool = false, + nodeflib: bool = false, + nodump: bool = false, + confalt: bool = false, + endfiltee: bool = false, + dispreldne: bool = false, + disprelpnd: bool = false, + nodirect: bool = false, + ignmuldef: bool = false, + noksyms: bool = false, + nohdr: bool = false, + edited: bool = false, + symintpose: bool = false, + globaudit: bool = false, + singleton: bool = false, + stub: bool = false, + pie: bool = false, +}; pub const Versym = packed struct(u16) { - VERSION: u15, - HIDDEN: bool, + version: u15, + hidden: bool, + + pub const local: Versym = .fromIndex(.local); + pub const global: Versym = .fromIndex(.global); - pub const LOCAL: Versym = @bitCast(@intFromEnum(VER_NDX.LOCAL)); - pub const GLOBAL: Versym = @bitCast(@intFromEnum(VER_NDX.GLOBAL)); + pub fn fromIndex(index: VersionIndex) Versym { + const idx = @intFromEnum(index); + return @bitCast(idx); + } + + pub fn toIndex(symbol: Versym) VersionIndex { + const sym: u16 = @bitCast(symbol); + return @enumFromInt(sym); + } }; -pub const VER_NDX = enum(u16) { +pub const VersionIndex = enum(u16) { + const Reserve = EnumRange(VersionIndex, .loreserve, .hireserve); + pub const ReserveRange = Reserve.Range; + pub const reserve = Reserve.fromInt; + pub const getReserve = Reserve.toInt; + /// Symbol is local - LOCAL = 0, + local = 0, /// Symbol is global - GLOBAL = 1, - /// Beginning of reserved entries - LORESERVE = 0xff00, - /// Symbol is to be eliminated - ELIMINATE = 0xff01, - UNSPECIFIED = 0xffff, + global = 1, + loreserve = 0xff00, + hireserve = 0xffff, _, + + /// Symbol is to be eliminated + pub const eliminate = reserve(0x01); }; /// Version definition of the file itself @@ -284,169 +88,318 @@ 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; - -/// 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; - -// Note type for .note.gnu.build_id -pub const NT_GNU_BUILD_ID = 3; - -/// Local symbol -pub const STB_LOCAL = 0; -/// Global symbol -pub const STB_GLOBAL = 1; -/// Weak symbol -pub const STB_WEAK = 2; -/// Number of defined types -pub const STB_NUM = 3; -/// Start of OS-specific -pub const STB_LOOS = 10; -/// Unique symbol -pub const STB_GNU_UNIQUE = 10; -/// End of OS-specific -pub const STB_HIOS = 12; -/// Start of processor-specific -pub const STB_LOPROC = 13; -/// End of processor-specific -pub const STB_HIPROC = 15; - -pub const STB_MIPS_SPLIT_COMMON = 13; - -/// Symbol type is unspecified -pub const STT_NOTYPE = 0; -/// Symbol is a data object -pub const STT_OBJECT = 1; -/// Symbol is a code object -pub const STT_FUNC = 2; -/// Symbol associated with a section -pub const STT_SECTION = 3; -/// Symbol's name is file name -pub const STT_FILE = 4; -/// Symbol is a common data object -pub const STT_COMMON = 5; -/// Symbol is thread-local data object -pub const STT_TLS = 6; -/// Number of defined types -pub const STT_NUM = 7; -/// Start of OS-specific -pub const STT_LOOS = 10; -/// Symbol is indirect code object -pub const STT_GNU_IFUNC = 10; -/// End of OS-specific -pub const STT_HIOS = 12; -/// Start of processor-specific -pub const STT_LOPROC = 13; -/// End of processor-specific -pub const STT_HIPROC = 15; - -pub const STT_SPARC_REGISTER = 13; - -pub const STT_PARISC_MILLICODE = 13; - -pub const STT_HP_OPAQUE = (STT_LOOS + 0x1); -pub const STT_HP_STUB = (STT_LOOS + 0x2); - -pub const STT_ARM_TFUNC = STT_LOPROC; -pub const STT_ARM_16BIT = STT_HIPROC; +pub const PT = enum(Word) { + const Os = EnumRange(PT, .LOOS, .HIOS); + pub const OsRange = Os.Range; + pub const os = Os.fromInt; + pub const getOs = Os.toInt; + + const Proc = EnumRange(PT, .LOPROC, .HIPROC); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + + /// 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, + /// Start of OS-specific + LOOS = 0x60000000, + /// End of OS-specific + HIOS = 0x6fffffff, + /// Start of processor-specific + LOPROC = 0x70000000, + /// End of processor-specific + HIPROC = 0x7fffffff, + _, -pub const MAGIC = "\x7fELF"; + /// GCC .eh_frame_hdr segment + pub const GNU_EH_FRAME = os(0x474e550); + /// Indicates stack executability + pub const GNU_STACK = os(0x474e551); + /// Read-only after relocation + pub const GNU_RELRO = os(0x474e552); + pub const LOSUNW = os(0xffffffa); + /// Sun specific segment + pub const SUNWBSS = os(0xffffffa); + /// Stack segment + pub const SUNWSTACK = os(0xffffffb); + pub const HISUNW = os(0xfffffff); +}; + +pub const SHT = enum(Word) { + const Os = EnumRange(SHT, .LOOS, .HIOS); + pub const OsRange = Os.Range; + pub const os = Os.fromInt; + pub const getOs = Os.toInt; + + const Proc = EnumRange(SHT, .LOPROC, .HIPROC); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + + const User = EnumRange(SHT, .LOUSER, .HIUSER); + pub const UserRange = User.Range; + pub const user = User.fromInt; + pub const getUser = User.toInt; + + /// 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, + /// Start of OS-specific + LOOS = 0x60000000, + /// End of OS-specific + HIOS = 0x6fffffff, + /// Start of processor-specific + LOPROC = 0x70000000, + /// End of processor-specific + HIPROC = 0x7fffffff, + /// Start of application-specific + LOUSER = 0x80000000, + /// End of application-specific + HIUSER = 0xffffffff, + _, + + /// LLVM address-significance table + pub const LLVM_ADDRSIG = os(0xfff4c03); + /// GNU hash table + pub const GNU_HASH = os(0xffffff6); + /// GNU version definition table + pub const GNU_VERDEF = os(0xffffffd); + /// GNU needed versions table + pub const GNU_VERNEED = os(0xffffffe); + /// GNU symbol version table + pub const GNU_VERSYM = os(0xfffffff); + /// Unwind information + pub const X86_64_UNWIND = proc(0x1); + + pub fn format( + sh_type: SHT, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + const name = switch (sh_type) { + .NULL, + .PROGBITS, + .SYMTAB, + .STRTAB, + .RELA, + .HASH, + .DYNAMIC, + .NOTE, + .NOBITS, + .REL, + .SHLIB, + .DYNSYM, + .INIT_ARRAY, + .FINI_ARRAY, + .PREINIT_ARRAY, + .GROUP, + .SYMTAB_SHNDX, + => @tagName(sh_type), + + LLVM_ADDRSIG => "LLVM_ADDRSIG", + GNU_HASH => "GNU_HASH", + GNU_VERDEF => "GNU_VERDEF", + GNU_VERNEED => "GNU_VERNEED", + GNU_VERSYM => "GNU_VERSYM", + X86_64_UNWIND => "X86_64_UNWIND", + + else => name: { + if (sh_type.getOs()) |osval| + try writer.print("OS(0x{X})", .{osval}) + else if (sh_type.getProc()) |procval| + try writer.print("PROC(0x{X})", .{procval}) + else + break :name "UNKNOWN"; + return; + }, + }; + + try writer.writeAll(name); + } +}; + +pub const NT = enum(u32) { + _, + + pub fn of(value: u32) NT { + return @enumFromInt(value); + } + + // Note type for .note.gnu.build_id + pub const GNU_BUILD_ID: NT = .of(3); +}; + +pub const STB = enum(u4) { + const Os = EnumRange(STB, .LOOS, .HIOS); + pub const OsRange = Os.Range; + pub const os = Os.fromInt; + pub const getOs = Os.toInt; + + const Proc = EnumRange(STB, .LOPROC, .HIPROC); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + + /// Local symbol + LOCAL = 0, + /// Global symbol + GLOBAL = 1, + /// Weak symbol + WEAK = 2, + /// Start of OS-specific + LOOS = 10, + /// End of OS-specific + HIOS = 12, + /// Start of processor-specific + LOPROC = 13, + /// End of processor-specific + HIPROC = 15, + _, + + /// Unique symbol + pub const GNU_UNIQUE = os(0); + pub const MIPS_SPLIT_COMMON = proc(0); +}; + +pub const STT = enum(u4) { + const Os = EnumRange(STT, .LOOS, .HIOS); + pub const OsRange = Os.Range; + pub const os = Os.fromInt; + pub const getOs = Os.toInt; + + const Proc = EnumRange(STT, .LOPROC, .HIPROC); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + + /// Symbol type is unspecified + NOTYPE = 0, + /// Symbol is a data object + OBJECT = 1, + /// Symbol is a code object + FUNC = 2, + /// Symbol associated with a section + SECTION = 3, + /// Symbol's name is file name + FILE = 4, + /// Symbol is a common data object + COMMON = 5, + /// Symbol is thread-local data object + TLS = 6, + /// Start of OS-specific + LOOS = 10, + /// End of OS-specific + HIOS = 12, + /// Start of processor-specific + LOPROC = 13, + /// End of processor-specific + HIPROC = 15, + _, + + /// Symbol is indirect code object + pub const GNU_IFUNC = os(0x0); + + pub const SPARC_REGISTER = proc(0x0); + + pub const PARISC_MILLICODE = proc(0x0); + + pub const HP_OPAQUE = os(0x1); + pub const HP_STUB = os(0x2); + + pub const ARM_TFUNC = proc(0x0); + pub const ARM_16BIT = proc(0x2); + + pub fn format( + st_type: STT, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + const name = switch (st_type) { + .NOTYPE, + .OBJECT, + .FUNC, + .SECTION, + .FILE, + .COMMON, + .TLS, + => @tagName(st_type), + + GNU_IFUNC => "GNU_IFUNC", + + else => name: { + if (st_type.getOs()) |osval| + try writer.print("OS({d})", .{osval}) + else if (st_type.getProc()) |procval| + try writer.print("PROC({d})", .{procval}) + else + break :name "UNKNOWN"; + return; + }, + }; + + try writer.writeAll(name); + } +}; /// File types pub const ET = enum(u16) { + const Os = EnumRange(ET, .LOOS, .HIOS); + pub const OsRange = Os.Range; + pub const os = Os.fromInt; + pub const getOs = Os.toInt; + + const Proc = EnumRange(ET, .LOOS, .HIOS); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + /// No file type NONE = 0, @@ -462,25 +415,18 @@ pub const ET = enum(u16) { /// Core file CORE = 4, - _, - - /// Beginning of OS-specific codes - pub const LOOS = 0xfe00; - - /// End of OS-specific codes - pub const HIOS = 0xfeff; - - /// Beginning of processor-specific codes - pub const LOPROC = 0xff00; + LOOS = 0xfe00, + HIOS = 0xfeff, + LOPROC = 0xff00, + HIPROC = 0xffff, - /// End of processor-specific codes - pub const HIPROC = 0xffff; + _, }; /// All integers are native endian. pub const Header = struct { is_64: bool, - endian: std.builtin.Endian, + endian: Endian, os_abi: OSABI, abi_version: u8, type: ET, @@ -494,52 +440,89 @@ pub const Header = struct { shnum: u16, shstrndx: u16, - pub fn program_header_iterator(self: Header, parse_source: anytype) ProgramHeaderIterator(@TypeOf(parse_source)) { - return ProgramHeaderIterator(@TypeOf(parse_source)){ - .elf_header = self, - .parse_source = parse_source, - }; + pub fn programHeaders( + self: *const Header, + parse_source: anytype, + ) ProgramHeaders(@TypeOf(parse_source)) { + return .new(self, parse_source); } - pub fn section_header_iterator(self: Header, parse_source: anytype) SectionHeaderIterator(@TypeOf(parse_source)) { - return SectionHeaderIterator(@TypeOf(parse_source)){ - .elf_header = self, - .parse_source = parse_source, - }; + pub fn sectionHeaders( + self: *const Header, + parse_source: anytype, + ) SectionHeaders(@TypeOf(parse_source)) { + return .new(self, parse_source); + } + + pub fn symbolTable( + self: *const Header, + symtab_header: *const elf64.Shdr, + parse_source: anytype, + ) SymbolTable(@TypeOf(parse_source)) { + return .new(self, symtab_header, parse_source); + } + + pub fn findSymbolTable( + self: *const Header, + parse_source: anytype, + ) !?SymbolTable(@TypeOf(parse_source)) { + var sheaders = self.sectionHeaders(parse_source).iterator(); + const symtab_header = while (try sheaders.next()) |shdr| { + if (shdr.sh_type == .SYMTAB) break shdr; + } else return null; + return self.symbolTable(&symtab_header, parse_source); + } + + pub fn stringTable( + self: *const Header, + strtab_header: *const elf64.Shdr, + parse_source: anytype, + ) StringTable(@TypeOf(parse_source)) { + _ = self; + return .new(strtab_header, parse_source); + } + + pub fn sectionNames( + self: *const Header, + parse_source: anytype, + ) !?StringTable(@TypeOf(parse_source)) { + const sheaders = self.sectionHeaders(parse_source); + const shstr_tab = try sheaders.get(self.shstrndx) orelse return null; + return self.stringTable(&shstr_tab, parse_source); } pub fn read(parse_source: anytype) !Header { - var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; + var hdr_buf: [@sizeOf(elf64.Ehdr)]u8 align(@alignOf(elf64.Ehdr)) = undefined; try parse_source.seekableStream().seekTo(0); try parse_source.reader().readNoEof(&hdr_buf); return Header.parse(&hdr_buf); } - pub fn parse(hdr_buf: *align(@alignOf(Elf64_Ehdr)) const [@sizeOf(Elf64_Ehdr)]u8) !Header { - const hdr32 = @as(*const Elf32_Ehdr, @ptrCast(hdr_buf)); - const hdr64 = @as(*const Elf64_Ehdr, @ptrCast(hdr_buf)); - if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic; - if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion; + pub fn parse(hdr_buf: *align(@alignOf(elf64.Ehdr)) const [@sizeOf(elf64.Ehdr)]u8) !Header { + const hdr32 = @as(*const elf32.Ehdr, @ptrCast(hdr_buf)); + const hdr64 = @as(*const elf64.Ehdr, @ptrCast(hdr_buf)); + if (!mem.eql(u8, hdr32.e_ident.magic(), MAGIC)) return error.InvalidElfMagic; + if (hdr32.e_ident.ei_version != .CURRENT) return error.InvalidElfVersion; - const is_64 = switch (hdr32.e_ident[EI_CLASS]) { - ELFCLASS32 => false, - ELFCLASS64 => true, + const is_64 = switch (hdr32.e_ident.ei_class) { + .@"32" => false, + .@"64" => true, else => return error.InvalidElfClass, }; - const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) { - ELFDATA2LSB => .little, - ELFDATA2MSB => .big, + const endian: Endian = switch (hdr32.e_ident.ei_data) { + .LSB => .little, + .MSB => .big, else => return error.InvalidElfEndian, }; const need_bswap = endian != native_endian; // Converting integers to exhaustive enums using `@enumFromInt` could cause a panic. comptime assert(!@typeInfo(OSABI).@"enum".is_exhaustive); - const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]); + const os_abi: OSABI = hdr32.e_ident.ei_osabi; // The meaning of this value depends on `os_abi` so just make it available as `u8`. - const abi_version = hdr32.e_ident[EI_ABIVERSION]; + const abi_version = hdr32.e_ident.ei_abiversion; const @"type" = if (need_bswap) blk: { comptime assert(!@typeInfo(ET).@"enum".is_exhaustive); @@ -572,43 +555,56 @@ pub const Header = struct { } }; -pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type { +pub fn ProgramHeaders(ParseSource: type) type { return struct { - elf_header: Header, - parse_source: ParseSource, - index: usize = 0, + const PHeaders = @This(); + + len: u16, + _parse_source: ParseSource, + _phoff: u64, + _is_64: bool, + _endian: Endian, + + pub fn new(header: *const Header, parse_source: ParseSource) PHeaders { + return .{ + .len = header.phnum, + ._parse_source = parse_source, + ._phoff = header.phoff, + ._is_64 = header.is_64, + ._endian = header.endian, + }; + } - pub fn next(self: *@This()) !?Elf64_Phdr { - if (self.index >= self.elf_header.phnum) return null; - defer self.index += 1; + pub fn get(self: *const PHeaders, index: u16) !?elf64.Phdr { + if (index >= self.len) return null; - if (self.elf_header.is_64) { - var phdr: Elf64_Phdr = undefined; - const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); + if (self._is_64) { + var phdr: elf64.Phdr = undefined; + const offset = self._phoff + @sizeOf(@TypeOf(phdr)) * index; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&phdr)); // ELF endianness matches native endianness. - if (self.elf_header.endian == native_endian) return phdr; + if (self._endian == native_endian) return phdr; // Convert fields to native endianness. - mem.byteSwapAllFields(Elf64_Phdr, &phdr); + mem.byteSwapAllFields(elf64.Phdr, &phdr); return phdr; } - var phdr: Elf32_Phdr = undefined; - const offset = self.elf_header.phoff + @sizeOf(@TypeOf(phdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.reader().readNoEof(mem.asBytes(&phdr)); + var phdr: elf32.Phdr = undefined; + const offset = self._phoff + @sizeOf(@TypeOf(phdr)) * index; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&phdr)); // ELF endianness does NOT match native endianness. - if (self.elf_header.endian != native_endian) { + if (self._endian != native_endian) { // Convert fields to native endianness. - mem.byteSwapAllFields(Elf32_Phdr, &phdr); + mem.byteSwapAllFields(elf32.Phdr, &phdr); } // Convert 32-bit header to 64-bit. - return Elf64_Phdr{ + return elf64.Phdr{ .p_type = phdr.p_type, .p_offset = phdr.p_offset, .p_vaddr = phdr.p_vaddr, @@ -619,49 +615,79 @@ pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type { .p_align = phdr.p_align, }; } + + pub fn iterator(self: PHeaders) Iterator { + return .{ .pheaders = self }; + } + + pub const Iterator = struct { + pheaders: PHeaders, + index: u16 = 0, + + pub fn next(self: *Iterator) !?elf64.Phdr { + const result = try self.pheaders.get(self.index) orelse return null; + self.index += 1; + return result; + } + }; }; } -pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { +pub fn SectionHeaders(ParseSource: type) type { return struct { - elf_header: Header, - parse_source: ParseSource, - index: usize = 0, + const SHeaders = @This(); + + len: u16, + _parse_source: ParseSource, + _shoff: u64, + _is_64: bool, + _endian: Endian, + + pub fn new(header: *const Header, parse_source: ParseSource) SHeaders { + return .{ + .len = header.shnum, + ._parse_source = parse_source, + ._shoff = header.shoff, + ._is_64 = header.is_64, + ._endian = header.endian, + }; + } - pub fn next(self: *@This()) !?Elf64_Shdr { - if (self.index >= self.elf_header.shnum) return null; - defer self.index += 1; + pub fn get(self: *const SHeaders, index: u16) !?elf64.Shdr { + if (index >= self.len) return null; - if (self.elf_header.is_64) { - var shdr: Elf64_Shdr = undefined; - const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); + if (self._is_64) { + var shdr: elf64.Shdr = undefined; + const offset = self._shoff + @sizeOf(@TypeOf(shdr)) * index; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&shdr)); // ELF endianness matches native endianness. - if (self.elf_header.endian == native_endian) return shdr; + if (self._endian == native_endian) return shdr; // Convert fields to native endianness. - mem.byteSwapAllFields(Elf64_Shdr, &shdr); + mem.byteSwapAllFields(elf64.Shdr, &shdr); return shdr; } - var shdr: Elf32_Shdr = undefined; - const offset = self.elf_header.shoff + @sizeOf(@TypeOf(shdr)) * self.index; - try self.parse_source.seekableStream().seekTo(offset); - try self.parse_source.reader().readNoEof(mem.asBytes(&shdr)); + var shdr: elf32.Shdr = undefined; + const offset = self._shoff + @sizeOf(@TypeOf(shdr)) * index; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&shdr)); // ELF endianness does NOT match native endianness. - if (self.elf_header.endian != native_endian) { + if (self._endian != native_endian) { // Convert fields to native endianness. - mem.byteSwapAllFields(Elf32_Shdr, &shdr); + mem.byteSwapAllFields(elf32.Shdr, &shdr); } + const sh_flags_orig: Word = @bitCast(shdr.sh_flags); + const sh_flags: Xword = @intCast(sh_flags_orig); // Convert 32-bit header to 64-bit. - return Elf64_Shdr{ + return elf64.Shdr{ .sh_name = shdr.sh_name, .sh_type = shdr.sh_type, - .sh_flags = shdr.sh_flags, + .sh_flags = @bitCast(sh_flags), .sh_addr = shdr.sh_addr, .sh_offset = shdr.sh_offset, .sh_size = shdr.sh_size, @@ -671,6 +697,150 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type { .sh_entsize = shdr.sh_entsize, }; } + + pub fn iterator(self: SHeaders) Iterator { + return .{ .sheaders = self }; + } + + pub const Iterator = struct { + sheaders: SHeaders, + index: u16 = 0, + + pub fn next(self: *Iterator) !?elf64.Shdr { + const shdr = try self.sheaders.get(self.index) orelse return null; + self.index += 1; + return shdr; + } + }; + }; +} + +pub fn SymbolTable(ParseSource: type) type { + return struct { + const SymTab = @This(); + + len: u64, + string_table_index: u32, + last_local_symbol: ?u32, + _parse_source: ParseSource, + _shoff: u64, + _entsize: u64, + _is_64: bool, + _endian: Endian, + + pub fn new( + elf_header: *const Header, + symtab_header: *const elf64.Shdr, + parse_source: ParseSource, + ) SymTab { + return .{ + .string_table_index = symtab_header.sh_link, + .last_local_symbol = if (symtab_header.sh_info > 0) symtab_header.sh_info - 1 else null, + .len = @divExact(symtab_header.sh_size, symtab_header.sh_entsize), + ._parse_source = parse_source, + ._shoff = symtab_header.sh_offset, + ._entsize = symtab_header.sh_entsize, + ._is_64 = elf_header.is_64, + ._endian = elf_header.endian, + }; + } + + pub fn get(self: *const SymTab, index: usize) !?elf64.Sym { + if (index >= self.len) return null; + const offset = self._shoff + self._entsize * index; + + if (self._is_64) { + var sym: elf64.Sym = undefined; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&sym)); + + // ELF endianness matches native endianness. + if (self._endian == native_endian) return sym; + + // Convert fields to native endianness. + mem.byteSwapAllFields(elf64.Sym, &sym); + return sym; + } + + var sym: elf32.Sym = undefined; + try self._parse_source.seekableStream().seekTo(offset); + try self._parse_source.reader().readNoEof(mem.asBytes(&sym)); + + // ELF endianness matches native endianness. + if (self._endian != native_endian) + // Convert fields to native endianness. + mem.byteSwapAllFields(elf32.Sym, &sym); + + return elf64.Sym{ + .st_name = sym.st_name, + .st_info = sym.st_info, + .st_other = sym.st_other, + .st_shndx = sym.st_shndx, + .st_value = @intCast(sym.st_value), + .st_size = @intCast(sym.st_size), + }; + } + + pub fn iterator(self: SymTab) SymTab.Iterator { + return .{ .symtab = self }; + } + + pub const Iterator = struct { + symtab: SymTab, + index: u64 = 0, + + pub fn next(self: *Iterator) !?elf64.Sym { + const sym = try self.symtab.get(self.index) orelse return null; + self.index += 1; + return sym; + } + }; + }; +} + +pub fn StringTable(ParseSource: type) type { + return struct { + const StrTab = @This(); + + len: u64, + _parse_source: ParseSource, + _shoff: u64, + + pub fn new( + strtab_header: *const elf64.Shdr, + parse_source: ParseSource, + ) StrTab { + return .{ + .len = strtab_header.sh_size, + ._parse_source = parse_source, + ._shoff = strtab_header.sh_offset, + }; + } + + pub fn get( + self: *const StrTab, + strndx: usize, + buffer: []u8, + ) !?[:0]u8 { + if (strndx == 0) return null; + var stream = std.io.fixedBufferStream(buffer); + try self._parse_source.seekableStream().seekTo(self._shoff + strndx); + try self._parse_source.reader().streamUntilDelimiter(stream.writer(), 0, self.len); + buffer[stream.pos] = 0; + return buffer[0..stream.pos :0]; + } + + pub fn getAlloc( + self: *const StrTab, + strndx: usize, + alloc: std.mem.Allocator, + ) !?[:0]u8 { + if (strndx == 0) return null; + var bytes: std.ArrayListUnmanaged(u8) = .empty; + try self._parse_source.seekableStream().seekTo(self._shoff + strndx); + try self._parse_source.reader().streamUntilDelimiter(bytes.writer(alloc), 0, self.len); + return try bytes.toOwnedSliceSentinel(alloc, 0); + } }; } @@ -694,223 +864,17 @@ fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 { } } -pub const ELFCLASSNONE = 0; -pub const ELFCLASS32 = 1; -pub const ELFCLASS64 = 2; -pub const ELFCLASSNUM = 3; - -pub const ELFDATANONE = 0; -pub const ELFDATA2LSB = 1; -pub const ELFDATA2MSB = 2; -pub const ELFDATANUM = 3; - -pub const EI_CLASS = 4; -pub const EI_DATA = 5; -pub const EI_VERSION = 6; -pub const EI_OSABI = 7; -pub const EI_ABIVERSION = 8; -pub const EI_PAD = 9; - -pub const EI_NIDENT = 16; - pub const Half = u16; pub const Word = u32; pub const Sword = i32; -pub const Elf32_Xword = u64; -pub const Elf32_Sxword = i64; -pub const Elf64_Xword = u64; -pub const Elf64_Sxword = i64; -pub const Elf32_Addr = u32; -pub const Elf64_Addr = u64; -pub const Elf32_Off = u32; -pub const Elf64_Off = u64; -pub const Elf32_Section = u16; -pub const Elf64_Section = u16; -pub const Elf32_Ehdr = extern struct { - e_ident: [EI_NIDENT]u8, - e_type: ET, - e_machine: EM, - e_version: Word, - e_entry: Elf32_Addr, - e_phoff: Elf32_Off, - e_shoff: Elf32_Off, - e_flags: Word, - e_ehsize: Half, - e_phentsize: Half, - e_phnum: Half, - e_shentsize: Half, - e_shnum: Half, - e_shstrndx: Half, -}; -pub const Elf64_Ehdr = extern struct { - e_ident: [EI_NIDENT]u8, - e_type: ET, - e_machine: EM, - e_version: Word, - e_entry: Elf64_Addr, - e_phoff: Elf64_Off, - e_shoff: Elf64_Off, - e_flags: Word, - e_ehsize: Half, - e_phentsize: Half, - e_phnum: Half, - e_shentsize: Half, - e_shnum: Half, - e_shstrndx: Half, -}; -pub const Elf32_Phdr = extern struct { - p_type: Word, - p_offset: Elf32_Off, - p_vaddr: Elf32_Addr, - p_paddr: Elf32_Addr, - p_filesz: Word, - p_memsz: Word, - p_flags: Word, - p_align: Word, -}; -pub const Elf64_Phdr = extern struct { - p_type: Word, - p_flags: Word, - p_offset: Elf64_Off, - p_vaddr: Elf64_Addr, - p_paddr: Elf64_Addr, - p_filesz: Elf64_Xword, - p_memsz: Elf64_Xword, - p_align: Elf64_Xword, -}; -pub const Elf32_Shdr = extern struct { - sh_name: Word, - sh_type: Word, - sh_flags: Word, - sh_addr: Elf32_Addr, - sh_offset: Elf32_Off, - sh_size: Word, - sh_link: Word, - sh_info: Word, - sh_addralign: Word, - sh_entsize: Word, -}; -pub const Elf64_Shdr = extern struct { - sh_name: Word, - sh_type: Word, - sh_flags: Elf64_Xword, - sh_addr: Elf64_Addr, - sh_offset: Elf64_Off, - sh_size: Elf64_Xword, - sh_link: Word, - sh_info: Word, - sh_addralign: Elf64_Xword, - sh_entsize: Elf64_Xword, -}; -pub const Elf32_Chdr = extern struct { - ch_type: COMPRESS, - ch_size: Word, - ch_addralign: Word, -}; -pub const Elf64_Chdr = extern struct { - ch_type: COMPRESS, - ch_reserved: Word = 0, - ch_size: Elf64_Xword, - ch_addralign: Elf64_Xword, -}; -pub const Elf32_Sym = extern struct { - st_name: Word, - st_value: Elf32_Addr, - st_size: Word, - st_info: u8, - st_other: u8, - st_shndx: Elf32_Section, - - pub inline fn st_type(self: @This()) u4 { - return @truncate(self.st_info); - } - pub inline fn st_bind(self: @This()) u4 { - return @truncate(self.st_info >> 4); - } -}; -pub const Elf64_Sym = extern struct { - st_name: Word, - st_info: u8, - st_other: u8, - st_shndx: Elf64_Section, - st_value: Elf64_Addr, - st_size: Elf64_Xword, - - pub inline fn st_type(self: @This()) u4 { - return @truncate(self.st_info); - } - pub inline fn st_bind(self: @This()) u4 { - return @truncate(self.st_info >> 4); - } -}; -pub const Elf32_Syminfo = extern struct { - si_boundto: Half, - si_flags: Half, -}; -pub const Elf64_Syminfo = extern struct { - si_boundto: Half, - si_flags: Half, -}; -pub const Elf32_Rel = extern struct { - r_offset: Elf32_Addr, - r_info: Word, - - pub inline fn r_sym(self: @This()) u24 { - return @truncate(self.r_info >> 8); - } - pub inline fn r_type(self: @This()) u8 { - return @truncate(self.r_info); - } -}; -pub const Elf64_Rel = extern struct { - r_offset: Elf64_Addr, - r_info: Elf64_Xword, - - pub inline fn r_sym(self: @This()) u32 { - return @truncate(self.r_info >> 32); - } - pub inline fn r_type(self: @This()) u32 { - return @truncate(self.r_info); - } -}; -pub const Elf32_Rela = extern struct { - r_offset: Elf32_Addr, - r_info: Word, - r_addend: Sword, - - pub inline fn r_sym(self: @This()) u24 { - return @truncate(self.r_info >> 8); - } - pub inline fn r_type(self: @This()) u8 { - return @truncate(self.r_info); - } -}; -pub const Elf64_Rela = extern struct { - r_offset: Elf64_Addr, - r_info: Elf64_Xword, - r_addend: Elf64_Sxword, +pub const Xword = u64; +pub const Sxword = i64; +pub const Section = u16; - pub inline fn r_sym(self: @This()) u32 { - return @truncate(self.r_info >> 32); - } - pub inline fn r_type(self: @This()) u32 { - return @truncate(self.r_info); - } -}; -pub const Elf32_Relr = Word; -pub const Elf64_Relr = Elf64_Xword; -pub const Elf32_Dyn = extern struct { - d_tag: Sword, - d_val: Elf32_Addr, -}; -pub const Elf64_Dyn = extern struct { - d_tag: Elf64_Sxword, - d_val: Elf64_Addr, -}; pub const Verdef = extern struct { version: Half, flags: Half, - ndx: VER_NDX, + ndx: VersionIndex, cnt: Half, hash: Word, aux: Word, @@ -920,20 +884,6 @@ pub const Verdaux = extern struct { name: Word, next: Word, }; -pub const Elf32_Verneed = extern struct { - vn_version: Half, - vn_cnt: Half, - vn_file: Word, - vn_aux: Word, - vn_next: Word, -}; -pub const Elf64_Verneed = extern struct { - vn_version: Half, - vn_cnt: Half, - vn_file: Word, - vn_aux: Word, - vn_next: Word, -}; pub const Vernaux = extern struct { hash: Word, flags: Half, @@ -941,82 +891,16 @@ pub const Vernaux = extern struct { name: Word, next: Word, }; -pub const Elf32_auxv_t = extern struct { - a_type: u32, - a_un: extern union { - a_val: u32, - }, -}; -pub const Elf64_auxv_t = extern struct { - a_type: u64, - a_un: extern union { - a_val: u64, - }, -}; -pub const Elf32_Nhdr = extern struct { - n_namesz: Word, - n_descsz: Word, - n_type: Word, -}; -pub const Elf64_Nhdr = extern struct { - n_namesz: Word, - n_descsz: Word, - n_type: Word, -}; -pub const Elf32_Move = extern struct { - m_value: Elf32_Xword, - m_info: Word, - m_poffset: Word, - m_repeat: Half, - m_stride: Half, -}; -pub const Elf64_Move = extern struct { - m_value: Elf64_Xword, - m_info: Elf64_Xword, - m_poffset: Elf64_Xword, - m_repeat: Half, - m_stride: Half, -}; -pub const Elf32_gptab = extern union { - gt_header: extern struct { - gt_current_g_value: Word, - gt_unused: Word, - }, - gt_entry: extern struct { - gt_g_value: Word, - gt_bytes: Word, - }, -}; -pub const Elf32_RegInfo = extern struct { - ri_gprmask: Word, - ri_cprmask: [4]Word, - ri_gp_value: Sword, -}; pub const Elf_Options = extern struct { kind: u8, size: u8, - section: Elf32_Section, + section: Section, info: Word, }; pub const Elf_Options_Hw = extern struct { hwp_flags1: Word, hwp_flags2: Word, }; -pub const Elf32_Lib = extern struct { - l_name: Word, - l_time_stamp: Word, - l_checksum: Word, - l_version: Word, - l_flags: Word, -}; -pub const Elf64_Lib = extern struct { - l_name: Word, - l_time_stamp: Word, - l_checksum: Word, - l_version: Word, - l_flags: Word, -}; -pub const Elf32_Conflict = Elf32_Addr; pub const Elf_MIPS_ABIFlags_v0 = extern struct { version: Half, isa_level: u8, @@ -1031,70 +915,778 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct { flags2: Word, }; -comptime { - assert(@sizeOf(Elf32_Ehdr) == 52); - assert(@sizeOf(Elf64_Ehdr) == 64); - - assert(@sizeOf(Elf32_Phdr) == 32); - assert(@sizeOf(Elf64_Phdr) == 56); - - assert(@sizeOf(Elf32_Shdr) == 40); - assert(@sizeOf(Elf64_Shdr) == 64); -} - -pub const Auxv = switch (@sizeOf(usize)) { - 4 => Elf32_auxv_t, - 8 => Elf64_auxv_t, - else => @compileError("expected pointer size of 32 or 64"), -}; -pub const Ehdr = switch (@sizeOf(usize)) { - 4 => Elf32_Ehdr, - 8 => Elf64_Ehdr, - else => @compileError("expected pointer size of 32 or 64"), +pub const ELFCLASS = enum(u8) { + NONE = 0, + @"32" = 1, + @"64" = 2, + _, }; -pub const Phdr = switch (@sizeOf(usize)) { - 4 => Elf32_Phdr, - 8 => Elf64_Phdr, - else => @compileError("expected pointer size of 32 or 64"), + +pub const ELFDATA = enum(u8) { + NONE = 0, + LSB = 1, + MSB = 2, + _, }; -pub const Dyn = switch (@sizeOf(usize)) { - 4 => Elf32_Dyn, - 8 => Elf64_Dyn, - else => @compileError("expected pointer size of 32 or 64"), + +pub const EV = enum(u8) { + NONE = 0, + CURRENT = 1, + _, }; -pub const Rel = switch (@sizeOf(usize)) { - 4 => Elf32_Rel, - 8 => Elf64_Rel, - else => @compileError("expected pointer size of 32 or 64"), + +pub const EIdent = packed struct(u128) { + ei_magic: u32, + ei_class: ELFCLASS, + ei_data: ELFDATA, + ei_version: EV, + ei_osabi: OSABI, + ei_abiversion: u8, + _pad: u56 = 0, + + pub fn magic(ei: *align(1) const EIdent) *const [4]u8 { + return mem.asBytes(&ei.ei_magic); + } }; -pub const Rela = switch (@sizeOf(usize)) { - 4 => Elf32_Rela, - 8 => Elf64_Rela, - else => @compileError("expected pointer size of 32 or 64"), + +pub const SymInfo = packed struct(u8) { + type: STT = .NOTYPE, + bind: STB = .LOCAL, }; -pub const Relr = switch (@sizeOf(usize)) { - 4 => Elf32_Relr, - 8 => Elf64_Relr, - else => @compileError("expected pointer size of 32 or 64"), + +pub const SHF_OSBITS = packed struct(u8) { + bits: u8, + + /// Not to be GCed by the linker + /// + /// For os bits. + pub const GNU_RETAIN: SHF_OSBITS = .{ .bits = 0x2 }; + + /// Section contains text/data which may be replicated in other sections. + /// Linker must retain only one copy. + pub const MIPS_NODUPES: SHF_OSBITS = .{ .bits = 0x10 }; + + /// Linker must generate implicit hidden weak names. + pub const MIPS_NAMES: SHF_OSBITS = .{ .bits = 0x20 }; + + /// Section data local to process. + pub const MIPS_LOCAL: SHF_OSBITS = .{ .bits = 0x40 }; + + /// Do not strip this section. + pub const MIPS_NOSTRIP: SHF_OSBITS = .{ .bits = 0x80 }; + + /// Make code section unreadable when in execute-only mode + /// TODO: according to https://llvm.org/doxygen/namespacellvm_1_1ELF.html this should be a proc bit + pub const ARM_PURECODE: SHF_OSBITS = .{ .bits = 0x20 }; }; -pub const Shdr = switch (@sizeOf(usize)) { - 4 => Elf32_Shdr, - 8 => Elf64_Shdr, - else => @compileError("expected pointer size of 32 or 64"), + +pub const SHF_PROCBITS = packed struct(u4) { + bits: u4, + + /// This section is excluded from the final executable or shared library. + /// + /// For proc bits. + pub const EXCLUDE: SHF_PROCBITS = .{ .bits = 8 }; + + /// If an object file section does not have this flag set, then it may not hold + /// more than 2GB and can be freely referred to in objects using smaller code + /// models. Otherwise, only objects using larger code models can refer to them. + /// For example, a medium code model object can refer to data in a section that + /// sets this flag besides being able to refer to data in a section that does + /// not set it; likewise, a small code model object can refer only to code in a + /// section that does not set this flag. + pub const X86_64_LARGE: SHF_PROCBITS = .{ .bits = 1 }; + + /// All sections with the GPREL flag are grouped into a global data area + /// for faster accesses + pub const HEX_GPREL: SHF_PROCBITS = .{ .bits = 1 }; + + /// Section must be part of global data area. + pub const MIPS_GPREL: SHF_PROCBITS = .{ .bits = 1 }; + + /// This section should be merged. + pub const MIPS_MERGE: SHF_PROCBITS = .{ .bits = 2 }; + + /// Address size to be inferred from section entry size. + pub const MIPS_ADDR: SHF_PROCBITS = .{ .bits = 4 }; + + /// Section data is string data by default. + pub const MIPS_STRING: SHF_PROCBITS = .{ .bits = 8 }; + + /// All sections with the "d" flag are grouped together by the linker to form + /// the data section and the dp register is set to the start of the section by + /// the boot code. + pub const XCORE_DP_SECTION = .{ .bits = 1 }; + + /// All sections with the "c" flag are grouped together by the linker to form + /// the constant pool and the cp register is set to the start of the constant + /// pool by the boot code. + pub const XCORE_CP_SECTION = .{ .bits = 2 }; }; -pub const Chdr = switch (@sizeOf(usize)) { - 4 => Elf32_Chdr, - 8 => Elf64_Chdr, - else => @compileError("expected pointer size of 32 or 64"), + +pub const elf32 = struct { + pub const Addr = u32; + pub const Off = u32; + + pub const Ehdr = extern struct { + e_ident: EIdent align(1), + e_type: ET, + e_machine: EM, + e_version: Word, + e_entry: Addr, + e_phoff: Off, + e_shoff: Off, + e_flags: Word, + e_ehsize: Half, + e_phentsize: Half, + e_phnum: Half, + e_shentsize: Half, + e_shnum: Half, + e_shstrndx: Half, + }; + + pub const Phdr = extern struct { + p_type: PT, + p_offset: Off, + p_vaddr: Addr, + p_paddr: Addr, + p_filesz: Word, + p_memsz: Word, + p_flags: PF, + p_align: Word, + }; + + pub const SHF = packed struct(Word) { + /// Section data should be writable during execution. + write: bool = false, + /// Section occupies memory during program execution. + alloc: bool = false, + /// Section contains executable machine instructions. + execinstr: bool = false, + _pad0: u1 = 0, + /// The data in this section may be merged. + merge: bool = false, + /// The data in this section is null-terminated strings. + strings: bool = false, + /// A field in this section holds a section header table index. + info_link: bool = false, + /// Adds special ordering requirements for link editors. + link_order: bool = false, + /// This section requires special OS-specific processing to avoid incorrect + /// behavior. + os_nonconforming: bool = false, + /// This section is a member of a section group. + group: bool = false, + /// This section holds Thread-Local Storage. + tls: bool = false, + /// Identifies a section containing compressed data. + compressed: bool = false, + _pad1: u8 = 0, + os: SHF_OSBITS = .{ .bits = 0 }, + proc: SHF_PROCBITS = .{ .bits = 0 }, + + pub fn format( + sh_flags: SHF, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + if (sh_flags.write) try writer.writeAll("W"); + if (sh_flags.alloc) try writer.writeAll("A"); + if (sh_flags.execinstr) try writer.writeAll("X"); + if (sh_flags.merge) try writer.writeAll("M"); + if (sh_flags.strings) try writer.writeAll("S"); + if (sh_flags.info_link) try writer.writeAll("I"); + if (sh_flags.link_order) try writer.writeAll("L"); + if (sh_flags.execinstr) try writer.writeAll("E"); + if (sh_flags.compressed) try writer.writeAll("C"); + if (sh_flags.group) try writer.writeAll("G"); + if (sh_flags.os_nonconforming) try writer.writeAll("O"); + if (sh_flags.tls) try writer.writeAll("T"); + if (sh_flags.os.bits != 0) try writer.print(" OS({x})", .{sh_flags.os.bits}); + if (sh_flags.proc.bits != 0) try writer.print(" PROC({x})", .{sh_flags.proc.bits}); + } + }; + + pub const Shdr = extern struct { + sh_name: Word, + sh_type: SHT, + sh_flags: SHF, + sh_addr: Addr, + sh_offset: Off, + sh_size: Word, + sh_link: Word, + sh_info: Word, + sh_addralign: Word, + sh_entsize: Word, + }; + + pub const Chdr = extern struct { + ch_type: COMPRESS, + ch_size: Word, + ch_addralign: Word, + }; + + pub const Sym = extern struct { + st_name: Word, + st_value: Addr, + st_size: Word, + st_info: SymInfo, + st_other: u8, + st_shndx: SHN, + }; + + pub const Syminfo = extern struct { + si_boundto: Half, + si_flags: Half, + }; + + pub const Rel = extern struct { + pub const Info = packed struct(Word) { + type: u8, + sym: u24, + }; + + r_offset: Addr, + r_info: Info, + }; + + pub const Rela = extern struct { + r_offset: Addr, + r_info: Rel.Info, + r_addend: Sword, + }; + + pub const Relr = Word; + + pub const DT = enum(Sword) { + /// Note that this range includes the 0xd offset for .LOOS (since it's easier to compare to documentation). + pub const OsRange = math.IntFittingRange(0, @intFromEnum(DT.LOOS) - @intFromEnum(DT.HIOS) + 0xd); + + /// Note that this function automatically subtracts 0xd from the value (since it's easier to compare to documentation). + pub fn os(comptime value: OsRange) DT { + comptime if (value < 0xd) + @compileError("invalid OS value"); + + const loos = @intFromEnum(DT.LOOS); + return @enumFromInt(loos + value - 0xd); + } + + /// Note that this function automatically adds 0xd to the value (since it's easier to compare to documentation). + pub fn getOs(d_tag: DT) ?OsRange { + const as_int = @intFromEnum(d_tag); + const loos = @intFromEnum(DT.LOOS); + if (as_int < loos or as_int > @intFromEnum(DT.HIOS)) + return null; + return as_int - loos + 0xd; + } + + const Reserve = EnumRange(DT, .LOPROC, .HIPROC); + pub const ReserveRange = Reserve.Range; + pub const reserve = Reserve.fromInt; + pub const getReserve = Reserve.toInt; + + const Proc = EnumRange(DT, .LOPROC, .HIPROC); + pub const ProcRange = Proc.Range; + pub const proc = Proc.fromInt; + pub const getProc = Proc.toInt; + + NULL = 0, + NEEDED = 1, + PLTRELSZ = 2, + PLTGOT = 3, + HASH = 4, + STRTAB = 5, + SYMTAB = 6, + RELA = 7, + RELASZ = 8, + RELAENT = 9, + STRSZ = 10, + SYMENT = 11, + INIT = 12, + FINI = 13, + SONAME = 14, + RPATH = 15, + SYMBOLIC = 16, + REL = 17, + RELSZ = 18, + RELENT = 19, + PLTREL = 20, + DEBUG = 21, + TEXTREL = 22, + JMPREL = 23, + BIND_NOW = 24, + INIT_ARRAY = 25, + FINI_ARRAY = 26, + INIT_ARRAYSZ = 27, + FINI_ARRAYSZ = 28, + RUNPATH = 29, + FLAGS = 30, + PREINIT_ARRAY = 32, + PREINIT_ARRAYSZ = 33, + SYMTAB_SHNDX = 34, + RELRSZ = 35, + RELR = 36, + RELRENT = 37, + NUM = 38, + LOOS = 0x6000000d, + HIOS = 0x6fffefff, + LORESERVE = 0x6ffff000, + HIRESERVE = 0x6fffffff, + LOPROC = 0x70000000, + HIPROC = 0x7fffffff, + _, + + pub const ENCODING: DT = @enumFromInt(32); + pub const PROCNUM: DT = @enumFromInt(36); + + pub const VALRNGLO: DT = reserve(0xd00); + pub const GNU_PRELINKED: DT = reserve(0xdf5); + pub const GNU_CONFLICTSZ: DT = reserve(0xdf6); + pub const GNU_LIBLISTSZ: DT = reserve(0xdf7); + pub const CHECKSUM: DT = reserve(0xdf8); + pub const PLTPADSZ: DT = reserve(0xdf9); + pub const MOVEENT: DT = reserve(0xdfa); + pub const MOVESZ: DT = reserve(0xdfb); + pub const FEATURE_1: DT = reserve(0xdfc); + pub const POSFLAG_1: DT = reserve(0xdfd); + + pub const SYMINSZ: DT = reserve(0xdfe); + pub const SYMINENT: DT = reserve(0xdff); + pub const VALRNGHI: DT = reserve(0xdff); + pub const VALNUM: DT = @enumFromInt(12); + + pub const ADDRRNGLO: DT = reserve(0xe00); + pub const GNU_HASH: DT = reserve(0xef5); + pub const TLSDESC_PLT: DT = reserve(0xef6); + pub const TLSDESC_GOT: DT = reserve(0xef7); + pub const GNU_CONFLICT: DT = reserve(0xef8); + pub const GNU_LIBLIST: DT = reserve(0xef9); + pub const CONFIG: DT = reserve(0xefa); + pub const DEPAUDIT: DT = reserve(0xefb); + pub const AUDIT: DT = reserve(0xefc); + pub const PLTPAD: DT = reserve(0xefd); + pub const MOVETAB: DT = reserve(0xefe); + pub const SYMINFO: DT = reserve(0xeff); + pub const ADDRRNGHI: DT = reserve(0xeff); + pub const ADDRNUM: DT = @enumFromInt(11); + + pub const VERSYM: DT = reserve(0xff0); + + pub const RELACOUNT: DT = reserve(0xff9); + pub const RELCOUNT: DT = reserve(0xffa); + + pub const FLAGS_1: DT = reserve(0xffb); + pub const VERDEF: DT = reserve(0xffc); + + pub const VERDEFNUM: DT = reserve(0xffd); + pub const VERNEED: DT = reserve(0xffe); + + pub const VERNEEDNUM: DT = reserve(0xfff); + pub const VERSIONTAGNUM: DT = @enumFromInt(16); + + pub const AUXILIARY: DT = proc(0xffffffd); + pub const FILTER: DT = proc(0xfffffff); + pub const EXTRANUM: DT = @enumFromInt(3); + + pub const SPARC_REGISTER: DT = proc(0x1); + pub const SPARC_NUM: DT = @enumFromInt(2); + + pub const MIPS_RLD_VERSION: DT = proc(0x1); + pub const MIPS_TIME_STAMP: DT = proc(0x2); + pub const MIPS_ICHECKSUM: DT = proc(0x3); + pub const MIPS_IVERSION: DT = proc(0x4); + pub const MIPS_FLAGS: DT = proc(0x5); + pub const MIPS_BASE_ADDRESS: DT = proc(0x6); + pub const MIPS_MSYM: DT = proc(0x7); + pub const MIPS_CONFLICT: DT = proc(0x8); + pub const MIPS_LIBLIST: DT = proc(0x9); + pub const MIPS_LOCAL_GOTNO: DT = proc(0xa); + pub const MIPS_CONFLICTNO: DT = proc(0xb); + pub const MIPS_LIBLISTNO: DT = proc(0x10); + pub const MIPS_SYMTABNO: DT = proc(0x11); + pub const MIPS_UNREFEXTNO: DT = proc(0x12); + pub const MIPS_GOTSYM: DT = proc(0x13); + pub const MIPS_HIPAGENO: DT = proc(0x14); + pub const MIPS_RLD_MAP: DT = proc(0x16); + pub const MIPS_DELTA_CLASS: DT = proc(0x17); + pub const MIPS_DELTA_CLASS_NO: DT = proc(0x18); + + pub const MIPS_DELTA_INSTANCE: DT = proc(0x19); + pub const MIPS_DELTA_INSTANCE_NO: DT = proc(0x1a); + + pub const MIPS_DELTA_RELOC: DT = proc(0x1b); + pub const MIPS_DELTA_RELOC_NO: DT = proc(0x1c); + + pub const MIPS_DELTA_SYM: DT = proc(0x1d); + + pub const MIPS_DELTA_SYM_NO: DT = proc(0x1e); + + pub const MIPS_DELTA_CLASSSYM: DT = proc(0x20); + + pub const MIPS_DELTA_CLASSSYM_NO: DT = proc(0x21); + + pub const MIPS_CXX_FLAGS: DT = proc(0x22); + pub const MIPS_PIXIE_INIT: DT = proc(0x23); + pub const MIPS_SYMBOL_LIB: DT = proc(0x24); + pub const MIPS_LOCALPAGE_GOTIDX: DT = proc(0x25); + pub const MIPS_LOCAL_GOTIDX: DT = proc(0x26); + pub const MIPS_HIDDEN_GOTIDX: DT = proc(0x27); + pub const MIPS_PROTECTED_GOTIDX: DT = proc(0x28); + pub const MIPS_OPTIONS: DT = proc(0x29); + pub const MIPS_INTERFACE: DT = proc(0x2a); + pub const MIPS_DYNSTR_ALIGN: DT = proc(0x2b); + pub const MIPS_INTERFACE_SIZE: DT = proc(0x2c); + pub const MIPS_RLD_TEXT_RESOLVE_ADDR: DT = proc(0x2d); + + pub const MIPS_PERF_SUFFIX: DT = proc(0x2e); + + pub const MIPS_COMPACT_SIZE: DT = proc(0x2f); + pub const MIPS_GP_VALUE: DT = proc(0x30); + pub const MIPS_AUX_DYNAMIC: DT = proc(0x31); + + pub const MIPS_PLTGOT: DT = proc(0x32); + + pub const MIPS_RWPLT: DT = proc(0x34); + pub const MIPS_RLD_MAP_REL: DT = proc(0x35); + pub const MIPS_NUM: DT = @enumFromInt(0x36); + + pub const ALPHA_PLTRO: DT = proc(0x0); + pub const ALPHA_NUM: DT = @enumFromInt(1); + + pub const PPC_GOT: DT = proc(0x0); + pub const PPC_OPT: DT = proc(0x1); + pub const PPC_NUM: DT = @enumFromInt(2); + + pub const PPC64_GLINK: DT = proc(0x0); + pub const PPC64_OPD: DT = proc(0x1); + pub const PPC64_OPDSZ: DT = proc(0x2); + pub const PPC64_OPT: DT = proc(0x3); + pub const PPC64_NUM: DT = @enumFromInt(4); + + pub const IA_64_PLT_RESERVE: DT = proc(0x0); + pub const IA_64_NUM: DT = @enumFromInt(1); + + pub const NIOS2_GP: DT = proc(0x2); + }; + + pub const Dyn = extern struct { + d_tag: DT, + d_val: Addr, + }; + + pub const Verneed = extern struct { + vn_version: Half, + vn_cnt: Half, + vn_file: Word, + vn_aux: Word, + vn_next: Word, + }; + + pub const AT = enum(u32) { + NULL = 0, + IGNORE = 1, + EXECFD = 2, + PHDR = 3, + PHENT = 4, + PHNUM = 5, + PAGESZ = 6, + BASE = 7, + FLAGS = 8, + ENTRY = 9, + NOTELF = 10, + UID = 11, + EUID = 12, + GID = 13, + EGID = 14, + CLKTCK = 17, + PLATFORM = 15, + HWCAP = 16, + FPUCW = 18, + DCACHEBSIZE = 19, + ICACHEBSIZE = 20, + UCACHEBSIZE = 21, + IGNOREPPC = 22, + SECURE = 23, + BASE_PLATFORM = 24, + RANDOM = 25, + HWCAP2 = 26, + EXECFN = 31, + SYSINFO = 32, + SYSINFO_EHDR = 33, + L1I_CACHESHAPE = 34, + L1D_CACHESHAPE = 35, + L2_CACHESHAPE = 36, + L3_CACHESHAPE = 37, + L1I_CACHESIZE = 40, + L1I_CACHEGEOMETRY = 41, + L1D_CACHESIZE = 42, + L1D_CACHEGEOMETRY = 43, + L2_CACHESIZE = 44, + L2_CACHEGEOMETRY = 45, + L3_CACHESIZE = 46, + L3_CACHEGEOMETRY = 47, + }; + + pub const auxv_t = extern struct { + a_type: AT, + a_un: extern union { + a_val: u32, + }, + }; + + pub const Nhdr = extern struct { + n_namesz: Word, + n_descsz: Word, + n_type: Word, + }; + + pub const Move = extern struct { + m_value: Xword, + m_info: Word, + m_poffset: Word, + m_repeat: Half, + m_stride: Half, + }; + + pub const gptab = extern union { + gt_header: extern struct { + gt_current_g_value: Word, + gt_unused: Word, + }, + gt_entry: extern struct { + gt_g_value: Word, + gt_bytes: Word, + }, + }; + + pub const RegInfo = extern struct { + ri_gprmask: Word, + ri_cprmask: [4]Word, + ri_gp_value: Sword, + }; + + pub const Lib = extern struct { + l_name: Word, + l_time_stamp: Word, + l_checksum: Word, + l_version: Word, + l_flags: Word, + }; + + pub const Conflict = Addr; }; -pub const Sym = switch (@sizeOf(usize)) { - 4 => Elf32_Sym, - 8 => Elf64_Sym, - else => @compileError("expected pointer size of 32 or 64"), + +pub const elf64 = struct { + pub const Addr = u64; + pub const Off = u64; + + pub const Ehdr = extern struct { + e_ident: EIdent align(1), + e_type: ET, + e_machine: EM, + e_version: Word, + e_entry: Addr, + e_phoff: Off, + e_shoff: Off, + e_flags: Word, + e_ehsize: Half, + e_phentsize: Half, + e_phnum: Half, + e_shentsize: Half, + e_shnum: Half, + e_shstrndx: Half, + }; + + pub const Phdr = extern struct { + p_type: PT, + p_flags: PF, + p_offset: Off, + p_vaddr: Addr, + p_paddr: Addr, + p_filesz: Xword, + p_memsz: Xword, + p_align: Xword, + }; + + pub const SHF = packed struct(Xword) { + /// Section data should be writable during execution. + write: bool = false, + /// Section occupies memory during program execution. + alloc: bool = false, + /// Section contains executable machine instructions. + execinstr: bool = false, + _pad0: u1 = 0, + /// The data in this section may be merged. + merge: bool = false, + /// The data in this section is null-terminated strings. + strings: bool = false, + /// A field in this section holds a section header table index. + info_link: bool = false, + /// Adds special ordering requirements for link editors. + link_order: bool = false, + /// This section requires special OS-specific processing to avoid incorrect + /// behavior. + os_nonconforming: bool = false, + /// This section is a member of a section group. + group: bool = false, + /// This section holds Thread-Local Storage. + tls: bool = false, + /// Identifies a section containing compressed data. + compressed: bool = false, + _pad1: u8 = 0, + os: SHF_OSBITS = .{ .bits = 0 }, + proc: SHF_PROCBITS = .{ .bits = 0 }, + _pad2: u32 = 0, + + pub fn format( + sh_flags: SHF, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + if (sh_flags.write) try writer.writeAll("W"); + if (sh_flags.alloc) try writer.writeAll("A"); + if (sh_flags.execinstr) try writer.writeAll("X"); + if (sh_flags.merge) try writer.writeAll("M"); + if (sh_flags.strings) try writer.writeAll("S"); + if (sh_flags.info_link) try writer.writeAll("I"); + if (sh_flags.link_order) try writer.writeAll("L"); + if (sh_flags.execinstr) try writer.writeAll("E"); + if (sh_flags.compressed) try writer.writeAll("C"); + if (sh_flags.group) try writer.writeAll("G"); + if (sh_flags.os_nonconforming) try writer.writeAll("O"); + if (sh_flags.tls) try writer.writeAll("T"); + if (sh_flags.os.bits != 0) try writer.print(" OS({x})", .{sh_flags.os.bits}); + if (sh_flags.proc.bits != 0) try writer.print(" PROC({x})", .{sh_flags.proc.bits}); + } + }; + + pub const Shdr = extern struct { + sh_name: Word, + sh_type: SHT, + sh_flags: SHF, + sh_addr: Addr, + sh_offset: Off, + sh_size: Xword, + sh_link: Word, + sh_info: Word, + sh_addralign: Xword, + sh_entsize: Xword, + }; + + pub const Chdr = extern struct { + ch_type: COMPRESS, + ch_reserved: Word = 0, + ch_size: Xword, + ch_addralign: Xword, + }; + + pub const Sym = extern struct { + st_name: Word, + st_info: SymInfo, + st_other: u8, + st_shndx: SHN, + st_value: Addr, + st_size: Xword, + + pub fn shndx(sym: Sym) std.meta.Tag(SHN) { + return @intFromEnum(sym.st_shndx); + } + }; + + pub const Syminfo = extern struct { + si_boundto: Half, + si_flags: Half, + }; + + pub const Rel = extern struct { + pub const Info = packed struct(Xword) { + type: u32, + sym: u32, + }; + + r_offset: Addr, + r_info: Info, + }; + + pub const Rela = extern struct { + r_offset: Addr, + r_info: Rel.Info, + r_addend: Sxword, + }; + + pub const Relr = Xword; + + pub const DT = @Type(Type: { + var @"enum" = @typeInfo(elf32.DT).@"enum"; + @"enum".tag_type = Sxword; + break :Type .{ .@"enum" = @"enum" }; + }); + + pub const Dyn = extern struct { + d_tag: DT, + d_val: Addr, + }; + + pub const Verneed = extern struct { + vn_version: Half, + vn_cnt: Half, + vn_file: Word, + vn_aux: Word, + vn_next: Word, + }; + + pub const AT = @Type(Type: { + var @"enum" = @typeInfo(elf32.AT).@"enum"; + @"enum".tag_type = u64; + break :Type .{ .@"enum" = @"enum" }; + }); + + pub const auxv_t = extern struct { + a_type: AT, + a_un: extern union { + a_val: u64, + }, + }; + + pub const Nhdr = extern struct { + n_namesz: Word, + n_descsz: Word, + n_type: Word, + }; + + pub const Move = extern struct { + m_value: Xword, + m_info: Xword, + m_poffset: Xword, + m_repeat: Half, + m_stride: Half, + }; + + pub const Lib = extern struct { + l_name: Word, + l_time_stamp: Word, + l_checksum: Word, + l_version: Word, + l_flags: Word, + }; }; -pub const Addr = switch (@sizeOf(usize)) { - 4 => Elf32_Addr, - 8 => Elf64_Addr, + +comptime { + assert(@sizeOf(elf32.Ehdr) == 52); + assert(@sizeOf(elf64.Ehdr) == 64); + + assert(@sizeOf(elf32.Phdr) == 32); + assert(@sizeOf(elf64.Phdr) == 56); + + assert(@sizeOf(elf32.Shdr) == 40); + assert(@sizeOf(elf64.Shdr) == 64); +} + +pub const native = switch (@sizeOf(usize)) { + 4 => elf32, + 8 => elf64, else => @compileError("expected pointer size of 32 or 64"), }; @@ -1618,133 +2210,38 @@ pub const EM = enum(u16) { pub const GRP_COMDAT = 1; -/// Section data should be writable during execution. -pub const SHF_WRITE = 0x1; - -/// Section occupies memory during program execution. -pub const SHF_ALLOC = 0x2; - -/// Section contains executable machine instructions. -pub const SHF_EXECINSTR = 0x4; - -/// The data in this section may be merged. -pub const SHF_MERGE = 0x10; - -/// The data in this section is null-terminated strings. -pub const SHF_STRINGS = 0x20; - -/// A field in this section holds a section header table index. -pub const SHF_INFO_LINK = 0x40; - -/// Adds special ordering requirements for link editors. -pub const SHF_LINK_ORDER = 0x80; - -/// This section requires special OS-specific processing to avoid incorrect -/// behavior. -pub const SHF_OS_NONCONFORMING = 0x100; - -/// This section is a member of a section group. -pub const SHF_GROUP = 0x200; - -/// This section holds Thread-Local Storage. -pub const SHF_TLS = 0x400; - -/// Identifies a section containing compressed data. -pub const SHF_COMPRESSED = 0x800; - -/// Not to be GCed by the linker -pub const SHF_GNU_RETAIN = 0x200000; - -/// This section is excluded from the final executable or shared library. -pub const SHF_EXCLUDE = 0x80000000; - -/// Start of target-specific flags. -pub const SHF_MASKOS = 0x0ff00000; - -/// Bits indicating processor-specific flags. -pub const SHF_MASKPROC = 0xf0000000; - -/// All sections with the "d" flag are grouped together by the linker to form -/// the data section and the dp register is set to the start of the section by -/// the boot code. -pub const XCORE_SHF_DP_SECTION = 0x10000000; - -/// All sections with the "c" flag are grouped together by the linker to form -/// the constant pool and the cp register is set to the start of the constant -/// pool by the boot code. -pub const XCORE_SHF_CP_SECTION = 0x20000000; - -/// If an object file section does not have this flag set, then it may not hold -/// more than 2GB and can be freely referred to in objects using smaller code -/// models. Otherwise, only objects using larger code models can refer to them. -/// For example, a medium code model object can refer to data in a section that -/// sets this flag besides being able to refer to data in a section that does -/// not set it; likewise, a small code model object can refer only to code in a -/// section that does not set this flag. -pub const SHF_X86_64_LARGE = 0x10000000; - -/// All sections with the GPREL flag are grouped into a global data area -/// for faster accesses -pub const SHF_HEX_GPREL = 0x10000000; - -/// Section contains text/data which may be replicated in other sections. -/// Linker must retain only one copy. -pub const SHF_MIPS_NODUPES = 0x01000000; - -/// Linker must generate implicit hidden weak names. -pub const SHF_MIPS_NAMES = 0x02000000; - -/// Section data local to process. -pub const SHF_MIPS_LOCAL = 0x04000000; - -/// Do not strip this section. -pub const SHF_MIPS_NOSTRIP = 0x08000000; - -/// Section must be part of global data area. -pub const SHF_MIPS_GPREL = 0x10000000; - -/// This section should be merged. -pub const SHF_MIPS_MERGE = 0x20000000; - -/// Address size to be inferred from section entry size. -pub const SHF_MIPS_ADDR = 0x40000000; - -/// Section data is string data by default. -pub const SHF_MIPS_STRING = 0x80000000; - -/// Make code section unreadable when in execute-only mode -pub const SHF_ARM_PURECODE = 0x2000000; - -/// Execute -pub const PF_X = 1; - -/// Write -pub const PF_W = 2; +pub const PF = packed struct(Word) { + execute: bool = false, + write: bool = false, + read: bool = false, + _pad: u17 = 0, + /// Bits for operating system-specific semantics. + os: u8 = 0, + /// Bits for processor-specific semantics. + proc: u4 = 0, +}; -/// Read -pub const PF_R = 4; +pub const SHN = enum(Section) { + const Reserve = EnumRange(SHN, .LORESERVE, .HIRESERVE); + pub const ReserveRange = Reserve.Range; + pub const reserve = Reserve.fromInt; + pub const getReserve = Reserve.toInt; -/// Bits for operating system-specific semantics. -pub const PF_MASKOS = 0x0ff00000; + /// Undefined section + UNDEF = 0, + LORESERVE = 0xff00, + HIRESERVE = 0xffff, + _, -/// Bits for processor-specific semantics. -pub const PF_MASKPROC = 0xf0000000; + pub const LOPROC = reserve(0x00); + pub const HIPROC = reserve(0x1f); -/// Undefined section -pub const SHN_UNDEF = 0; -/// Start of reserved indices -pub const SHN_LORESERVE = 0xff00; -/// Start of processor-specific -pub const SHN_LOPROC = 0xff00; -/// End of processor-specific -pub const SHN_HIPROC = 0xff1f; -pub const SHN_LIVEPATCH = 0xff20; -/// Associated symbol is absolute -pub const SHN_ABS = 0xfff1; -/// Associated symbol is common -pub const SHN_COMMON = 0xfff2; -/// End of reserved indices -pub const SHN_HIRESERVE = 0xffff; + pub const LIVEPATCH = reserve(0x20); + /// Associated symbol is absolute + pub const ABS = reserve(0xf1); + /// Associated symbol is common + pub const COMMON = reserve(0xf2); +}; // Legal values for ch_type (compression algorithm). pub const COMPRESS = enum(u32) { @@ -2432,3 +2929,23 @@ pub const gnu_hash = struct { try std.testing.expectEqual(0x8ae9f18e, calculate("flapenguin.me")); } }; + +fn EnumRange(E: type, start: E, end: E) type { + const start_int = @intFromEnum(start); + const end_int = @intFromEnum(end); + + return struct { + pub const Range = math.IntFittingRange(0, end_int - start_int); + + pub fn toInt(value: E) ?Range { + const as_int = @intFromEnum(value); + if (as_int < start_int or as_int > end_int) return null; + return @truncate(as_int - start_int); + } + + pub fn fromInt(comptime value: Range) E { + comptime assert(value <= end_int - start_int); + return @enumFromInt(start_int + value); + } + }; +} diff --git a/lib/std/std.zig b/lib/std/std.zig index 94851657a680..9779d689b42f 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -170,6 +170,7 @@ comptime { test { testing.refAllDecls(@This()); + testing.refAllDeclsRecursive(elf); } comptime { From 63745ce8949c8db7aff956f8f8c3df43e6132ff2 Mon Sep 17 00:00:00 2001 From: Carmen Date: Fri, 18 Apr 2025 22:52:41 +0200 Subject: [PATCH 2/2] downstream changes --- lib/compiler/aro/backend/Object/Elf.zig | 82 ++-- lib/compiler/objcopy.zig | 120 +++-- lib/std/Build/Step/CheckObject.zig | 155 +++--- lib/std/dynamic_library.zig | 41 +- lib/std/elf.zig | 42 ++ src/link.zig | 2 +- src/link/Elf.zig | 608 ++++++++++-------------- src/link/Elf/Atom.zig | 156 +++--- src/link/Elf/AtomList.zig | 4 +- src/link/Elf/Merge.zig | 8 +- src/link/Elf/Object.zig | 152 +++--- src/link/Elf/SharedObject.zig | 56 ++- src/link/Elf/Symbol.zig | 54 +-- src/link/Elf/ZigObject.zig | 6 +- src/link/Elf/eh_frame.zig | 52 +- src/link/Elf/synthetic_sections.zig | 62 +-- test/standalone/pie/main.zig | 2 +- tools/gen_stubs.zig | 83 ++-- 18 files changed, 816 insertions(+), 869 deletions(-) diff --git a/lib/compiler/aro/backend/Object/Elf.zig b/lib/compiler/aro/backend/Object/Elf.zig index 9b4f347de575..0bb060584749 100644 --- a/lib/compiler/aro/backend/Object/Elf.zig +++ b/lib/compiler/aro/backend/Object/Elf.zig @@ -7,8 +7,8 @@ const Section = struct { data: std.ArrayList(u8), relocations: std.ArrayListUnmanaged(Relocation) = .empty, flags: u64, - type: u32, - index: u16 = undefined, + type: std.elf.SHT, + index: std.elf.SHN = undefined, }; const Symbol = struct { @@ -86,7 +86,7 @@ pub fn getSection(elf: *Elf, section_kind: Object.Section) !*std.ArrayList(u8) { const section = try elf.arena.allocator().create(Section); section.* = .{ .data = std.ArrayList(u8).init(elf.arena.child_allocator), - .type = std.elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = switch (section_kind) { .func, .custom => std.elf.SHF_ALLOC + std.elf.SHF_EXECINSTR, .strings => std.elf.SHF_ALLOC + std.elf.SHF_MERGE + std.elf.SHF_STRINGS, @@ -116,16 +116,16 @@ pub fn declareSymbol( const section_name = sectionString(section_kind); break :blk elf.sections.get(section_name); }; - const binding: u8 = switch (linkage) { - .Internal => std.elf.STB_LOCAL, - .Strong => std.elf.STB_GLOBAL, - .Weak => std.elf.STB_WEAK, + const binding: std.elf.STB = switch (linkage) { + .Internal => .LOCAL, + .Strong => .GLOBAL, + .Weak => .WEAK, .LinkOnce => unreachable, }; - const sym_type: u8 = switch (@"type") { - .func => std.elf.STT_FUNC, - .variable => std.elf.STT_OBJECT, - .external => std.elf.STT_NOTYPE, + const sym_type: std.elf.STT = switch (@"type") { + .func => .FUNC, + .variable => .OBJECT, + .external => .NOTYPE, }; const name = if (maybe_name) |some| some else blk: { defer elf.unnamed_symbol_mangle += 1; @@ -174,29 +174,29 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { var buf_writer = std.io.bufferedWriter(file.writer()); const w = buf_writer.writer(); - var num_sections: std.elf.Elf64_Half = additional_sections; - var relocations_len: std.elf.Elf64_Off = 0; - var sections_len: std.elf.Elf64_Off = 0; + var num_sections: std.elf.Half = additional_sections; + var relocations_len: std.elf.elf64.Off = 0; + var sections_len: std.elf.elf64.Off = 0; { var it = elf.sections.valueIterator(); while (it.next()) |sect| { sections_len += sect.*.data.items.len; - relocations_len += sect.*.relocations.items.len * @sizeOf(std.elf.Elf64_Rela); - sect.*.index = num_sections; + relocations_len += sect.*.relocations.items.len * @sizeOf(std.elf.elf64.Rela); + sect.*.index = @enumFromInt(num_sections); num_sections += 1; num_sections += @intFromBool(sect.*.relocations.items.len != 0); } } - const symtab_len = (elf.local_symbols.count() + elf.global_symbols.count() + 1) * @sizeOf(std.elf.Elf64_Sym); + const symtab_len = (elf.local_symbols.count() + elf.global_symbols.count() + 1) * @sizeOf(std.elf.elf64.Sym); - const symtab_offset = @sizeOf(std.elf.Elf64_Ehdr) + sections_len; + const symtab_offset = @sizeOf(std.elf.elf64.Ehdr) + sections_len; const symtab_offset_aligned = std.mem.alignForward(u64, symtab_offset, 8); const rela_offset = symtab_offset_aligned + symtab_len; const strtab_offset = rela_offset + relocations_len; const sh_offset = strtab_offset + elf.strtab_len; const sh_offset_aligned = std.mem.alignForward(u64, sh_offset, 16); - const elf_header = std.elf.Elf64_Ehdr{ + const elf_header = std.elf.elf64.Ehdr{ .e_ident = .{ 0x7F, 'E', 'L', 'F', 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, .e_type = std.elf.ET.REL, // we only produce relocatables .e_machine = elf.obj.target.toElfMachine(), @@ -205,10 +205,10 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { .e_phoff = 0, // no program header .e_shoff = sh_offset_aligned, // section headers offset .e_flags = 0, // no flags - .e_ehsize = @sizeOf(std.elf.Elf64_Ehdr), + .e_ehsize = @sizeOf(std.elf.elf64.Ehdr), .e_phentsize = 0, // no program header .e_phnum = 0, // no program header - .e_shentsize = @sizeOf(std.elf.Elf64_Shdr), + .e_shentsize = @sizeOf(std.elf.elf64.Shdr), .e_shnum = num_sections, .e_shstrndx = strtab_index, }; @@ -227,13 +227,13 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { // write symbols { // first symbol must be null - try w.writeStruct(std.mem.zeroes(std.elf.Elf64_Sym)); + try w.writeStruct(std.mem.zeroes(std.elf.elf64.Sym)); var sym_index: u16 = 1; var it = elf.local_symbols.iterator(); while (it.next()) |entry| { const sym = entry.value_ptr.*; - try w.writeStruct(std.elf.Elf64_Sym{ + try w.writeStruct(std.elf.elf64.Sym{ .st_name = name_offset, .st_info = sym.info, .st_other = 0, @@ -241,14 +241,14 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { .st_value = sym.offset, .st_size = sym.size, }); - sym.index = sym_index; + sym.index = @enumFromInt(sym_index); sym_index += 1; name_offset += @intCast(entry.key_ptr.len + 1); // +1 for null byte } it = elf.global_symbols.iterator(); while (it.next()) |entry| { const sym = entry.value_ptr.*; - try w.writeStruct(std.elf.Elf64_Sym{ + try w.writeStruct(std.elf.elf64.Sym{ .st_name = name_offset, .st_info = sym.info, .st_other = 0, @@ -256,7 +256,7 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { .st_value = sym.offset, .st_size = sym.size, }); - sym.index = sym_index; + sym.index = @enumFromInt(sym_index); sym_index += 1; name_offset += @intCast(entry.key_ptr.len + 1); // +1 for null byte } @@ -267,7 +267,7 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { var it = elf.sections.valueIterator(); while (it.next()) |sect| { for (sect.*.relocations.items) |rela| { - try w.writeStruct(std.elf.Elf64_Rela{ + try w.writeStruct(std.elf.elf64.Rela{ .r_offset = rela.offset, .r_addend = rela.addend, .r_info = (@as(u64, rela.symbol.index) << 32) | rela.type, @@ -295,13 +295,13 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { // pad to 16 bytes try w.writeByteNTimes(0, @intCast(sh_offset_aligned - sh_offset)); // mandatory null header - try w.writeStruct(std.mem.zeroes(std.elf.Elf64_Shdr)); + try w.writeStruct(std.mem.zeroes(std.elf.elf64.Shdr)); // write strtab section header { - const sect_header = std.elf.Elf64_Shdr{ + const sect_header = std.elf.elf64.Shdr{ .sh_name = strtab_name, - .sh_type = std.elf.SHT_STRTAB, + .sh_type = .STRTAB, .sh_flags = 0, .sh_addr = 0, .sh_offset = strtab_offset, @@ -316,9 +316,9 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { // write symtab section header { - const sect_header = std.elf.Elf64_Shdr{ + const sect_header = std.elf.elf64.Shdr{ .sh_name = symtab_name, - .sh_type = std.elf.SHT_SYMTAB, + .sh_type = .SYMTAB, .sh_flags = 0, .sh_addr = 0, .sh_offset = symtab_offset_aligned, @@ -326,21 +326,21 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { .sh_link = strtab_index, .sh_info = elf.local_symbols.size + 1, .sh_addralign = 8, - .sh_entsize = @sizeOf(std.elf.Elf64_Sym), + .sh_entsize = @sizeOf(std.elf.elf64.Sym), }; try w.writeStruct(sect_header); } // remaining section headers { - var sect_offset: u64 = @sizeOf(std.elf.Elf64_Ehdr); + var sect_offset: u64 = @sizeOf(std.elf.elf64.Ehdr); var rela_sect_offset: u64 = rela_offset; var it = elf.sections.iterator(); while (it.next()) |entry| { const sect = entry.value_ptr.*; const rela_count = sect.relocations.items.len; const rela_name_offset: u32 = if (rela_count != 0) @truncate(".rela".len) else 0; - try w.writeStruct(std.elf.Elf64_Shdr{ + try w.writeStruct(std.elf.elf64.Shdr{ .sh_name = rela_name_offset + name_offset, .sh_type = sect.type, .sh_flags = sect.flags, @@ -354,18 +354,18 @@ pub fn finish(elf: *Elf, file: std.fs.File) !void { }); if (rela_count != 0) { - const size = rela_count * @sizeOf(std.elf.Elf64_Rela); - try w.writeStruct(std.elf.Elf64_Shdr{ + const size = rela_count * @sizeOf(std.elf.elf64.Rela); + try w.writeStruct(std.elf.elf64.Shdr{ .sh_name = name_offset, - .sh_type = std.elf.SHT_RELA, + .sh_type = .RELA, .sh_flags = 0, .sh_addr = 0, .sh_offset = rela_sect_offset, - .sh_size = rela_count * @sizeOf(std.elf.Elf64_Rela), + .sh_size = size, .sh_link = symtab_index, - .sh_info = sect.index, + .sh_info = @intFromEnum(sect.index), .sh_addralign = 8, - .sh_entsize = @sizeOf(std.elf.Elf64_Rela), + .sh_entsize = @sizeOf(std.elf.elf64.Rela), }); rela_sect_offset += size; } diff --git a/lib/compiler/objcopy.zig b/lib/compiler/objcopy.zig index bf031bb39120..34a8e496a72b 100644 --- a/lib/compiler/objcopy.zig +++ b/lib/compiler/objcopy.zig @@ -827,26 +827,21 @@ fn stripElf( // TODO: support non-native endianess fn ElfFile(comptime is_64: bool) type { - const Elf_Ehdr = if (is_64) elf.Elf64_Ehdr else elf.Elf32_Ehdr; - const Elf_Phdr = if (is_64) elf.Elf64_Phdr else elf.Elf32_Phdr; - const Elf_Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr; - const Elf_Chdr = if (is_64) elf.Elf64_Chdr else elf.Elf32_Chdr; - const Elf_Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym; - const Elf_OffSize = if (is_64) elf.Elf64_Off else elf.Elf32_Off; + const elfn = if (is_64) elf.elf64 else elf.elf32; return struct { - raw_elf_header: Elf_Ehdr, - program_segments: []const Elf_Phdr, + raw_elf_header: elfn.Ehdr, + program_segments: []const elfn.Phdr, sections: []const Section, arena: std.heap.ArenaAllocator, const SectionCategory = ElfFileHelper.SectionCategory; - const section_memory_align = @alignOf(Elf_Sym); // most restrictive of what we may load in memory + const section_memory_align: std.mem.Alignment = .of(elfn.Sym); // most restrictive of what we may load in memory const Section = struct { - section: Elf_Shdr, + section: elfn.Shdr, name: []const u8 = "", - segment: ?*const Elf_Phdr = null, // if the section is used by a program segment (there can be more than one) - payload: ?[]align(section_memory_align) const u8 = null, // if we need the data in memory + segment: ?*const elfn.Phdr = null, // if the section is used by a program segment (there can be more than one) + payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, // if we need the data in memory category: SectionCategory = .none, // should the section be kept in the exe or stripped to the debug database, or both. }; @@ -857,36 +852,36 @@ fn ElfFile(comptime is_64: bool) type { errdefer arena.deinit(); const allocator = arena.allocator(); - var raw_header: Elf_Ehdr = undefined; + var raw_header: elfn.Ehdr = undefined; { const bytes_read = try in_file.preadAll(std.mem.asBytes(&raw_header), 0); - if (bytes_read < @sizeOf(Elf_Ehdr)) + if (bytes_read < @sizeOf(elfn.Ehdr)) return error.TRUNCATED_ELF; } // program header: list of segments const program_segments = blk: { - if (@sizeOf(Elf_Phdr) != header.phentsize) + if (@sizeOf(elfn.Phdr) != header.phentsize) fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize}); - const program_header = try allocator.alloc(Elf_Phdr, header.phnum); + const program_header = try allocator.alloc(elfn.Phdr, header.phnum); const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff); - if (bytes_read < @sizeOf(Elf_Phdr) * header.phnum) + if (bytes_read < @sizeOf(elfn.Phdr) * header.phnum) return error.TRUNCATED_ELF; break :blk program_header; }; // section header const sections = blk: { - if (@sizeOf(Elf_Shdr) != header.shentsize) + if (@sizeOf(elfn.Shdr) != header.shentsize) fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize}); const section_header = try allocator.alloc(Section, header.shnum); - const raw_section_header = try allocator.alloc(Elf_Shdr, header.shnum); + const raw_section_header = try allocator.alloc(elfn.Shdr, header.shnum); defer allocator.free(raw_section_header); const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(raw_section_header), header.shoff); - if (bytes_read < @sizeOf(Elf_Phdr) * header.shnum) + if (bytes_read < @sizeOf(elfn.Phdr) * header.shnum) return error.TRUNCATED_ELF; for (section_header, raw_section_header) |*section, hdr| { @@ -899,9 +894,10 @@ fn ElfFile(comptime is_64: bool) type { // string tables for access // sections than need modifications when other sections move. for (sections, 0..) |*section, idx| { + const VERSYM: elf.SHT = @enumFromInt(@intFromEnum(elf.elf32.DT.VERSYM)); const need_data = switch (section.section.sh_type) { - elf.DT_VERSYM => true, - elf.SHT_SYMTAB, elf.SHT_DYNSYM => true, + VERSYM => true, + .SYMTAB, .DYNSYM => true, else => false, }; const need_strings = (idx == header.shstrndx); @@ -999,8 +995,8 @@ fn ElfFile(comptime is_64: bool) type { remap_idx: u16, // optionally overrides the payload from the source file - payload: ?[]align(section_memory_align) const u8 = null, - section: ?Elf_Shdr = null, + payload: ?[]align(section_memory_align.toByteUnits()) const u8 = null, + section: ?elfn.Shdr = null, }; const sections_update = try allocator.alloc(Update, self.sections.len); const new_shnum = blk: { @@ -1008,7 +1004,7 @@ fn ElfFile(comptime is_64: bool) type { for (self.sections, sections_update) |section, *update| { const action = ElfFileHelper.selectAction(section.category, options.section_filter); const remap_idx = idx: { - if (action == .strip) break :idx elf.SHN_UNDEF; + if (action == .strip) break :idx 0; next_idx += 1; break :idx next_idx - 1; }; @@ -1027,8 +1023,8 @@ fn ElfFile(comptime is_64: bool) type { // add a ".gnu_debuglink" to the string table if needed const debuglink_name: u32 = blk: { - if (options.debuglink == null) break :blk elf.SHN_UNDEF; - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) + if (options.debuglink == null) break :blk 0; + if (self.raw_elf_header.e_shstrndx == 0) fatal("zig objcopy: no strtab, cannot add the debuglink section", .{}); // TODO add the section if needed? const strtab = &self.sections[self.raw_elf_header.e_shstrndx]; @@ -1076,8 +1072,8 @@ fn ElfFile(comptime is_64: bool) type { if (!std.mem.startsWith(u8, section.name, ".debug_")) continue; if ((section.section.sh_flags & elf.SHF_COMPRESSED) != 0) continue; // already compressed - const chdr = Elf_Chdr{ - .ch_type = elf.COMPRESS.ZLIB, + const chdr = elfn.Chdr{ + .ch_type = .ZLIB, .ch_size = section.section.sh_size, .ch_addralign = section.section.sh_addralign, }; @@ -1086,7 +1082,7 @@ fn ElfFile(comptime is_64: bool) type { if (compressed_payload) |payload| { update.payload = payload; update.section = section.section; - update.section.?.sh_addralign = @alignOf(Elf_Chdr); + update.section.?.sh_addralign = @alignOf(elfn.Chdr); update.section.?.sh_size = @intCast(payload.len); update.section.?.sh_flags |= elf.SHF_COMPRESSED; } @@ -1096,36 +1092,36 @@ fn ElfFile(comptime is_64: bool) type { var cmdbuf = std.ArrayList(ElfFileHelper.WriteCmd).init(allocator); defer cmdbuf.deinit(); try cmdbuf.ensureUnusedCapacity(3 + new_shnum); - var eof_offset: Elf_OffSize = 0; // track the end of the data written so far. + var eof_offset: elf.native.Off = 0; // track the end of the data written so far. // build the updated headers // nb: updated_elf_header will be updated before the actual write var updated_elf_header = self.raw_elf_header; - if (updated_elf_header.e_shstrndx != elf.SHN_UNDEF) + if (updated_elf_header.e_shstrndx != 0) updated_elf_header.e_shstrndx = sections_update[updated_elf_header.e_shstrndx].remap_idx; cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = std.mem.asBytes(&updated_elf_header), .out_offset = 0 } }); - eof_offset = @sizeOf(Elf_Ehdr); + eof_offset = @sizeOf(elfn.Ehdr); // program header as-is. // nb: for only-debug files, removing it appears to work, but is invalid by ELF specifcation. { - assert(updated_elf_header.e_phoff == @sizeOf(Elf_Ehdr)); + assert(updated_elf_header.e_phoff == @sizeOf(elfn.Ehdr)); const data = std.mem.sliceAsBytes(self.program_segments); assert(data.len == @as(usize, updated_elf_header.e_phentsize) * updated_elf_header.e_phnum); cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = data, .out_offset = updated_elf_header.e_phoff } }); - eof_offset = updated_elf_header.e_phoff + @as(Elf_OffSize, @intCast(data.len)); + eof_offset = updated_elf_header.e_phoff + @as(elfn.Off, @intCast(data.len)); } // update sections and queue payload writes const updated_section_header = blk: { - const dest_sections = try allocator.alloc(Elf_Shdr, new_shnum); + const dest_sections = try allocator.alloc(elfn.Shdr, new_shnum); { // the ELF format doesn't specify the order for all sections. // this code only supports when they are in increasing file order. var offset: u64 = eof_offset; for (self.sections[1..]) |section| { - if (section.section.sh_type == elf.SHT_NOBITS) + if (section.section.sh_type == .NOBITS) continue; if (section.section.sh_offset < offset) { fatal("zig objcopy: unsupported ELF file", .{}); @@ -1148,17 +1144,17 @@ fn ElfFile(comptime is_64: bool) type { dest.* = src.*; - if (src.sh_link != elf.SHN_UNDEF) + if (src.sh_link != 0) dest.sh_link = sections_update[src.sh_link].remap_idx; - if ((src.sh_flags & elf.SHF_INFO_LINK) != 0 and src.sh_info != elf.SHN_UNDEF) + if ((src.sh_flags & elf.SHF_INFO_LINK) != 0 and src.sh_info != 0) dest.sh_info = sections_update[src.sh_info].remap_idx; if (payload) |data| dest.sh_size = @intCast(data.len); - const addralign = if (src.sh_addralign == 0 or dest.sh_type == elf.SHT_NOBITS) 1 else src.sh_addralign; - dest.sh_offset = std.mem.alignForward(Elf_OffSize, eof_offset, addralign); - if (src.sh_offset != dest.sh_offset and section.segment != null and update.action != .empty and dest.sh_type != elf.SHT_NOTE and dest.sh_type != elf.SHT_NOBITS) { + const addralign = if (src.sh_addralign == 0 or dest.sh_type == .NOBITS) 1 else src.sh_addralign; + dest.sh_offset = std.mem.alignForward(elfn.Off, eof_offset, addralign); + if (src.sh_offset != dest.sh_offset and section.segment != null and update.action != .empty and dest.sh_type != .NOTE and dest.sh_type != .NOBITS) { if (src.sh_offset > dest.sh_offset) { dest.sh_offset = src.sh_offset; // add padding to avoid modifing the program segments } else { @@ -1168,13 +1164,13 @@ fn ElfFile(comptime is_64: bool) type { assert(dest.sh_addr % addralign == dest.sh_offset % addralign); if (update.action == .empty) - dest.sh_type = elf.SHT_NOBITS; + dest.sh_type = .NOBITS; - if (dest.sh_type != elf.SHT_NOBITS) { + if (dest.sh_type != .NOBITS) { if (payload) |src_data| { // update sections payload and write const dest_data = switch (src.sh_type) { - elf.DT_VERSYM => dst_data: { + .VERSYM => dst_data: { const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); @memcpy(data, src_data); @@ -1186,13 +1182,13 @@ fn ElfFile(comptime is_64: bool) type { break :dst_data data; }, - elf.SHT_SYMTAB, elf.SHT_DYNSYM => dst_data: { + .SYMTAB, .DYNSYM => dst_data: { const data = try allocator.alignedAlloc(u8, section_memory_align, src_data.len); @memcpy(data, src_data); - const syms = @as([*]Elf_Sym, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(Elf_Sym)]; + const syms = @as([*]elfn.Sym, @ptrCast(data))[0 .. @as(usize, @intCast(src.sh_size)) / @sizeOf(elfn.Sym)]; for (syms) |*sym| { - if (sym.st_shndx != elf.SHN_UNDEF and sym.st_shndx < elf.SHN_LORESERVE) + if (sym.st_shndx != .UNDEF and sym.st_shndx.getReserve() == null) sym.st_shndx = sections_update[sym.st_shndx].remap_idx; } @@ -1226,22 +1222,22 @@ fn ElfFile(comptime is_64: bool) type { break :payload buf; }; - dest_sections[dest_section_idx] = Elf_Shdr{ + dest_sections[dest_section_idx] = elfn.Shdr{ .sh_name = debuglink_name, - .sh_type = elf.SHT_PROGBITS, + .sh_type = .PROGBITS, .sh_flags = 0, .sh_addr = 0, .sh_offset = eof_offset, .sh_size = @intCast(payload.len), - .sh_link = elf.SHN_UNDEF, - .sh_info = elf.SHN_UNDEF, + .sh_link = 0, + .sh_info = 0, .sh_addralign = 4, .sh_entsize = 0, }; dest_section_idx += 1; cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); - eof_offset += @as(Elf_OffSize, @intCast(payload.len)); + eof_offset += @as(elfn.Off, @intCast(payload.len)); } // --add-section @@ -1252,22 +1248,22 @@ fn ElfFile(comptime is_64: bool) type { const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize)); - dest_sections[dest_section_idx] = Elf_Shdr{ + dest_sections[dest_section_idx] = elfn.Shdr{ .sh_name = user_section_name, - .sh_type = elf.SHT_PROGBITS, + .sh_type = .PROGBITS, .sh_flags = 0, .sh_addr = 0, .sh_offset = eof_offset, .sh_size = @intCast(payload.len), - .sh_link = elf.SHN_UNDEF, - .sh_info = elf.SHN_UNDEF, + .sh_link = 0, + .sh_info = 0, .sh_addralign = 4, .sh_entsize = 0, }; dest_section_idx += 1; cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } }); - eof_offset += @as(Elf_OffSize, @intCast(payload.len)); + eof_offset += @as(elfn.Off, @intCast(payload.len)); } assert(dest_section_idx == new_shnum); @@ -1276,7 +1272,7 @@ fn ElfFile(comptime is_64: bool) type { // --set-section-alignment: overwrite alignment if (options.set_section_alignment) |set_align| { - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) + if (self.raw_elf_header.e_shstrndx == 0) fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? const strtab = §ions_update[self.raw_elf_header.e_shstrndx]; @@ -1291,7 +1287,7 @@ fn ElfFile(comptime is_64: bool) type { // --set-section-flags: overwrite flags if (options.set_section_flags) |set_flags| { - if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF) + if (self.raw_elf_header.e_shstrndx == 0) fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed? const strtab = §ions_update[self.raw_elf_header.e_shstrndx]; @@ -1340,7 +1336,7 @@ fn ElfFile(comptime is_64: bool) type { // write the section header at the tail { - const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr)); + const offset = std.mem.alignForward(elfn.Off, eof_offset, @alignOf(elfn.Shdr)); const data = std.mem.sliceAsBytes(updated_section_header); assert(data.len == @as(usize, updated_elf_header.e_shentsize) * new_shnum); @@ -1353,7 +1349,7 @@ fn ElfFile(comptime is_64: bool) type { try ElfFileHelper.write(allocator, out_file, in_file, cmdbuf.items); } - fn sectionWithinSegment(section: Elf_Shdr, segment: Elf_Phdr) bool { + fn sectionWithinSegment(section: elfn.Shdr, segment: elfn.Phdr) bool { const file_size = if (section.sh_type == elf.SHT_NOBITS) 0 else section.sh_size; return segment.p_offset <= section.sh_offset and (segment.p_offset + segment.p_filesz) >= (section.sh_offset + file_size); } diff --git a/lib/std/Build/Step/CheckObject.zig b/lib/std/Build/Step/CheckObject.zig index 289a4ff4f8b4..64b6ccc904a9 100644 --- a/lib/std/Build/Step/CheckObject.zig +++ b/lib/std/Build/Step/CheckObject.zig @@ -1910,13 +1910,13 @@ const ElfDumper = struct { var stream = std.io.fixedBufferStream(bytes); const reader = stream.reader(); - const hdr = try reader.readStruct(elf.Elf64_Ehdr); + const hdr = try reader.readStruct(elf.elf64.Ehdr); if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) { return error.InvalidMagicNumber; } - const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(bytes.ptr + hdr.e_shoff))[0..hdr.e_shnum]; - const phdrs = @as([*]align(1) const elf.Elf64_Phdr, @ptrCast(bytes.ptr + hdr.e_phoff))[0..hdr.e_phnum]; + const shdrs = @as([*]align(1) const elf.elf64.Shdr, @ptrCast(bytes.ptr + hdr.e_shoff))[0..hdr.e_shnum]; + const phdrs = @as([*]align(1) const elf.elf64.Phdr, @ptrCast(bytes.ptr + hdr.e_phoff))[0..hdr.e_phnum]; var ctx = ObjectContext{ .gpa = gpa, @@ -1931,8 +1931,8 @@ const ElfDumper = struct { for (ctx.shdrs, 0..) |shdr, i| switch (shdr.sh_type) { elf.SHT_SYMTAB, elf.SHT_DYNSYM => { const raw = ctx.getSectionContents(i); - const nsyms = @divExact(raw.len, @sizeOf(elf.Elf64_Sym)); - const symbols = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw.ptr))[0..nsyms]; + const nsyms = @divExact(raw.len, @sizeOf(elf.elf64.Sym)); + const symbols = @as([*]align(1) const elf.elf64.Sym, @ptrCast(raw.ptr))[0..nsyms]; const strings = ctx.getSectionContents(shdr.sh_link); switch (shdr.sh_type) { @@ -1992,9 +1992,9 @@ const ElfDumper = struct { const ObjectContext = struct { gpa: Allocator, data: []const u8, - hdr: elf.Elf64_Ehdr, - shdrs: []align(1) const elf.Elf64_Shdr, - phdrs: []align(1) const elf.Elf64_Phdr, + hdr: elf.elf64.Ehdr, + shdrs: []align(1) const elf.elf64.Shdr, + phdrs: []align(1) const elf.elf64.Phdr, shstrtab: []const u8, symtab: Symtab = .{}, dysymtab: Symtab = .{}, @@ -2065,96 +2065,91 @@ const ElfDumper = struct { const shdr = ctx.shdrs[shndx]; const strtab = ctx.getSectionContents(shdr.sh_link); const data = ctx.getSectionContents(shndx); - const nentries = @divExact(data.len, @sizeOf(elf.Elf64_Dyn)); - const entries = @as([*]align(1) const elf.Elf64_Dyn, @ptrCast(data.ptr))[0..nentries]; + const nentries = @divExact(data.len, @sizeOf(elf.elf64.Dyn)); + const entries = @as([*]align(1) const elf.elf64.Dyn, @ptrCast(data.ptr))[0..nentries]; try writer.writeAll(ElfDumper.dynamic_section_label ++ "\n"); for (entries) |entry| { - const key = @as(u64, @bitCast(entry.d_tag)); const value = entry.d_val; - const key_str = switch (key) { - elf.DT_NEEDED => "NEEDED", - elf.DT_SONAME => "SONAME", - elf.DT_INIT_ARRAY => "INIT_ARRAY", - elf.DT_INIT_ARRAYSZ => "INIT_ARRAYSZ", - elf.DT_FINI_ARRAY => "FINI_ARRAY", - elf.DT_FINI_ARRAYSZ => "FINI_ARRAYSZ", - elf.DT_HASH => "HASH", - elf.DT_GNU_HASH => "GNU_HASH", - elf.DT_STRTAB => "STRTAB", - elf.DT_SYMTAB => "SYMTAB", - elf.DT_STRSZ => "STRSZ", - elf.DT_SYMENT => "SYMENT", - elf.DT_PLTGOT => "PLTGOT", - elf.DT_PLTRELSZ => "PLTRELSZ", - elf.DT_PLTREL => "PLTREL", - elf.DT_JMPREL => "JMPREL", - elf.DT_RELA => "RELA", - elf.DT_RELASZ => "RELASZ", - elf.DT_RELAENT => "RELAENT", - elf.DT_VERDEF => "VERDEF", - elf.DT_VERDEFNUM => "VERDEFNUM", - elf.DT_FLAGS => "FLAGS", - elf.DT_FLAGS_1 => "FLAGS_1", - elf.DT_VERNEED => "VERNEED", - elf.DT_VERNEEDNUM => "VERNEEDNUM", - elf.DT_VERSYM => "VERSYM", - elf.DT_RELACOUNT => "RELACOUNT", - elf.DT_RPATH => "RPATH", - elf.DT_RUNPATH => "RUNPATH", - elf.DT_INIT => "INIT", - elf.DT_FINI => "FINI", - elf.DT_NULL => "NULL", + const key_str = switch (entry.d_tag) { + .NEEDED => "NEEDED", + .SONAME => "SONAME", + .INIT_ARRAY => "INIT_ARRAY", + .INIT_ARRAYSZ => "INIT_ARRAYSZ", + .FINI_ARRAY => "FINI_ARRAY", + .FINI_ARRAYSZ => "FINI_ARRAYSZ", + .HASH => "HASH", + .GNU_HASH => "GNU_HASH", + .STRTAB => "STRTAB", + .SYMTAB => "SYMTAB", + .STRSZ => "STRSZ", + .SYMENT => "SYMENT", + .PLTGOT => "PLTGOT", + .PLTRELSZ => "PLTRELSZ", + .PLTREL => "PLTREL", + .JMPREL => "JMPREL", + .RELA => "RELA", + .RELASZ => "RELASZ", + .RELAENT => "RELAENT", + .VERDEF => "VERDEF", + .VERDEFNUM => "VERDEFNUM", + .FLAGS => "FLAGS", + .FLAGS_1 => "FLAGS_1", + .VERNEED => "VERNEED", + .VERNEEDNUM => "VERNEEDNUM", + .VERSYM => "VERSYM", + .RELACOUNT => "RELACOUNT", + .RPATH => "RPATH", + .RUNPATH => "RUNPATH", + .INIT => "INIT", + .FINI => "FINI", + .NULL => "NULL", else => "UNKNOWN", }; try writer.print("{s}", .{key_str}); - switch (key) { - elf.DT_NEEDED, - elf.DT_SONAME, - elf.DT_RPATH, - elf.DT_RUNPATH, - => { + switch (entry.d_tag) { + .NEEDED, .SONAME, .RPATH, .RUNPATH => { const name = getString(strtab, @intCast(value)); try writer.print(" {s}", .{name}); }, - elf.DT_INIT_ARRAY, - elf.DT_FINI_ARRAY, - elf.DT_HASH, - elf.DT_GNU_HASH, - elf.DT_STRTAB, - elf.DT_SYMTAB, - elf.DT_PLTGOT, - elf.DT_JMPREL, - elf.DT_RELA, - elf.DT_VERDEF, - elf.DT_VERNEED, - elf.DT_VERSYM, - elf.DT_INIT, - elf.DT_FINI, - elf.DT_NULL, + .INIT_ARRAY, + .FINI_ARRAY, + .HASH, + .GNU_HASH, + .STRTAB, + .SYMTAB, + .PLTGOT, + .JMPREL, + .RELA, + .VERDEF, + .VERNEED, + .VERSYM, + .INIT, + .FINI, + .NULL, => try writer.print(" {x}", .{value}), - elf.DT_INIT_ARRAYSZ, - elf.DT_FINI_ARRAYSZ, - elf.DT_STRSZ, - elf.DT_SYMENT, - elf.DT_PLTRELSZ, - elf.DT_RELASZ, - elf.DT_RELAENT, - elf.DT_RELACOUNT, + .INIT_ARRAYSZ, + .FINI_ARRAYSZ, + .STRSZ, + .SYMENT, + .PLTRELSZ, + .RELASZ, + .RELAENT, + .RELACOUNT, => try writer.print(" {d}", .{value}), - elf.DT_PLTREL => try writer.writeAll(switch (value) { - elf.DT_REL => " REL", - elf.DT_RELA => " RELA", + .PLTREL => try writer.writeAll(switch (value) { + @intFromEnum(elf.elf64.DT.REL) => " REL", + @intFromEnum(elf.elf64.DT.RELA) => " RELA", else => " UNKNOWN", }), - elf.DT_FLAGS => if (value > 0) { + .FLAGS => if (value > 0) { if (value & elf.DF_ORIGIN != 0) try writer.writeAll(" ORIGIN"); if (value & elf.DF_SYMBOLIC != 0) try writer.writeAll(" SYMBOLIC"); if (value & elf.DF_TEXTREL != 0) try writer.writeAll(" TEXTREL"); @@ -2162,7 +2157,7 @@ const ElfDumper = struct { if (value & elf.DF_STATIC_TLS != 0) try writer.writeAll(" STATIC_TLS"); }, - elf.DT_FLAGS_1 => if (value > 0) { + .FLAGS_1 => if (value > 0) { if (value & elf.DF_1_NOW != 0) try writer.writeAll(" NOW"); if (value & elf.DF_1_GLOBAL != 0) try writer.writeAll(" GLOBAL"); if (value & elf.DF_1_GROUP != 0) try writer.writeAll(" GROUP"); @@ -2306,10 +2301,10 @@ const ElfDumper = struct { }; const Symtab = struct { - symbols: []align(1) const elf.Elf64_Sym = &[0]elf.Elf64_Sym{}, + symbols: []align(1) const elf.elf64.Sym = &[0]elf.elf64.Sym{}, strings: []const u8 = &[0]u8{}, - fn get(st: Symtab, index: usize) ?elf.Elf64_Sym { + fn get(st: Symtab, index: usize) ?elf.elf64.Sym { if (index >= st.symbols.len) return null; return st.symbols[index]; } diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 4b1faa87baa5..0cdf7ae4af1b 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -85,11 +85,11 @@ const RDebug = extern struct { /// TODO make it possible to reference this same external symbol 2x so we don't need this /// helper function. -pub fn get_DYNAMIC() ?[*]elf.Dyn { - return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak }); +pub fn get_DYNAMIC() ?[*]elf.native.Dyn { + return @extern([*]elf.native.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak }); } -pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator { +pub fn linkmap_iterator(phdrs: []elf.native.Phdr) error{InvalidExe}!LinkMap.Iterator { _ = phdrs; const _DYNAMIC = get_DYNAMIC() orelse { // No PT_DYNAMIC means this is either a statically-linked program or a @@ -99,16 +99,16 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator { const link_map_ptr = init: { var i: usize = 0; - while (_DYNAMIC[i].d_tag != elf.DT_NULL) : (i += 1) { + while (_DYNAMIC[i].d_tag != .NULL) : (i += 1) { switch (_DYNAMIC[i].d_tag) { - elf.DT_DEBUG => { + .DEBUG => { const ptr = @as(?*RDebug, @ptrFromInt(_DYNAMIC[i].d_val)); if (ptr) |r_debug| { if (r_debug.r_version != 1) return error.InvalidExe; break :init r_debug.r_map; } }, - elf.DT_PLTGOT => { + .PLTGOT => { const ptr = @as(?[*]usize, @ptrFromInt(_DYNAMIC[i].d_val)); if (ptr) |got_table| { // The address to the link_map structure is stored in @@ -255,10 +255,10 @@ pub const ElfDynLib = struct { i += 1; ph_addr += eh.e_phentsize; }) { - const ph = @as(*elf.Phdr, @ptrFromInt(ph_addr)); + const ph = @as(*elf.native.Phdr, @ptrFromInt(ph_addr)); switch (ph.p_type) { - elf.PT_LOAD => virt_addr_end = @max(virt_addr_end, ph.p_vaddr + ph.p_memsz), - elf.PT_DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(elf_addr + ph.p_offset)), + .LOAD => virt_addr_end = @max(virt_addr_end, ph.p_vaddr + ph.p_memsz), + .DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(elf_addr + ph.p_offset)), else => {}, } } @@ -286,9 +286,9 @@ pub const ElfDynLib = struct { i += 1; ph_addr += eh.e_phentsize; }) { - const ph = @as(*elf.Phdr, @ptrFromInt(ph_addr)); + const ph = @as(*elf.native.Phdr, @ptrFromInt(ph_addr)); switch (ph.p_type) { - elf.PT_LOAD => { + .LOAD => { // The VirtAddr may not be page-aligned; in such case there will be // extra nonsense mapped before/after the VirtAddr,MemSiz const aligned_addr = (base + ph.p_vaddr) & ~(@as(usize, page_size) - 1); @@ -296,7 +296,7 @@ pub const ElfDynLib = struct { const extended_memsz = mem.alignForward(usize, ph.p_memsz + extra_bytes, page_size); const ptr = @as([*]align(std.heap.page_size_min) u8, @ptrFromInt(aligned_addr)); const prot = elfToMmapProt(ph.p_flags); - if ((ph.p_flags & elf.PF_W) == 0) { + if (!ph.p_flags.write) { // If it does not need write access, it can be mapped from the fd. _ = try posix.mmap( ptr, @@ -334,13 +334,14 @@ pub const ElfDynLib = struct { var i: usize = 0; while (dynv[i] != 0) : (i += 2) { const p = base + dynv[i + 1]; - switch (dynv[i]) { - elf.DT_STRTAB => maybe_strings = @ptrFromInt(p), - elf.DT_SYMTAB => maybe_syms = @ptrFromInt(p), - elf.DT_HASH => maybe_hashtab = @ptrFromInt(p), - elf.DT_GNU_HASH => maybe_gnu_hash = @ptrFromInt(p), - elf.DT_VERSYM => maybe_versym = @ptrFromInt(p), - elf.DT_VERDEF => maybe_verdef = @ptrFromInt(p), + const d_tag: elf.native.DT = @enumFromInt(dynv[i]); + switch (d_tag) { + .STRTAB => maybe_strings = @ptrFromInt(p), + .SYMTAB => maybe_syms = @ptrFromInt(p), + .HASH => maybe_hashtab = @ptrFromInt(p), + .GNU_HASH => maybe_gnu_hash = @ptrFromInt(p), + .VERSYM => maybe_versym = @ptrFromInt(p), + .VERDEF => maybe_verdef = @ptrFromInt(p), else => {}, } } @@ -535,7 +536,7 @@ pub const ElfDynLib = struct { fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, strings: [*:0]u8) bool { var def = def_arg; - const vsym_index = vsym_arg.VERSION; + const vsym_index = vsym_arg.version; while (true) { if (0 == (def.flags & elf.VER_FLG_BASE) and @intFromEnum(def.ndx) == vsym_index) break; if (def.next == 0) return false; diff --git a/lib/std/elf.zig b/lib/std/elf.zig index 8e20f9810896..417c9f5d91ce 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -137,6 +137,35 @@ pub const PT = enum(Word) { /// Stack segment pub const SUNWSTACK = os(0xffffffb); pub const HISUNW = os(0xfffffff); + + pub fn format( + p_type: PT, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + const name = switch (p_type) { + .NULL, .LOAD, .DYNAMIC, .INTERP, .NOTE, .SHLIB, .PHDR, .TLS => @tagName(p_type), + + GNU_EH_FRAME => "GNU_EH_FRAME", + GNU_STACK => "GNU_STACK", + GNU_RELRO => "GNU_RELRO", + SUNWBSS => "SUNWBSS", + SUNWSTACK => "SUNWSTACK", + + else => name: { + if (p_type.getOs()) |osval| + try writer.print("OS(0x{X})", .{osval}) + else if (p_type.getProc()) |procval| + try writer.print("PROC(0x{X})", .{procval}) + else + break :name "UNKNOWN"; + return; + }, + }; + + try writer.writeAll(name); + } }; pub const SHT = enum(Word) { @@ -2219,6 +2248,19 @@ pub const PF = packed struct(Word) { os: u8 = 0, /// Bits for processor-specific semantics. proc: u4 = 0, + + pub fn format( + p_flags: PF, + comptime _: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, + ) !void { + try writer.writeAll(if (p_flags.read) "R" else "-"); + try writer.writeAll(if (p_flags.write) "W" else "-"); + try writer.writeAll(if (p_flags.execute) "X" else "-"); + if (p_flags.os != 0) try writer.print(" OS({x})", .{p_flags.os}); + if (p_flags.proc != 0) try writer.print(" PROC({x})", .{p_flags.proc}); + } }; pub const SHN = enum(Section) { diff --git a/src/link.zig b/src/link.zig index f436106aabae..fcb9676e8984 100644 --- a/src/link.zig +++ b/src/link.zig @@ -2301,7 +2301,7 @@ fn resolvePathInputLib( }), }; errdefer file.close(); - try ld_script_bytes.resize(gpa, @sizeOf(std.elf.Elf64_Ehdr)); + try ld_script_bytes.resize(gpa, @sizeOf(std.elf.elf64.Ehdr)); const n = file.preadAll(ld_script_bytes.items, 0) catch |err| fatal("failed to read '{'}': {s}", .{ test_path, @errorName(err), }); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a338ec722d0a..c4a813408eb4 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -66,7 +66,7 @@ default_sym_version: elf.Versym, /// .shstrtab buffer shstrtab: std.ArrayListUnmanaged(u8) = .empty, /// .symtab buffer -symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty, +symtab: std.ArrayListUnmanaged(elf.elf64.Sym) = .empty, /// .strtab buffer strtab: std.ArrayListUnmanaged(u8) = .empty, /// Dynamic symbol table. Only populated and emitted when linking dynamically. @@ -80,7 +80,7 @@ verneed: VerneedSection = .{}, /// .got section got: GotSection = .{}, /// .rela.dyn section -rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .empty, +rela_dyn: std.ArrayListUnmanaged(elf.elf64.Rela) = .empty, /// .dynamic section dynamic: DynamicSection = .{}, /// .hash section @@ -96,7 +96,7 @@ plt_got: PltGotSection = .{}, /// .copyrel section copy_rel: CopyRelSection = .{}, /// .rela.plt section -rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .empty, +rela_plt: std.ArrayListUnmanaged(elf.elf64.Rela) = .empty, /// SHT_GROUP sections /// Applies only to a relocatable. comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .empty, @@ -142,7 +142,7 @@ const SectionIndexes = struct { symtab: ?u32 = null, }; -const ProgramHeaderList = std.ArrayListUnmanaged(elf.Elf64_Phdr); +const ProgramHeaderList = std.ArrayListUnmanaged(elf.elf64.Phdr); const OptionalProgramHeaderIndex = enum(u16) { none = std.math.maxInt(u16), @@ -384,25 +384,20 @@ pub fn createEmpty( if (!is_obj_or_ar) { try self.dynstrtab.append(gpa, 0); + const native_elf = switch (self.ptr_width) { + .p32 => elf.elf32, + .p64 => elf.elf64, + }; // Initialize PT_PHDR program header - const p_align: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Phdr), - .p64 => @alignOf(elf.Elf64_Phdr), - }; - const ehsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Ehdr), - .p64 => @sizeOf(elf.Elf64_Ehdr), - }; - const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), - }; + const p_align: u16 = @alignOf(native_elf.Phdr); + const ehsize: u64 = @sizeOf(native_elf.Ehdr); + const phsize: u64 = @sizeOf(native_elf.Phdr); const max_nphdrs = comptime getMaxNumberOfPhdrs(); const reserved: u64 = mem.alignForward(u64, padToIdeal(max_nphdrs * phsize), self.page_size); self.phdr_indexes.table = (try self.addPhdr(.{ - .type = elf.PT_PHDR, - .flags = elf.PF_R, + .type = .PHDR, + .flags = .{ .read = true }, .@"align" = p_align, .addr = self.image_base + ehsize, .offset = ehsize, @@ -410,8 +405,8 @@ pub fn createEmpty( .memsz = reserved, })).toOptional(); self.phdr_indexes.table_load = (try self.addPhdr(.{ - .type = elf.PT_LOAD, - .flags = elf.PF_R, + .type = .LOAD, + .flags = .{ .read = true }, .@"align" = self.page_size, .addr = self.image_base, .offset = 0, @@ -537,7 +532,7 @@ pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.Relo /// Returns end pos of collision, if any. fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { const small_ptr = self.ptr_width == .p32; - const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr); + const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.elf32.Ehdr) else @sizeOf(elf.elf64.Ehdr); if (start < ehdr_size) return ehdr_size; @@ -545,7 +540,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { const end = start + padToIdeal(size); if (self.shdr_table_offset) |off| { - const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr); + const shdr_size: u64 = if (small_ptr) @sizeOf(elf.elf32.Shdr) else @sizeOf(elf.elf64.Shdr); const tight_size = self.sections.items(.shdr).len * shdr_size; const increased_size = padToIdeal(tight_size); const test_end = off +| increased_size; @@ -556,7 +551,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { } for (self.sections.items(.shdr)) |shdr| { - if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (shdr.sh_type == .NOBITS) continue; const increased_size = padToIdeal(shdr.sh_size); const test_end = shdr.sh_offset +| increased_size; if (start < test_end) { @@ -566,7 +561,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) !?u64 { } for (self.phdrs.items) |phdr| { - if (phdr.p_type != elf.PT_LOAD) continue; + if (phdr.p_type != .LOAD) continue; const increased_size = padToIdeal(phdr.p_filesz); const test_end = phdr.p_offset +| increased_size; if (start < test_end) { @@ -607,7 +602,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 { pub fn growSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void { const shdr = &self.sections.items(.shdr)[shdr_index]; - if (shdr.sh_type != elf.SHT_NOBITS) { + if (shdr.sh_type != .NOBITS) { const allocated_size = self.allocatedSize(shdr.sh_offset); log.debug("allocated size {x} of '{s}', needed size {x}", .{ allocated_size, @@ -965,7 +960,7 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { if (!atom_ptr.alive) continue; const out_shndx = atom_ptr.output_section_index; const shdr = &self.sections.items(.shdr)[out_shndx]; - if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (shdr.sh_type == .NOBITS) continue; const code = try zo.codeAlloc(self, atom_index); defer gpa.free(code); const file_offset = atom_ptr.offset(self); @@ -1449,7 +1444,7 @@ fn scanRelocs(self: *Elf) !void { pub fn initOutputSection(self: *Elf, args: struct { name: [:0]const u8, flags: u64, - type: u32, + type: elf.SHT, }) error{OutOfMemory}!u32 { const name = blk: { if (self.base.isRelocatable()) break :blk args.name; @@ -1466,16 +1461,16 @@ pub fn initOutputSection(self: *Elf, args: struct { } break :blk args.name; }; - const @"type" = tt: { - if (self.getTarget().cpu.arch == .x86_64 and args.type == elf.SHT_X86_64_UNWIND) - break :tt elf.SHT_PROGBITS; + const @"type": elf.SHT = tt: { + if (self.getTarget().cpu.arch == .x86_64 and args.type == .X86_64_UNWIND) + break :tt .PROGBITS; switch (args.type) { - elf.SHT_NULL => unreachable, - elf.SHT_PROGBITS => { + .NULL => unreachable, + .PROGBITS => { if (mem.eql(u8, args.name, ".init_array") or mem.startsWith(u8, args.name, ".init_array.")) - break :tt elf.SHT_INIT_ARRAY; + break :tt .INIT_ARRAY; if (mem.eql(u8, args.name, ".fini_array") or mem.startsWith(u8, args.name, ".fini_array.")) - break :tt elf.SHT_FINI_ARRAY; + break :tt .FINI_ARRAY; break :tt args.type; }, else => break :tt args.type, @@ -1487,7 +1482,7 @@ pub fn initOutputSection(self: *Elf, args: struct { flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); } break :blk switch (@"type") { - elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, + .INIT_ARRAY, .FINI_ARRAY => flags | elf.SHF_WRITE, else => flags, }; }; @@ -2110,14 +2105,12 @@ pub fn writeShdrTable(self: *Elf) !void { const gpa = self.base.comp.gpa; const target_endian = self.getTarget().cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian(); - const shsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Shdr), - .p64 => @sizeOf(elf.Elf64_Shdr), - }; - const shalign: u16 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Shdr), - .p64 => @alignOf(elf.Elf64_Shdr), + const Shdr = switch (self.ptr_width) { + .p32 => elf.Elf32_Shdr, + .p64 => elf.Elf64_Shdr, }; + const shsize: u64 = @sizeOf(Shdr); + const shalign: u16 = @alignOf(Shdr); const shoff = self.shdr_table_offset orelse 0; const needed_size = self.sections.items(.shdr).len * shsize; @@ -2134,27 +2127,27 @@ pub fn writeShdrTable(self: *Elf) !void { switch (self.ptr_width) { .p32 => { - const buf = try gpa.alloc(elf.Elf32_Shdr, self.sections.items(.shdr).len); + const buf = try gpa.alloc(elf.elf32.Shdr, self.sections.items(.shdr).len); defer gpa.free(buf); for (buf, 0..) |*shdr, i| { assert(self.sections.items(.shdr)[i].sh_offset != math.maxInt(u64)); shdr.* = shdrTo32(self.sections.items(.shdr)[i]); if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf32_Shdr, shdr); + mem.byteSwapAllFields(elf.elf32.Shdr, shdr); } } try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); }, .p64 => { - const buf = try gpa.alloc(elf.Elf64_Shdr, self.sections.items(.shdr).len); + const buf = try gpa.alloc(elf.elf64.Shdr, self.sections.items(.shdr).len); defer gpa.free(buf); for (buf, 0..) |*shdr, i| { assert(self.sections.items(.shdr)[i].sh_offset != math.maxInt(u64)); shdr.* = self.sections.items(.shdr)[i]; if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf64_Shdr, shdr); + mem.byteSwapAllFields(elf.elf64.Shdr, shdr); } } try self.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?); @@ -2175,25 +2168,25 @@ fn writePhdrTable(self: *Elf) !void { switch (self.ptr_width) { .p32 => { - const buf = try gpa.alloc(elf.Elf32_Phdr, self.phdrs.items.len); + const buf = try gpa.alloc(elf.elf32.Phdr, self.phdrs.items.len); defer gpa.free(buf); for (buf, 0..) |*phdr, i| { phdr.* = phdrTo32(self.phdrs.items[i]); if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf32_Phdr, phdr); + mem.byteSwapAllFields(elf.elf32.Phdr, phdr); } } try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset); }, .p64 => { - const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len); + const buf = try gpa.alloc(elf.elf64.Phdr, self.phdrs.items.len); defer gpa.free(buf); for (buf, 0..) |*phdr, i| { phdr.* = self.phdrs.items[i]; if (foreign_endian) { - mem.byteSwapAllFields(elf.Elf64_Phdr, phdr); + mem.byteSwapAllFields(elf.elf64.Phdr, phdr); } } try self.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset); @@ -2201,152 +2194,79 @@ fn writePhdrTable(self: *Elf) !void { } } -pub fn writeElfHeader(self: *Elf) !void { +fn writeElfHeaderImpl(self: *Elf, comptime is_64: bool) !void { + const native_elf = if (is_64) elf.elf64 else elf.elf32; + const diags = &self.base.comp.link_diags; if (diags.hasErrors()) return; // We had errors, so skip flushing to render the output unusable const comp = self.base.comp; - var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined; - - var index: usize = 0; - hdr_buf[0..4].* = elf.MAGIC.*; - index += 4; - - hdr_buf[index] = switch (self.ptr_width) { - .p32 => elf.ELFCLASS32, - .p64 => elf.ELFCLASS64, - }; - index += 1; - const target = self.getTarget(); - const endian = target.cpu.arch.endian(); - hdr_buf[index] = switch (endian) { - .little => elf.ELFDATA2LSB, - .big => elf.ELFDATA2MSB, - }; - index += 1; - - hdr_buf[index] = 1; // ELF version - index += 1; - - hdr_buf[index] = @intFromEnum(@as(elf.OSABI, switch (target.cpu.arch) { - .amdgcn => switch (target.os.tag) { - .amdhsa => .AMDGPU_HSA, - .amdpal => .AMDGPU_PAL, - .mesa3d => .AMDGPU_MESA3D, - else => .NONE, - }, - .msp430 => .STANDALONE, - else => switch (target.os.tag) { - .freebsd, .ps4 => .FREEBSD, - .hermit => .STANDALONE, - .illumos, .solaris => .SOLARIS, - .openbsd => .OPENBSD, - else => .NONE, - }, - })); - index += 1; - - // ABI Version, possibly used by glibc but not by static executables - // padding - @memset(hdr_buf[index..][0..8], 0); - index += 8; - - assert(index == 16); - const output_mode = comp.config.output_mode; const link_mode = comp.config.link_mode; - const elf_type: elf.ET = switch (output_mode) { - .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC, - .Obj => .REL, - .Lib => switch (link_mode) { - .static => @as(elf.ET, .REL), - .dynamic => .DYN, - }, - }; - mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian); - index += 2; - - const machine = target.toElfMachine(); - mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(machine), endian); - index += 2; - - // ELF Version, again - mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian); - index += 4; - - const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: { - const entry_sym = obj.entrySymbol(self) orelse break :blk 0; - break :blk @intCast(entry_sym.address(.{}, self)); - } else 0; const phdr_table_offset = if (self.phdr_indexes.table.int()) |phndx| self.phdrs.items[phndx].p_offset else 0; - switch (self.ptr_width) { - .p32 => { - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(e_entry), endian); - index += 4; - - // e_phoff - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(phdr_table_offset), endian); - index += 4; - // e_shoff - mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(self.shdr_table_offset.?), endian); - index += 4; + const hdr: native_elf.Ehdr = .{ + .e_ident = .{ + .ei_magic = mem.bytesAsValue(u32, elf.MAGIC), + .ei_class = if (is_64) .@"32" else .@"64", + .ei_data = switch (target.cpu.arch.endian()) { + .little => .LSB, + .big => .MSB, + }, + .ei_version = .CURRENT, + .ei_osabi = switch (target.cpu.arch) { + .amdgcn => switch (target.os.tag) { + .amdhsa => .AMDGPU_HSA, + .amdpal => .AMDGPU_PAL, + .mesa3d => .AMDGPU_MESA3D, + else => .NONE, + }, + .msp430 => .STANDALONE, + else => switch (target.os.tag) { + .freebsd, .ps4 => .FREEBSD, + .hermit => .STANDALONE, + .illumos, .solaris => .SOLARIS, + .openbsd => .OPENBSD, + else => .NONE, + }, + }, + // possibly used by glibc but not by static executables + .ei_abiversion = 8, }, - .p64 => { - // e_entry - mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian); - index += 8; - - // e_phoff - mem.writeInt(u64, hdr_buf[index..][0..8], phdr_table_offset, endian); - index += 8; - - // e_shoff - mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian); - index += 8; + .e_type = switch (output_mode) { + .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC, + .Obj => .REL, + .Lib => switch (link_mode) { + .static => .REL, + .dynamic => .DYN, + }, }, - } - - const e_flags = 0; - mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian); - index += 4; - - const e_ehsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Ehdr), - .p64 => @sizeOf(elf.Elf64_Ehdr), - }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian); - index += 2; - - const e_phentsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), - }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian); - index += 2; - - const e_phnum = @as(u16, @intCast(self.phdrs.items.len)); - mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian); - index += 2; - - const e_shentsize: u16 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Shdr), - .p64 => @sizeOf(elf.Elf64_Shdr), + .e_machine = target.toElfMachine(), + .e_version = mem.bytesToValue(u32, elf.MAGIC), + .e_entry = if (self.linkerDefinedPtr()) |obj| blk: { + const entry_sym = obj.entrySymbol(self) orelse break :blk 0; + break :blk @intCast(entry_sym.address(.{}, self)); + } else 0, + .e_phoff = @intCast(phdr_table_offset), + .e_shoff = @intCast(self.shdr_table_offset.?), + .e_flags = 0, + .e_ehsize = @sizeOf(native_elf.Ehdr), + .e_phentsize = @sizeOf(native_elf.Phdr), + .e_phnum = @intCast(self.phdrs.items.len), + .e_shentsize = @sizeOf(native_elf.Shdr), + .e_shnum = @intCast(self.sections.items(.shdr).len), + .e_shstrndx = @intCast(self.section_indexes.shstrtab.?), }; - mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian); - index += 2; - const e_shnum: u16 = @intCast(self.sections.items(.shdr).len); - mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian); - index += 2; - - mem.writeInt(u16, hdr_buf[index..][0..2], @intCast(self.section_indexes.shstrtab.?), endian); - index += 2; - - assert(index == e_ehsize); + try self.pwriteAll(mem.asBytes(&hdr), 0); +} - try self.pwriteAll(hdr_buf[0..index], 0); +pub fn writeElfHeader(self: *Elf) !void { + switch (self.ptr_width) { + .p32 => try self.writeElfHeaderImpl(false), + .p64 => try self.writeElfHeaderImpl(true), + } } pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void { @@ -2456,7 +2376,7 @@ fn checkDuplicates(self: *Elf) !void { pub fn addCommentString(self: *Elf) !void { const gpa = self.base.comp.gpa; if (self.comment_merge_section_index != null) return; - const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, elf.SHT_PROGBITS); + const msec_index = try self.getOrCreateMergeSection(".comment", elf.SHF_MERGE | elf.SHF_STRINGS, .PROGBITS); const msec = self.mergeSection(msec_index); const res = try msec.insertZ(gpa, "zig " ++ builtin.zig_version_string); if (res.found_existing) return; @@ -2583,9 +2503,9 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.eh_frame = self.sectionByName(".eh_frame") orelse try self.addSection(.{ .name = try self.insertShString(".eh_frame"), .type = if (target.cpu.arch == .x86_64) - elf.SHT_X86_64_UNWIND + .X86_64_UNWIND else - elf.SHT_PROGBITS, + .PROGBITS, .flags = elf.SHF_ALLOC, .addralign = ptr_size, }); @@ -2593,7 +2513,7 @@ fn initSyntheticSections(self: *Elf) !void { if (comp.link_eh_frame_hdr and self.section_indexes.eh_frame_hdr == null) { self.section_indexes.eh_frame_hdr = try self.addSection(.{ .name = try self.insertShString(".eh_frame_hdr"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC, .addralign = 4, }); @@ -2603,7 +2523,7 @@ fn initSyntheticSections(self: *Elf) !void { if (self.got.entries.items.len > 0 and self.section_indexes.got == null) { self.section_indexes.got = try self.addSection(.{ .name = try self.insertShString(".got"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .addralign = ptr_size, }); @@ -2612,7 +2532,7 @@ fn initSyntheticSections(self: *Elf) !void { if (self.section_indexes.got_plt == null) { self.section_indexes.got_plt = try self.addSection(.{ .name = try self.insertShString(".got.plt"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, .addralign = @alignOf(u64), }); @@ -2632,10 +2552,10 @@ fn initSyntheticSections(self: *Elf) !void { if (needs_rela_dyn and self.section_indexes.rela_dyn == null) { self.section_indexes.rela_dyn = try self.addSection(.{ .name = try self.insertShString(".rela.dyn"), - .type = elf.SHT_RELA, + .type = .RELA, .flags = elf.SHF_ALLOC, - .addralign = @alignOf(elf.Elf64_Rela), - .entsize = @sizeOf(elf.Elf64_Rela), + .addralign = @alignOf(elf.elf64.Rela), + .entsize = @sizeOf(elf.elf64.Rela), }); } @@ -2643,7 +2563,7 @@ fn initSyntheticSections(self: *Elf) !void { if (self.section_indexes.plt == null) { self.section_indexes.plt = try self.addSection(.{ .name = try self.insertShString(".plt"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, .addralign = 16, }); @@ -2651,10 +2571,10 @@ fn initSyntheticSections(self: *Elf) !void { if (self.section_indexes.rela_plt == null) { self.section_indexes.rela_plt = try self.addSection(.{ .name = try self.insertShString(".rela.plt"), - .type = elf.SHT_RELA, + .type = .RELA, .flags = elf.SHF_ALLOC, - .addralign = @alignOf(elf.Elf64_Rela), - .entsize = @sizeOf(elf.Elf64_Rela), + .addralign = @alignOf(elf.elf64.Rela), + .entsize = @sizeOf(elf.elf64.Rela), }); } } @@ -2662,7 +2582,7 @@ fn initSyntheticSections(self: *Elf) !void { if (self.plt_got.symbols.items.len > 0 and self.section_indexes.plt_got == null) { self.section_indexes.plt_got = try self.addSection(.{ .name = try self.insertShString(".plt.got"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, .addralign = 16, }); @@ -2671,7 +2591,7 @@ fn initSyntheticSections(self: *Elf) !void { if (self.copy_rel.symbols.items.len > 0 and self.section_indexes.copy_rel == null) { self.section_indexes.copy_rel = try self.addSection(.{ .name = try self.insertShString(".copyrel"), - .type = elf.SHT_NOBITS, + .type = .NOBITS, .flags = elf.SHF_ALLOC | elf.SHF_WRITE, }); } @@ -2688,7 +2608,7 @@ fn initSyntheticSections(self: *Elf) !void { if (needs_interp and self.section_indexes.interp == null) { self.section_indexes.interp = try self.addSection(.{ .name = try self.insertShString(".interp"), - .type = elf.SHT_PROGBITS, + .type = .PROGBITS, .flags = elf.SHF_ALLOC, .addralign = 1, }); @@ -2699,7 +2619,7 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.dynstrtab = try self.addSection(.{ .name = try self.insertShString(".dynstr"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_STRTAB, + .type = .STRTAB, .entsize = 1, .addralign = 1, }); @@ -2708,18 +2628,18 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.dynamic = try self.addSection(.{ .name = try self.insertShString(".dynamic"), .flags = elf.SHF_ALLOC | elf.SHF_WRITE, - .type = elf.SHT_DYNAMIC, - .entsize = @sizeOf(elf.Elf64_Dyn), - .addralign = @alignOf(elf.Elf64_Dyn), + .type = .DYNAMIC, + .entsize = @sizeOf(elf.elf64.Dyn), + .addralign = @alignOf(elf.elf64.Dyn), }); } if (self.section_indexes.dynsymtab == null) { self.section_indexes.dynsymtab = try self.addSection(.{ .name = try self.insertShString(".dynsym"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_DYNSYM, - .addralign = @alignOf(elf.Elf64_Sym), - .entsize = @sizeOf(elf.Elf64_Sym), + .type = .DYNSYM, + .addralign = @alignOf(elf.elf64.Sym), + .entsize = @sizeOf(elf.elf64.Sym), .info = 1, }); } @@ -2727,7 +2647,7 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.hash = try self.addSection(.{ .name = try self.insertShString(".hash"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_HASH, + .type = .HASH, .addralign = 4, .entsize = 4, }); @@ -2736,21 +2656,21 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.gnu_hash = try self.addSection(.{ .name = try self.insertShString(".gnu.hash"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_GNU_HASH, + .type = .GNU_HASH, .addralign = 8, }); } const needs_versions = for (self.dynsym.entries.items) |entry| { const sym = self.symbol(entry.ref).?; - if (sym.flags.import and sym.version_index.VERSION > elf.Versym.GLOBAL.VERSION) break true; + if (sym.flags.import and sym.version_index.version > elf.Versym.global.version) break true; } else false; if (needs_versions) { if (self.section_indexes.versym == null) { self.section_indexes.versym = try self.addSection(.{ .name = try self.insertShString(".gnu.version"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_GNU_VERSYM, + .type = .GNU_VERSYM, .addralign = @alignOf(elf.Versym), .entsize = @sizeOf(elf.Versym), }); @@ -2759,8 +2679,8 @@ fn initSyntheticSections(self: *Elf) !void { self.section_indexes.verneed = try self.addSection(.{ .name = try self.insertShString(".gnu.version_r"), .flags = elf.SHF_ALLOC, - .type = elf.SHT_GNU_VERNEED, - .addralign = @alignOf(elf.Elf64_Verneed), + .type = .GNU_VERNEED, + .addralign = @alignOf(elf.elf64.Verneed), }); } } @@ -2776,17 +2696,18 @@ pub fn initSymtab(self: *Elf) !void { .p64 => false, }; if (self.section_indexes.symtab == null) { + const Sym = if (small_ptr) elf.elf32.Sym else elf.elf64.Sym; self.section_indexes.symtab = try self.addSection(.{ .name = try self.insertShString(".symtab"), - .type = elf.SHT_SYMTAB, - .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym), - .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym), + .type = .SYMTAB, + .addralign = @alignOf(Sym), + .entsize = @sizeOf(Sym), }); } if (self.section_indexes.strtab == null) { self.section_indexes.strtab = try self.addSection(.{ .name = try self.insertShString(".strtab"), - .type = elf.SHT_STRTAB, + .type = .STRTAB, .entsize = 1, .addralign = 1, }); @@ -2797,7 +2718,7 @@ pub fn initShStrtab(self: *Elf) !void { if (self.section_indexes.shstrtab == null) { self.section_indexes.shstrtab = try self.addSection(.{ .name = try self.insertShString(".shstrtab"), - .type = elf.SHT_STRTAB, + .type = .STRTAB, .entsize = 1, .addralign = 1, }); @@ -2809,27 +2730,27 @@ fn initSpecialPhdrs(self: *Elf) !void { if (self.section_indexes.interp != null and self.phdr_indexes.interp == .none) { self.phdr_indexes.interp = (try self.addPhdr(.{ - .type = elf.PT_INTERP, - .flags = elf.PF_R, + .type = .INTERP, + .flags = .{ .read = true }, .@"align" = 1, })).toOptional(); } if (self.section_indexes.dynamic != null and self.phdr_indexes.dynamic == .none) { self.phdr_indexes.dynamic = (try self.addPhdr(.{ - .type = elf.PT_DYNAMIC, - .flags = elf.PF_R | elf.PF_W, + .type = .DYNAMIC, + .flags = .{ .read = true, .write = true }, })).toOptional(); } if (self.section_indexes.eh_frame_hdr != null and self.phdr_indexes.gnu_eh_frame == .none) { self.phdr_indexes.gnu_eh_frame = (try self.addPhdr(.{ - .type = elf.PT_GNU_EH_FRAME, - .flags = elf.PF_R, + .type = .GNU_EH_FRAME, + .flags = .{ .read = true }, })).toOptional(); } if (self.phdr_indexes.gnu_stack == .none) { self.phdr_indexes.gnu_stack = (try self.addPhdr(.{ - .type = elf.PT_GNU_STACK, - .flags = elf.PF_W | elf.PF_R, + .type = .GNU_STACK, + .flags = .{ .read = true, .write = true }, .memsz = self.base.stack_size, .@"align" = 1, })).toOptional(); @@ -2840,8 +2761,8 @@ fn initSpecialPhdrs(self: *Elf) !void { } else false; if (has_tls and self.phdr_indexes.tls == .none) { self.phdr_indexes.tls = (try self.addPhdr(.{ - .type = elf.PT_TLS, - .flags = elf.PF_R, + .type = .TLS, + .flags = .{ .read = true }, .@"align" = 1, })).toOptional(); } @@ -2885,10 +2806,7 @@ fn sortInitFini(self: *Elf) !void { var is_init_fini = false; var is_ctor_dtor = false; switch (shdr.sh_type) { - elf.SHT_PREINIT_ARRAY, - elf.SHT_INIT_ARRAY, - elf.SHT_FINI_ARRAY, - => is_init_fini = true, + .PREINIT_ARRAY, .INIT_ARRAY, .FINI_ARRAY => is_init_fini = true, else => { const name = self.getShString(shdr.sh_name); is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null; @@ -2956,7 +2874,7 @@ fn setVersionSymtab(self: *Elf) !void { const gpa = self.base.comp.gpa; if (self.section_indexes.versym == null) return; try self.versym.resize(gpa, self.dynsym.count()); - self.versym.items[0] = .LOCAL; + self.versym.items[0] = .local; for (self.dynsym.entries.items, 1..) |entry, i| { const sym = self.symbol(entry.ref).?; self.versym.items[i] = sym.version_index; @@ -2980,13 +2898,13 @@ fn setHashSections(self: *Elf) !void { fn phdrRank(phdr: elf.Elf64_Phdr) u8 { return switch (phdr.p_type) { - elf.PT_NULL => 0, - elf.PT_PHDR => 1, - elf.PT_INTERP => 2, - elf.PT_LOAD => 3, - elf.PT_DYNAMIC, elf.PT_TLS => 4, - elf.PT_GNU_EH_FRAME => 5, - elf.PT_GNU_STACK => 6, + .NULL => 0, + .PHDR => 1, + .INTERP => 2, + .LOAD => 3, + .DYNAMIC, .TLS => 4, + .GNU_EH_FRAME => 5, + .GNU_STACK => 6, else => 7, }; } @@ -3000,7 +2918,7 @@ fn sortPhdrs( const Entry = struct { phndx: u16, - pub fn lessThan(program_headers: []const elf.Elf64_Phdr, lhs: @This(), rhs: @This()) bool { + pub fn lessThan(program_headers: []const elf.elf64.Phdr, lhs: @This(), rhs: @This()) bool { const lhs_phdr = program_headers[lhs.phndx]; const rhs_phdr = program_headers[rhs.phndx]; const lhs_rank = phdrRank(lhs_phdr); @@ -3017,7 +2935,7 @@ fn sortPhdrs( } // The `@as` here works around a bug in the C backend. - mem.sort(Entry, entries, @as([]const elf.Elf64_Phdr, phdrs.items), Entry.lessThan); + mem.sort(Entry, entries, @as([]const elf.elf64.Phdr, phdrs.items), Entry.lessThan); const backlinks = try gpa.alloc(u16, entries.len); defer gpa.free(backlinks); @@ -3043,29 +2961,29 @@ fn sortPhdrs( } } -fn shdrRank(shdr: elf.Elf64_Shdr, shstrtab: []const u8) u8 { +fn shdrRank(shdr: elf.elf64.Shdr, shstrtab: []const u8) u8 { const name = shString(shstrtab, shdr.sh_name); const flags = shdr.sh_flags; switch (shdr.sh_type) { - elf.SHT_NULL => return 0, - elf.SHT_DYNSYM => return 2, - elf.SHT_HASH => return 3, - elf.SHT_GNU_HASH => return 3, - elf.SHT_GNU_VERSYM => return 4, - elf.SHT_GNU_VERDEF => return 4, - elf.SHT_GNU_VERNEED => return 4, - - elf.SHT_PREINIT_ARRAY, - elf.SHT_INIT_ARRAY, - elf.SHT_FINI_ARRAY, + .NULL => return 0, + .DYNSYM => return 2, + .HASH => return 3, + .GNU_HASH => return 3, + .GNU_VERSYM => return 4, + .GNU_VERDEF => return 4, + .GNU_VERNEED => return 4, + + .PREINIT_ARRAY, + .INIT_ARRAY, + .FINI_ARRAY, => return 0xf1, - elf.SHT_DYNAMIC => return 0xf2, + .DYNAMIC => return 0xf2, - elf.SHT_RELA, elf.SHT_GROUP => return 0xf, + .RELA, .GROUP => return 0xf, - elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { + .PROGBITS => if (flags & elf.SHF_ALLOC != 0) { if (flags & elf.SHF_EXECINSTR != 0) { return 0xf0; } else if (flags & elf.SHF_WRITE != 0) { @@ -3084,11 +3002,11 @@ fn shdrRank(shdr: elf.Elf64_Shdr, shstrtab: []const u8) u8 { return 0xf8; } }, - elf.SHT_X86_64_UNWIND => return 0xe1, + .X86_64_UNWIND => return 0xe1, - elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6, - elf.SHT_SYMTAB => return 0xf9, - elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa, + .NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6, + .SYMTAB => return 0xf9, + .STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa, else => return 0xff, } } @@ -3107,7 +3025,7 @@ pub fn sortShdrs( shndx: u32, const Context = struct { - shdrs: []const elf.Elf64_Shdr, + shdrs: []const elf.elf64.Shdr, shstrtab: []const u8, }; @@ -3166,7 +3084,7 @@ pub fn sortShdrs( for (atom_list.atoms.keys()) |ref| { fileLookup(files, ref.file, zig_object_ptr).?.atom(ref.index).?.output_section_index = atom_list.output_section_index; } - if (shdr.sh_type == elf.SHT_RELA) { + if (shdr.sh_type == .RELA) { shdr.sh_link = section_indexes.symtab.?; shdr.sh_info = backlinks[shdr.sh_info]; } @@ -3293,11 +3211,11 @@ fn updateSectionSizes(self: *Elf) !void { for (self.objects.items) |index| { num += self.file(index).?.object.num_dynrelocs; } - shdrs[shndx].sh_size = num * @sizeOf(elf.Elf64_Rela); + shdrs[shndx].sh_size = num * @sizeOf(elf.elf64.Rela); } if (self.section_indexes.rela_plt) |index| { - shdrs[index].sh_size = self.plt.numRela() * @sizeOf(elf.Elf64_Rela); + shdrs[index].sh_size = self.plt.numRela() * @sizeOf(elf.elf64.Rela); } if (self.section_indexes.copy_rel) |index| { @@ -3346,13 +3264,14 @@ pub fn updateShStrtabSize(self: *Elf) void { } } -fn shdrToPhdrFlags(sh_flags: u64) u32 { +fn shdrToPhdrFlags(sh_flags: u64) elf.PF { const write = sh_flags & elf.SHF_WRITE != 0; const exec = sh_flags & elf.SHF_EXECINSTR != 0; - var out_flags: u32 = elf.PF_R; - if (write) out_flags |= elf.PF_W; - if (exec) out_flags |= elf.PF_X; - return out_flags; + return .{ + .read = true, + .write = write, + .execute = exec, + }; } /// Returns maximum number of program headers that may be emitted by the linker. @@ -3370,11 +3289,11 @@ fn getMaxNumberOfPhdrs() u64 { fn addLoadPhdrs(self: *Elf) error{OutOfMemory}!void { for (self.sections.items(.shdr)) |shdr| { - if (shdr.sh_type == elf.SHT_NULL) continue; + if (shdr.sh_type == .NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; const flags = shdrToPhdrFlags(shdr.sh_flags); - if (self.getPhdr(.{ .flags = flags, .type = elf.PT_LOAD }) == .none) { - _ = try self.addPhdr(.{ .flags = flags, .type = elf.PT_LOAD }); + if (self.getPhdr(.{ .flags = flags, .type = .LOAD }) == .none) { + _ = try self.addPhdr(.{ .flags = flags, .type = .LOAD }); } } } @@ -3385,14 +3304,13 @@ fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void { const phdr_table = &self.phdrs.items[self.phdr_indexes.table.int().?]; const phdr_table_load = &self.phdrs.items[self.phdr_indexes.table_load.int().?]; - const ehsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Ehdr), - .p64 => @sizeOf(elf.Elf64_Ehdr), - }; - const phsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Phdr), - .p64 => @sizeOf(elf.Elf64_Phdr), + const native_elf = switch (self.ptr_width) { + .p32 => elf.elf32, + .p64 => elf.elf64, }; + + const ehsize: u64 = @sizeOf(native_elf.Ehdr); + const phsize: u64 = @sizeOf(native_elf.Phdr); const needed_size = self.phdrs.items.len * phsize; const available_space = self.allocatedSize(phdr_table.p_offset); @@ -3439,7 +3357,7 @@ pub fn allocateAllocSections(self: *Elf) !void { const slice = self.sections.slice(); var alignment = Align{}; for (slice.items(.shdr), 0..) |shdr, i| { - if (shdr.sh_type == elf.SHT_NULL) continue; + if (shdr.sh_type == .NULL) continue; if (shdr.sh_flags & elf.SHF_TLS == 0) continue; if (alignment.first_tls_index == null) alignment.first_tls_index = i; alignment.tls_start_align = @max(alignment.tls_start_align, shdr.sh_addralign); @@ -3464,7 +3382,7 @@ pub fn allocateAllocSections(self: *Elf) !void { }; for (slice.items(.shdr), 0..) |shdr, shndx| { - if (shdr.sh_type == elf.SHT_NULL) continue; + if (shdr.sh_type == .NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; const flags = shdrToPhdrFlags(shdr.sh_flags); try covers[flags - 1].append(@intCast(shndx)); @@ -3484,7 +3402,7 @@ pub fn allocateAllocSections(self: *Elf) !void { var @"align": u64 = self.page_size; for (cover.items) |shndx| { const shdr = slice.items(.shdr)[shndx]; - if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue; + if (shdr.sh_type == .NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue; @"align" = @max(@"align", shdr.sh_addralign); } @@ -3496,7 +3414,7 @@ pub fn allocateAllocSections(self: *Elf) !void { while (i < cover.items.len) : (i += 1) { const shndx = cover.items[i]; const shdr = &slice.items(.shdr)[shndx]; - if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) { + if (shdr.sh_type == .NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) { // .tbss is a little special as it's used only by the loader meaning it doesn't // need to be actually mmap'ed at runtime. We still need to correctly increment // the addresses of every TLS zerofill section tho. Thus, we hack it so that @@ -3511,7 +3429,7 @@ pub fn allocateAllocSections(self: *Elf) !void { // ... var tbss_addr = addr; while (i < cover.items.len and - slice.items(.shdr)[cover.items[i]].sh_type == elf.SHT_NOBITS and + slice.items(.shdr)[cover.items[i]].sh_type == .NOBITS and slice.items(.shdr)[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1) { const tbss_shndx = cover.items[i]; @@ -3527,7 +3445,7 @@ pub fn allocateAllocSections(self: *Elf) !void { const padding = next - addr; addr = next; shdr.sh_addr = addr; - if (shdr.sh_type != elf.SHT_NOBITS) { + if (shdr.sh_type != .NOBITS) { filesz += padding + shdr.sh_size; } memsz += padding + shdr.sh_size; @@ -3535,7 +3453,7 @@ pub fn allocateAllocSections(self: *Elf) !void { } const first = slice.items(.shdr)[cover.items[0]]; - const phndx = self.getPhdr(.{ .type = elf.PT_LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).unwrap().?; + const phndx = self.getPhdr(.{ .type = .LOAD, .flags = shdrToPhdrFlags(first.sh_flags) }).unwrap().?; const phdr = &self.phdrs.items[phndx.int()]; const allocated_size = self.allocatedSize(phdr.p_offset); if (filesz > allocated_size) { @@ -3549,7 +3467,7 @@ pub fn allocateAllocSections(self: *Elf) !void { for (cover.items) |shndx| { const shdr = &slice.items(.shdr)[shndx]; slice.items(.phndx)[shndx] = phndx.toOptional(); - if (shdr.sh_type == elf.SHT_NOBITS) { + if (shdr.sh_type == .NOBITS) { shdr.sh_offset = 0; continue; } @@ -3591,7 +3509,7 @@ pub fn allocateAllocSections(self: *Elf) !void { /// Allocates non-alloc sections (debug info, symtabs, etc.). pub fn allocateNonAllocSections(self: *Elf) !void { for (self.sections.items(.shdr), 0..) |*shdr, shndx| { - if (shdr.sh_type == elf.SHT_NULL) continue; + if (shdr.sh_type == .NULL) continue; if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue; const needed_size = shdr.sh_size; if (needed_size > self.allocatedSize(shdr.sh_offset)) { @@ -3660,7 +3578,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { phdr.p_align = shdr.sh_addralign; shndx += 1; phdr.p_align = @max(phdr.p_align, shdr.sh_addralign); - if (shdr.sh_type != elf.SHT_NOBITS) { + if (shdr.sh_type != .NOBITS) { phdr.p_filesz = shdr.sh_offset + shdr.sh_size - phdr.p_offset; } phdr.p_memsz = shdr.sh_addr + shdr.sh_size - phdr.p_vaddr; @@ -3669,7 +3587,7 @@ fn allocateSpecialPhdrs(self: *Elf) void { const next = shdrs[shndx]; if (next.sh_flags & elf.SHF_TLS == 0) break; phdr.p_align = @max(phdr.p_align, next.sh_addralign); - if (next.sh_type != elf.SHT_NOBITS) { + if (next.sh_type != .NOBITS) { phdr.p_filesz = next.sh_offset + next.sh_size - phdr.p_offset; } phdr.p_memsz = next.sh_addr + next.sh_size - phdr.p_vaddr; @@ -3695,7 +3613,7 @@ fn writeAtoms(self: *Elf) !void { const slice = self.sections.slice(); var has_reloc_errors = false; for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| { - if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (shdr.sh_type == .NOBITS) continue; if (atom_list.atoms.keys().len == 0) continue; atom_list.write(&buffer, &undefs, self) catch |err| switch (err) { error.UnsupportedCpuArch => { @@ -3804,8 +3722,8 @@ pub fn updateSymtabSize(self: *Elf) !void { symtab_shdr.sh_link = self.section_indexes.strtab.?; const sym_size: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Sym), - .p64 => @sizeOf(elf.Elf64_Sym), + .p32 => @sizeOf(elf.elf32.Sym), + .p64 => @sizeOf(elf.elf64.Sym), }; const needed_size = (nlocals + nglobals) * sym_size; symtab_shdr.sh_size = needed_size; @@ -3966,8 +3884,8 @@ pub fn writeSymtab(self: *Elf) !void { const symtab_shdr = slice.items(.shdr)[self.section_indexes.symtab.?]; const strtab_shdr = slice.items(.shdr)[self.section_indexes.strtab.?]; const sym_size: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Sym), - .p64 => @sizeOf(elf.Elf64_Sym), + .p32 => @sizeOf(elf.elf32.Sym), + .p64 => @sizeOf(elf.elf64.Sym), }; const nsyms = try self.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)); @@ -3993,7 +3911,9 @@ pub fn writeSymtab(self: *Elf) !void { out_sym.* = .{ .st_name = 0, .st_value = shdr.sh_addr, - .st_info = if (shdr.sh_type == elf.SHT_NULL) elf.STT_NOTYPE else elf.STT_SECTION, + .st_info = .{ + .type = if (shdr.sh_type == .NULL) .NOTYPE else .SECTION, + }, .st_shndx = @intCast(shndx), .st_size = 0, .st_other = 0, @@ -4037,7 +3957,7 @@ pub fn writeSymtab(self: *Elf) !void { const foreign_endian = self.getTarget().cpu.arch.endian() != builtin.cpu.arch.endian(); switch (self.ptr_width) { .p32 => { - const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len); + const buf = try gpa.alloc(elf.elf32.Sym, self.symtab.items.len); defer gpa.free(buf); for (buf, self.symtab.items) |*out, sym| { @@ -4049,13 +3969,13 @@ pub fn writeSymtab(self: *Elf) !void { .st_value = @intCast(sym.st_value), .st_size = @intCast(sym.st_size), }; - if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out); + if (foreign_endian) mem.byteSwapAllFields(elf.elf32.Sym, out); } try self.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset); }, .p64 => { if (foreign_endian) { - for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym); + for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.elf64.Sym, sym); } try self.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset); }, @@ -4078,7 +3998,7 @@ pub fn archPtrWidthBytes(self: Elf) u8 { return @intCast(@divExact(self.getTarget().ptrBitWidth(), 8)); } -fn phdrTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { +fn phdrTo32(phdr: elf.elf64.Phdr) elf.elf32.Phdr { return .{ .p_type = phdr.p_type, .p_flags = phdr.p_flags, @@ -4091,7 +4011,7 @@ fn phdrTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { }; } -fn shdrTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr { +fn shdrTo32(shdr: elf.elf64.Shdr) elf.elf32.Shdr { return .{ .sh_name = shdr.sh_name, .sh_type = shdr.sh_type, @@ -4201,8 +4121,8 @@ pub fn isEffectivelyDynLib(self: Elf) bool { } fn getPhdr(self: *Elf, opts: struct { - type: u32 = 0, - flags: u32 = 0, + type: elf.PT = .NULL, + flags: elf.PF = .{}, }) OptionalProgramHeaderIndex { for (self.phdrs.items, 0..) |phdr, phndx| { if (self.phdr_indexes.table_load.int()) |index| { @@ -4215,8 +4135,8 @@ fn getPhdr(self: *Elf, opts: struct { } fn addPhdr(self: *Elf, opts: struct { - type: u32 = 0, - flags: u32 = 0, + type: elf.PT = .NULL, + flags: elf.PF = .{}, @"align": u64 = 0, offset: u64 = 0, addr: u64 = 0, @@ -4239,17 +4159,15 @@ fn addPhdr(self: *Elf, opts: struct { } pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 { - const entsize: u64 = switch (self.ptr_width) { - .p32 => @sizeOf(elf.Elf32_Rela), - .p64 => @sizeOf(elf.Elf64_Rela), - }; - const addralign: u64 = switch (self.ptr_width) { - .p32 => @alignOf(elf.Elf32_Rela), - .p64 => @alignOf(elf.Elf64_Rela), + const Rela = switch (self.ptr_width) { + .p32 => elf.elf32.Rela, + .p64 => elf.elf64.Rela, }; + const entsize: u64 = @sizeOf(Rela); + const addralign: u64 = @alignOf(Rela); return self.addSection(.{ .name = name, - .type = elf.SHT_RELA, + .type = .RELA, .flags = elf.SHF_INFO_LINK, .entsize = entsize, .info = shndx, @@ -4259,7 +4177,7 @@ pub fn addRelaShdr(self: *Elf, name: u32, shndx: u32) !u32 { pub const AddSectionOpts = struct { name: u32 = 0, - type: u32 = elf.SHT_NULL, + type: elf.SHT = .NULL, flags: u64 = 0, link: u32 = 0, info: u32 = 0, @@ -4324,9 +4242,9 @@ pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void { fn sortRelaDyn(self: *Elf) void { const Sort = struct { - fn rank(rel: elf.Elf64_Rela, ctx: *Elf) u2 { + fn rank(rel: elf.elf64.Rela, ctx: *Elf) u2 { const cpu_arch = ctx.getTarget().cpu.arch; - const r_type = rel.r_type(); + const r_type = rel.r_info.type; const r_kind = relocation.decode(r_type, cpu_arch).?; return switch (r_kind) { .rel => 0, @@ -4335,15 +4253,15 @@ fn sortRelaDyn(self: *Elf) void { }; } - pub fn lessThan(ctx: *Elf, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { + pub fn lessThan(ctx: *Elf, lhs: elf.elf64.Rela, rhs: elf.elf64.Rela) bool { if (rank(lhs, ctx) == rank(rhs, ctx)) { - if (lhs.r_sym() == rhs.r_sym()) return lhs.r_offset < rhs.r_offset; - return lhs.r_sym() < rhs.r_sym(); + if (lhs.r_info.sym == rhs.r_info.sym) return lhs.r_offset < rhs.r_offset; + return lhs.r_info.sym < rhs.r_info.sym; } return rank(lhs, ctx) < rank(rhs, ctx); } }; - mem.sort(elf.Elf64_Rela, self.rela_dyn.items, self, Sort.lessThan); + mem.sort(elf.elf64.Rela, self.rela_dyn.items, self, Sort.lessThan); } pub fn calcNumIRelativeRelocs(self: *Elf) usize { @@ -4358,7 +4276,7 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize { return count; } -pub fn getStartStopBasename(self: Elf, shdr: elf.Elf64_Shdr) ?[]const u8 { +pub fn getStartStopBasename(self: Elf, shdr: elf.elf64.Shdr) ?[]const u8 { const name = self.getShString(shdr.sh_name); if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { if (Elf.isCIdentifier(name)) return name; @@ -4711,10 +4629,10 @@ fn formatShdrFlags( const FormatPhdrCtx = struct { elf_file: *Elf, - phdr: elf.Elf64_Phdr, + phdr: elf.elf64.Phdr, }; -fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) { +fn fmtPhdr(self: *Elf, phdr: elf.elf64.Phdr) std.fmt.Formatter(formatPhdr) { return .{ .data = .{ .phdr = phdr, .elf_file = self, @@ -4730,23 +4648,21 @@ fn formatPhdr( _ = options; _ = unused_fmt_string; const phdr = ctx.phdr; - const write = phdr.p_flags & elf.PF_W != 0; - const read = phdr.p_flags & elf.PF_R != 0; - const exec = phdr.p_flags & elf.PF_X != 0; + const p_flags = phdr.p_flags; var flags: [3]u8 = [_]u8{'_'} ** 3; - if (exec) flags[0] = 'X'; - if (write) flags[1] = 'W'; - if (read) flags[2] = 'R'; + if (p_flags.execute) flags[0] = 'X'; + if (p_flags.write) flags[1] = 'W'; + if (p_flags.read) flags[2] = 'R'; const p_type = switch (phdr.p_type) { - elf.PT_LOAD => "LOAD", - elf.PT_TLS => "TLS", - elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME", - elf.PT_GNU_STACK => "GNU_STACK", - elf.PT_DYNAMIC => "DYNAMIC", - elf.PT_INTERP => "INTERP", - elf.PT_NULL => "NULL", - elf.PT_PHDR => "PHDR", - elf.PT_NOTE => "NOTE", + .LOAD => "LOAD", + .TLS => "TLS", + .GNU_EH_FRAME => "GNU_EH_FRAME", + .GNU_STACK => "GNU_STACK", + .DYNAMIC => "DYNAMIC", + .INTERP => "INTERP", + .NULL => "NULL", + .PHDR => "PHDR", + .NOTE => "NOTE", else => "UNKNOWN", }; try writer.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{ @@ -4949,18 +4865,18 @@ pub const SymtabCtx = struct { } }; -pub const null_sym = elf.Elf64_Sym{ +pub const null_sym = elf.elf64.Sym{ .st_name = 0, - .st_info = 0, + .st_info = .{}, .st_other = 0, - .st_shndx = 0, + .st_shndx = .UNDEF, .st_value = 0, .st_size = 0, }; -pub const null_shdr = elf.Elf64_Shdr{ +pub const null_shdr = elf.elf64.Shdr{ .sh_name = 0, - .sh_type = 0, + .sh_type = .NULL, .sh_flags = 0, .sh_addr = 0, .sh_offset = 0, @@ -5088,7 +5004,7 @@ pub const SymbolResolver = struct { const Section = struct { /// Section header. - shdr: elf.Elf64_Shdr, + shdr: elf.elf64.Shdr, /// Assigned program header index if any. phndx: OptionalProgramHeaderIndex = .none, @@ -5191,9 +5107,9 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { for (atom_ptr.relocs(elf_file)) |rel| { const is_reachable = switch (cpu_arch) { .aarch64 => r: { - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_info.type); if (r_type != .CALL26 and r_type != .JUMP26) break :r true; - const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target_ref = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const target = elf_file.symbol(target_ref).?; if (target.flags.has_plt) break :r false; if (atom_ptr.output_section_index != target.output_section_index) break :r false; @@ -5208,7 +5124,7 @@ fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { else => @panic("unsupported arch"), }; if (is_reachable) continue; - const target = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); try thunk_ptr.symbols.put(gpa, target, {}); } atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index cb145f772c5d..d50d9a38b4e6 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -89,7 +89,7 @@ pub fn thunk(self: Atom, elf_file: *Elf) *Thunk { return elf_file.thunk(extras.thunk); } -pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { +pub fn inputShdr(self: Atom, elf_file: *Elf) elf.elf64.Shdr { return switch (self.file(elf_file).?) { .object => |x| x.shdrs.items[self.input_section_index], .zig_object => |x| x.inputShdr(self.atom_index, elf_file), @@ -209,8 +209,8 @@ pub fn free(self: *Atom, elf_file: *Elf) void { self.* = .{}; } -pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela { - const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{}; +pub fn relocs(self: Atom, elf_file: *Elf) []const elf.elf64.Rela { + const shndx = self.relocsShndx() orelse return &[0]elf.elf64.Rela{}; switch (self.file(elf_file).?) { .zig_object => |x| return x.relocs.items[shndx].items, .object => |x| { @@ -221,20 +221,20 @@ pub fn relocs(self: Atom, elf_file: *Elf) []const elf.Elf64_Rela { } } -pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void { +pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.elf64.Rela)) !void { relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) }); const cpu_arch = elf_file.getTarget().cpu.arch; const file_ptr = self.file(elf_file).?; for (self.relocs(elf_file)) |rel| { - const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target_ref = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const target = elf_file.symbol(target_ref).?; - const r_type = rel.r_type(); + const r_type = rel.r_info.type; const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset))); var r_addend = rel.r_addend; var r_sym: u32 = 0; switch (target.type(elf_file)) { - elf.STT_SECTION => { + .SECTION => { r_addend += @intCast(target.address(.{}, elf_file)); r_sym = target.outputShndx(elf_file) orelse 0; }, @@ -244,7 +244,7 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El } relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ - relocation.fmtRelocType(rel.r_type(), cpu_arch), + relocation.fmtRelocType(r_type, cpu_arch), r_offset, r_sym, target.name(elf_file), @@ -268,13 +268,13 @@ pub fn markFdesDead(self: Atom, object: *Object) void { for (self.fdes(object)) |*fde| fde.alive = false; } -pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.Elf64_Rela, zo: *ZigObject) !void { +pub fn addReloc(self: Atom, alloc: Allocator, reloc: elf.elf64.Rela, zo: *ZigObject) !void { const rels = &zo.relocs.items[self.relocs_section_index]; try rels.ensureUnusedCapacity(alloc, 1); self.addRelocAssumeCapacity(reloc, zo); } -pub fn addRelocAssumeCapacity(self: Atom, reloc: elf.Elf64_Rela, zo: *ZigObject) void { +pub fn addRelocAssumeCapacity(self: Atom, reloc: elf.elf64.Rela, zo: *ZigObject) void { const rels = &zo.relocs.items[self.relocs_section_index]; rels.appendAssumeCapacity(reloc); } @@ -288,7 +288,7 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool { for (self.relocs(elf_file)) |rel| { switch (cpu_arch) { .x86_64 => { - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_info.type); if (r_type == .GOTTPOFF) return true; }, else => {}, @@ -305,14 +305,14 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype var has_reloc_errors = false; var it = RelocsIterator{ .relocs = rels }; while (it.next()) |rel| { - const r_kind = relocation.decode(rel.r_type(), cpu_arch); + const r_kind = relocation.decode(rel.r_info.type, cpu_arch); if (r_kind == .none) continue; - const symbol_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const symbol_ref = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const symbol = elf_file.symbol(symbol_ref) orelse { const sym_name = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), - inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + .zig_object => |x| x.symbol(rel.r_info.sym).name(elf_file), + inline else => |x| x.symbols.items[rel.r_info.sym].name(elf_file), }; // Violation of One Definition Rule for COMDATs. // TODO convert into an error @@ -326,7 +326,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype const is_synthetic_symbol = switch (file_ptr) { .zig_object => false, // TODO: implement this once we support merge sections in ZigObject - .object => |x| rel.r_sym() >= x.symtab.items.len, + .object => |x| rel.r_info.sym >= x.symtab.items.len, else => unreachable, }; @@ -512,11 +512,11 @@ fn outputType(elf_file: *Elf) u2 { fn dataType(symbol: *const Symbol, elf_file: *Elf) u2 { if (symbol.isAbs(elf_file)) return 0; if (!symbol.flags.import) return 1; - if (symbol.type(elf_file) != elf.STT_FUNC) return 2; + if (symbol.type(elf_file) != elf.STT.FUNC) return 2; return 3; } -fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) RelocError!void { +fn reportUnhandledRelocError(self: Atom, rel: elf.elf64.Rela, elf_file: *Elf) RelocError!void { const diags = &elf_file.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); try err.addMsg("fatal linker error: unhandled relocation type {} at offset 0x{x}", .{ @@ -530,7 +530,7 @@ fn reportUnhandledRelocError(self: Atom, rel: elf.Elf64_Rela, elf_file: *Elf) Re fn reportTextRelocError( self: Atom, symbol: *const Symbol, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, elf_file: *Elf, ) RelocError!void { const diags = &elf_file.base.comp.link_diags; @@ -546,7 +546,7 @@ fn reportTextRelocError( fn reportPicError( self: Atom, symbol: *const Symbol, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, elf_file: *Elf, ) RelocError!void { const diags = &elf_file.base.comp.link_diags; @@ -563,7 +563,7 @@ fn reportPicError( fn reportNoPicError( self: Atom, symbol: *const Symbol, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, elf_file: *Elf, ) RelocError!void { const diags = &elf_file.base.comp.link_diags; @@ -582,28 +582,28 @@ fn reportUndefined( self: Atom, elf_file: *Elf, sym: *const Symbol, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, undefs: anytype, ) !bool { const comp = elf_file.base.comp; const gpa = comp.gpa; const file_ptr = self.file(elf_file).?; const rel_esym = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file), - .shared_object => |so| so.parsed.symtab[rel.r_sym()], - inline else => |x| x.symtab.items[rel.r_sym()], + .zig_object => |x| x.symbol(rel.r_info.sym).elfSym(elf_file), + .shared_object => |so| so.parsed.symtab[rel.r_info.sym], + inline else => |x| x.symtab.items[rel.r_info.sym], }; const esym = sym.elfSym(elf_file); - if (rel_esym.st_shndx == elf.SHN_UNDEF and - rel_esym.st_bind() == elf.STB_GLOBAL and + if (rel_esym.st_shndx == .UNDEF and + rel_esym.st_info.bind == .GLOBAL and sym.esym_index > 0 and !sym.flags.import and - esym.st_shndx == elf.SHN_UNDEF) + esym.st_shndx == .UNDEF) { const idx = switch (file_ptr) { - .zig_object => |x| x.symbols_resolver.items[rel.r_sym() & ZigObject.symbol_mask], - .object => |x| x.symbols_resolver.items[rel.r_sym() - x.first_global.?], - inline else => |x| x.symbols_resolver.items[rel.r_sym()], + .zig_object => |x| x.symbols_resolver.items[rel.r_info.sym & ZigObject.symbol_mask], + .object => |x| x.symbols_resolver.items[rel.r_info.sym - x.first_global.?], + inline else => |x| x.symbols_resolver.items[rel.r_info.sym], }; const gop = try undefs.getOrPut(idx); if (!gop.found_existing) { @@ -627,10 +627,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi var it = RelocsIterator{ .relocs = rels }; var has_reloc_errors = false; while (it.next()) |rel| { - const r_kind = relocation.decode(rel.r_type(), cpu_arch); + const r_kind = relocation.decode(rel.r_info.type, cpu_arch); if (r_kind == .none) continue; - const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target_ref = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const target = elf_file.symbol(target_ref).?; const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; @@ -653,7 +653,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi const DTP = elf_file.dtpAddress(); relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{ - relocation.fmtRelocType(rel.r_type(), cpu_arch), + relocation.fmtRelocType(rel.r_info.type, cpu_arch), r_offset, P, S + A, @@ -810,16 +810,16 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any var has_reloc_errors = false; var it = RelocsIterator{ .relocs = rels }; while (it.next()) |rel| { - const r_kind = relocation.decode(rel.r_type(), cpu_arch); + const r_kind = relocation.decode(rel.r_info.type, cpu_arch); if (r_kind == .none) continue; const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target_ref = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const target = elf_file.symbol(target_ref) orelse { const sym_name = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()).name(elf_file), - inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file), + .zig_object => |x| x.symbol(rel.r_info.sym).name(elf_file), + inline else => |x| x.symbols.items[rel.r_info.sym].name(elf_file), }; // Violation of One Definition Rule for COMDATs. // TODO convert into an error @@ -832,7 +832,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any }; const is_synthetic_symbol = switch (file_ptr) { .zig_object => false, // TODO: implement this once we support merge sections in ZigObject - .object => |x| rel.r_sym() >= x.symtab.items.len, + .object => |x| rel.r_info.sym >= x.symtab.items.len, else => unreachable, }; @@ -856,7 +856,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP }; relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ - relocation.fmtRelocType(rel.r_type(), cpu_arch), + relocation.fmtRelocType(rel.r_info.type, cpu_arch), rel.r_offset, P, S + A, @@ -970,7 +970,7 @@ const x86_64 = struct { fn scanReloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, symbol: *Symbol, code: ?[]const u8, it: *RelocsIterator, @@ -980,7 +980,7 @@ const x86_64 = struct { const is_static = elf_file.base.isStatic(); const is_dyn_lib = elf_file.isEffectivelyDynLib(); - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_info.type); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; switch (r_type) { @@ -1083,7 +1083,7 @@ const x86_64 = struct { fn resolveRelocAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -1093,7 +1093,7 @@ const x86_64 = struct { dev.check(.x86_64_backend); const t = &elf_file.base.comp.root_mod.resolved_target.result; const diags = &elf_file.base.comp.link_diags; - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_info.type); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); @@ -1224,7 +1224,7 @@ const x86_64 = struct { fn resolveRelocNonAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -1234,7 +1234,7 @@ const x86_64 = struct { dev.check(.x86_64_backend); _ = code; _ = it; - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_info.type); const cwriter = stream.writer(); _, const A, const S, const GOT, _, _, const DTP = args; @@ -1305,7 +1305,7 @@ const x86_64 = struct { fn relaxTlsGdToIe( self: Atom, - rels: []const elf.Elf64_Rela, + rels: []const elf.elf64.Rela, value: i32, elf_file: *Elf, stream: anytype, @@ -1314,7 +1314,7 @@ const x86_64 = struct { assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; const writer = stream.writer(); - const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); + const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_info.type); switch (rel) { .PC32, .PLT32, @@ -1331,8 +1331,8 @@ const x86_64 = struct { else => { var err = try diags.addErrorWithNotes(1); try err.addMsg("TODO: rewrite {} when followed by {}", .{ - relocation.fmtRelocType(rels[0].r_type(), .x86_64), - relocation.fmtRelocType(rels[1].r_type(), .x86_64), + relocation.fmtRelocType(rels[0].r_info.type, .x86_64), + relocation.fmtRelocType(rels[1].r_info.type, .x86_64), }); err.addNote("in {}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), @@ -1346,7 +1346,7 @@ const x86_64 = struct { fn relaxTlsLdToLe( self: Atom, - rels: []const elf.Elf64_Rela, + rels: []const elf.elf64.Rela, value: i32, elf_file: *Elf, stream: anytype, @@ -1355,7 +1355,7 @@ const x86_64 = struct { assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; const writer = stream.writer(); - const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); + const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_info.type); switch (rel) { .PC32, .PLT32, @@ -1387,8 +1387,8 @@ const x86_64 = struct { else => { var err = try diags.addErrorWithNotes(1); try err.addMsg("TODO: rewrite {} when followed by {}", .{ - relocation.fmtRelocType(rels[0].r_type(), .x86_64), - relocation.fmtRelocType(rels[1].r_type(), .x86_64), + relocation.fmtRelocType(rels[0].r_info.type, .x86_64), + relocation.fmtRelocType(rels[1].r_info.type, .x86_64), }); err.addNote("in {}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), @@ -1453,7 +1453,7 @@ const x86_64 = struct { fn relaxTlsGdToLe( self: Atom, - rels: []const elf.Elf64_Rela, + rels: []const elf.elf64.Rela, value: i32, elf_file: *Elf, stream: anytype, @@ -1462,7 +1462,7 @@ const x86_64 = struct { assert(rels.len == 2); const diags = &elf_file.base.comp.link_diags; const writer = stream.writer(); - const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type()); + const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_info.type); switch (rel) { .PC32, .PLT32, @@ -1477,16 +1477,16 @@ const x86_64 = struct { try stream.seekBy(-4); try writer.writeAll(&insts); relocs_log.debug(" relaxing {} and {}", .{ - relocation.fmtRelocType(rels[0].r_type(), .x86_64), - relocation.fmtRelocType(rels[1].r_type(), .x86_64), + relocation.fmtRelocType(rels[0].r_info.type, .x86_64), + relocation.fmtRelocType(rels[1].r_info.type, .x86_64), }); }, else => { var err = try diags.addErrorWithNotes(1); try err.addMsg("fatal linker error: rewrite {} when followed by {}", .{ - relocation.fmtRelocType(rels[0].r_type(), .x86_64), - relocation.fmtRelocType(rels[1].r_type(), .x86_64), + relocation.fmtRelocType(rels[0].r_info.type, .x86_64), + relocation.fmtRelocType(rels[1].r_info.type, .x86_64), }); err.addNote("in {}:{s} at offset 0x{x}", .{ self.file(elf_file).?.fmtPath(), @@ -1523,7 +1523,7 @@ const aarch64 = struct { fn scanReloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, symbol: *Symbol, code: ?[]const u8, it: *RelocsIterator, @@ -1531,7 +1531,7 @@ const aarch64 = struct { _ = code; _ = it; - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_info.type); const is_dyn_lib = elf_file.isEffectivelyDynLib(); switch (r_type) { @@ -1609,7 +1609,7 @@ const aarch64 = struct { fn resolveRelocAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -1619,7 +1619,7 @@ const aarch64 = struct { _ = it; const diags = &elf_file.base.comp.link_diags; - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_info.type); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); const code = code_buffer[r_offset..][0..4]; @@ -1645,7 +1645,7 @@ const aarch64 = struct { => { const disp: i28 = math.cast(i28, S + A - P) orelse blk: { const th = atom.thunk(elf_file); - const target_index = file_ptr.resolveSymbol(rel.r_sym(), elf_file); + const target_index = file_ptr.resolveSymbol(rel.r_info.sym, elf_file); const S_ = th.targetAddress(target_index, elf_file); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; @@ -1815,7 +1815,7 @@ const aarch64 = struct { fn resolveRelocNonAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -1825,7 +1825,7 @@ const aarch64 = struct { _ = it; _ = code; - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_info.type); const cwriter = stream.writer(); _, const A, const S, _, _, _, _ = args; @@ -1850,7 +1850,7 @@ const riscv = struct { fn scanReloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, symbol: *Symbol, code: ?[]const u8, it: *RelocsIterator, @@ -1858,7 +1858,7 @@ const riscv = struct { _ = code; _ = it; - const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); + const r_type: elf.R_RISCV = @enumFromInt(rel.r_info.type); switch (r_type) { .@"32" => try atom.scanReloc(symbol, rel, absRelocAction(symbol, elf_file), elf_file), @@ -1894,7 +1894,7 @@ const riscv = struct { fn resolveRelocAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -1902,7 +1902,7 @@ const riscv = struct { stream: anytype, ) !void { const diags = &elf_file.base.comp.link_diags; - const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); + const r_type: elf.R_RISCV = @enumFromInt(rel.r_info.type); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); @@ -1973,13 +1973,13 @@ const riscv = struct { return error.RelocFailure; }; it.pos = pos; - const target_ref_ = file_ptr.resolveSymbol(pair.r_sym(), elf_file); + const target_ref_ = file_ptr.resolveSymbol(pair.r_info.sym, elf_file); const target_ = elf_file.symbol(target_ref_).?; const S_ = target_.address(.{}, elf_file); const A_ = pair.r_addend; const P_ = atom_addr + @as(i64, @intCast(pair.r_offset)); const G_ = target_.gotAddress(elf_file) - GOT; - const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_type()))) { + const disp = switch (@as(elf.R_RISCV, @enumFromInt(pair.r_info.type))) { .PCREL_HI20 => math.cast(i32, S_ + A_ - P_) orelse return error.Overflow, .GOT_HI20 => math.cast(i32, G_ + GOT + A_ - P_) orelse return error.Overflow, else => unreachable, @@ -2032,7 +2032,7 @@ const riscv = struct { fn resolveRelocNonAlloc( atom: Atom, elf_file: *Elf, - rel: elf.Elf64_Rela, + rel: elf.elf64.Rela, target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, @@ -2041,7 +2041,7 @@ const riscv = struct { ) !void { _ = it; - const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); + const r_type: elf.R_RISCV = @enumFromInt(rel.r_info.type); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); @@ -2096,16 +2096,16 @@ const RelocError = error{ }; const RelocsIterator = struct { - relocs: []const elf.Elf64_Rela, + relocs: []const elf.elf64.Rela, pos: i64 = -1, - fn next(it: *RelocsIterator) ?elf.Elf64_Rela { + fn next(it: *RelocsIterator) ?elf.elf64.Rela { it.pos += 1; if (it.pos >= it.relocs.len) return null; return it.relocs[@intCast(it.pos)]; } - fn prev(it: *RelocsIterator) ?elf.Elf64_Rela { + fn prev(it: *RelocsIterator) ?elf.elf64.Rela { if (it.pos == -1) return null; const rel = it.relocs[@intCast(it.pos)]; it.pos -= 1; diff --git a/src/link/Elf/AtomList.zig b/src/link/Elf/AtomList.zig index f8d57d04a108..b81086bed9a5 100644 --- a/src/link/Elf/AtomList.zig +++ b/src/link/Elf/AtomList.zig @@ -92,7 +92,7 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void { pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; const osec = elf_file.sections.items(.shdr)[list.output_section_index]; - assert(osec.sh_type != elf.SHT_NOBITS); + assert(osec.sh_type != .NOBITS); assert(!list.dirty); log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); @@ -129,7 +129,7 @@ pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_fi pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; const osec = elf_file.sections.items(.shdr)[list.output_section_index]; - assert(osec.sh_type != elf.SHT_NOBITS); + assert(osec.sh_type != .NOBITS); log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); diff --git a/src/link/Elf/Merge.zig b/src/link/Elf/Merge.zig index 33e4f9c5b29c..90df1316a84c 100644 --- a/src/link/Elf/Merge.zig +++ b/src/link/Elf/Merge.zig @@ -4,9 +4,9 @@ pub const Section = struct { alignment: Atom.Alignment = .@"1", entsize: u32 = 0, name_offset: u32 = 0, - type: u32 = 0, + type: std.elf.SHT = .NULL, flags: u64 = 0, - output_section_index: u32 = 0, + output_section_index: std.elf.SHN = .UNDEF, bytes: std.ArrayListUnmanaged(u8) = .empty, table: std.HashMapUnmanaged( String, @@ -192,13 +192,13 @@ pub const Section = struct { _ = unused_fmt_string; const msec = ctx.msec; const elf_file = ctx.elf_file; - try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{ + try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({s}) : flags({x})\n", .{ msec.name(elf_file), msec.address(elf_file), msec.size, msec.alignment.toByteUnits() orelse 0, msec.entsize, - msec.type, + @tagName(msec.type), msec.flags, }); for (msec.subsections.items) |msub| { diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index f489294aa0c3..8e4ba41e7d88 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -5,16 +5,16 @@ path: Path, file_handle: File.HandleIndex, index: File.Index, -header: ?elf.Elf64_Ehdr = null, -shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .empty, +header: ?elf.elf64.Ehdr = null, +shdrs: std.ArrayListUnmanaged(elf.elf64.Shdr) = .empty, -symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty, +symtab: std.ArrayListUnmanaged(elf.elf64.Sym) = .empty, strtab: std.ArrayListUnmanaged(u8) = .empty, first_global: ?Symbol.Index = null, symbols: std.ArrayListUnmanaged(Symbol) = .empty, symbols_extra: std.ArrayListUnmanaged(u32) = .empty, symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .empty, -relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .empty, +relocs: std.ArrayListUnmanaged(elf.elf64.Rela) = .empty, atoms: std.ArrayListUnmanaged(Atom) = .empty, atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .empty, @@ -84,7 +84,7 @@ pub fn parse( for (self.shdrs.items, 0..) |shdr, i| { const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue; if (!atom_ptr.alive) continue; - if ((target.cpu.arch == .x86_64 and shdr.sh_type == elf.SHT_X86_64_UNWIND) or + if ((target.cpu.arch == .x86_64 and shdr.sh_type == .X86_64_UNWIND) or mem.eql(u8, self.getString(atom_ptr.name_offset), ".eh_frame")) { try self.parseEhFrame(gpa, handle, @intCast(i), target); @@ -103,9 +103,9 @@ pub fn parseCommon( const offset = if (self.archive) |ar| ar.offset else 0; const file_size = (try handle.stat()).size; - const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.Elf64_Ehdr)); + const header_buffer = try Elf.preadAllAlloc(gpa, handle, offset, @sizeOf(elf.elf64.Ehdr)); defer gpa.free(header_buffer); - self.header = @as(*align(1) const elf.Elf64_Ehdr, @ptrCast(header_buffer)).*; + self.header = @as(*align(1) const elf.elf64.Ehdr, @ptrCast(header_buffer)).*; const em = target.toElfMachine(); if (em != self.header.?.e_machine) { @@ -119,18 +119,18 @@ pub fn parseCommon( const shoff = math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; - const shsize = shnum * @sizeOf(elf.Elf64_Shdr); + const shsize = shnum * @sizeOf(elf.elf64.Shdr); if (file_size < offset + shoff or file_size < offset + shoff + shsize) { return diags.failParse(path, "corrupt header: section header table extends past the end of file", .{}); } const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, offset + shoff, shsize); defer gpa.free(shdrs_buffer); - const shdrs = @as([*]align(1) const elf.Elf64_Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; + const shdrs = @as([*]align(1) const elf.elf64.Shdr, @ptrCast(shdrs_buffer.ptr))[0..shnum]; try self.shdrs.appendUnalignedSlice(gpa, shdrs); for (self.shdrs.items) |shdr| { - if (shdr.sh_type != elf.SHT_NOBITS) { + if (shdr.sh_type != .NOBITS) { if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) { return diags.failParse(path, "corrupt section: extends past the end of file", .{}); } @@ -147,7 +147,7 @@ pub fn parseCommon( try self.strtab.appendSlice(gpa, shstrtab); const symtab_index = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { - elf.SHT_SYMTAB => break @as(u32, @intCast(i)), + .SYMTAB => break @as(u32, @intCast(i)), else => {}, } else null; @@ -157,10 +157,10 @@ pub fn parseCommon( const raw_symtab = try self.preadShdrContentsAlloc(gpa, handle, index); defer gpa.free(raw_symtab); - const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { + const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.elf64.Sym)) catch { return diags.failParse(path, "symbol table not evenly divisible", .{}); }; - const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; + const symtab = @as([*]align(1) const elf.elf64.Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; const strtab_bias = @as(u32, @intCast(self.strtab.items.len)); const strtab = try self.preadShdrContentsAlloc(gpa, handle, shdr.sh_link); @@ -171,8 +171,8 @@ pub fn parseCommon( for (symtab) |sym| { const out_sym = self.symtab.addOneAssumeCapacity(); out_sym.* = sym; - out_sym.st_name = if (sym.st_name == 0 and sym.st_type() == elf.STT_SECTION) - shdrs[sym.st_shndx].sh_name + out_sym.st_name = if (sym.st_name == 0 and sym.st_info.type == .SECTION) + shdrs[sym.shndx()].sh_name else sym.st_name + strtab_bias; } @@ -279,7 +279,7 @@ fn initAtoms( shdr.sh_type != elf.SHT_LLVM_ADDRSIG) continue; switch (shdr.sh_type) { - elf.SHT_GROUP => { + .GROUP => { if (shdr.sh_info >= self.symtab.items.len) { // TODO convert into an error log.debug("{}: invalid symbol index in sh_info", .{self.fmtPath()}); @@ -287,8 +287,8 @@ fn initAtoms( } const group_info_sym = self.symtab.items[shdr.sh_info]; const group_signature = blk: { - if (group_info_sym.st_name == 0 and group_info_sym.st_type() == elf.STT_SECTION) { - const sym_shdr = shdrs[group_info_sym.st_shndx]; + if (group_info_sym.st_name == 0 and group_info_sym.st_info.type == .SECTION) { + const sym_shdr = shdrs[group_info_sym.shndx()]; break :blk sym_shdr.sh_name; } break :blk group_info_sym.st_name; @@ -323,13 +323,13 @@ fn initAtoms( }; }, - elf.SHT_SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), + .SYMTAB_SHNDX => @panic("TODO SHT_SYMTAB_SHNDX"), - elf.SHT_NULL, - elf.SHT_REL, - elf.SHT_RELA, - elf.SHT_SYMTAB, - elf.SHT_STRTAB, + .NULL, + .REL, + .RELA, + .SYMTAB, + .STRTAB, => {}, else => { @@ -338,7 +338,7 @@ fn initAtoms( const size, const alignment = if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) blk: { const data = try self.preadShdrContentsAlloc(gpa, handle, shndx); defer gpa.free(data); - const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; + const chdr = @as(*align(1) const elf.elf64.Chdr, @ptrCast(data.ptr)).*; break :blk .{ chdr.ch_size, Alignment.fromNonzeroByteUnits(chdr.ch_addralign) }; } else .{ shdr.sh_size, Alignment.fromNonzeroByteUnits(shdr.sh_addralign) }; const atom_index = self.addAtomAssumeCapacity(.{ @@ -354,7 +354,7 @@ fn initAtoms( // Parse relocs sections if any. for (shdrs, 0..) |shdr, i| switch (shdr.sh_type) { - elf.SHT_REL, elf.SHT_RELA => { + .REL, .RELA => { const atom_index = self.atoms_indexes.items[shdr.sh_info]; if (self.atom(atom_index)) |atom_ptr| { const relocs = try self.preadRelocsAlloc(gpa, handle, @intCast(i)); @@ -408,10 +408,10 @@ fn initSymbols( sym_ptr.name_offset = sym.st_name; sym_ptr.esym_index = @intCast(i); sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{}); - sym_ptr.version_index = if (i >= first_global) default_sym_version else .LOCAL; - sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK; - if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) { - sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index }; + sym_ptr.version_index = if (i >= first_global) default_sym_version else .local; + sym_ptr.flags.weak = sym.st_info.bind == .WEAK; + if (sym.st_shndx != .ABS and sym.st_shndx != .COMMON) { + sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.shndx()], .file = self.index }; } } } @@ -424,7 +424,7 @@ fn parseEhFrame( target: std.Target, ) !void { const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { - elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), + .RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), else => {}, } else null; @@ -435,7 +435,7 @@ fn parseEhFrame( const relocs = if (relocs_shndx) |index| try self.preadRelocsAlloc(gpa, handle, index) else - &[0]elf.Elf64_Rela{}; + &[0]elf.elf64.Rela{}; defer gpa.free(relocs); const rel_start: u32 = @intCast(self.relocs.items.len); try self.relocs.appendUnalignedSlice(gpa, relocs); @@ -523,38 +523,38 @@ fn parseEhFrame( } } -fn sortRelocs(relocs: []elf.Elf64_Rela) void { +fn sortRelocs(relocs: []elf.elf64.Rela) void { const sortFn = struct { - fn lessThan(c: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { + fn lessThan(c: void, lhs: elf.elf64.Rela, rhs: elf.elf64.Rela) bool { _ = c; return lhs.r_offset < rhs.r_offset; } }.lessThan; - mem.sort(elf.Elf64_Rela, relocs, {}, sortFn); + mem.sort(elf.elf64.Rela, relocs, {}, sortFn); } fn filterRelocs( - relocs: []const elf.Elf64_Rela, + relocs: []const elf.elf64.Rela, start: u64, len: u64, ) struct { start: u64, len: u64 } { const Predicate = struct { value: u64, - pub fn predicate(self: @This(), rel: elf.Elf64_Rela) bool { + pub fn predicate(self: @This(), rel: elf.elf64.Rela) bool { return rel.r_offset < self.value; } }; const LPredicate = struct { value: u64, - pub fn predicate(self: @This(), rel: elf.Elf64_Rela) bool { + pub fn predicate(self: @This(), rel: elf.elf64.Rela) bool { return rel.r_offset >= self.value; } }; - const f_start = Elf.bsearch(elf.Elf64_Rela, relocs, Predicate{ .value = start }); - const f_len = Elf.lsearch(elf.Elf64_Rela, relocs[f_start..], LPredicate{ .value = start + len }); + const f_start = Elf.bsearch(elf.elf64.Rela, relocs, Predicate{ .value = start }); + const f_len = Elf.lsearch(elf.elf64.Rela, relocs[f_start..], LPredicate{ .value = start + len }); return .{ .start = f_start, .len = f_len }; } @@ -567,7 +567,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { if (!atom_ptr.alive) continue; const shdr = atom_ptr.inputShdr(elf_file); if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; - if (shdr.sh_type == elf.SHT_NOBITS) continue; + if (shdr.sh_type == .NOBITS) continue; if (atom_ptr.scanRelocsRequiresCode(elf_file)) { // TODO ideally, we don't have to decompress at this stage (should already be done) // and we just fetch the code slice. @@ -581,7 +581,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void { for (cie.relocs(elf_file)) |rel| { const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym(), elf_file)).?; if (sym.flags.import) { - if (sym.type(elf_file) != elf.STT_FUNC) + if (sym.type(elf_file) != .FUNC) // TODO convert into an error log.debug("{s}: {s}: CIE referencing external data reference", .{ self.fmtPath(), sym.name(elf_file), @@ -608,9 +608,9 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void { } resolv.* = gop.index; - if (esym.st_shndx == elf.SHN_UNDEF) continue; - if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) { - const atom_index = self.atoms_indexes.items[esym.st_shndx]; + if (esym.st_shndx == .UNDEF) continue; + if (esym.st_shndx != .ABS and esym.st_shndx != .COMMON) { + const atom_index = self.atoms_indexes.items[esym.shndx()]; const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; } @@ -630,7 +630,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { for (self.globals(), 0..) |*sym, i| { const esym_index = @as(u32, @intCast(first_global + i)); const esym = self.symtab.items[esym_index]; - if (esym.st_shndx != elf.SHN_UNDEF) continue; + if (esym.st_shndx != .UNDEF) continue; if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; const is_import = blk: { @@ -644,7 +644,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { sym.ref = .{ .index = 0, .file = 0 }; sym.esym_index = esym_index; sym.file_index = self.index; - sym.version_index = if (is_import) .LOCAL else elf_file.default_sym_version; + sym.version_index = if (is_import) .local else elf_file.default_sym_version; sym.flags.import = is_import; const idx = self.symbols_resolver.items[i]; @@ -657,7 +657,7 @@ pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void { for (self.globals(), 0..) |*sym, i| { const esym_index = @as(u32, @intCast(first_global + i)); const esym = self.symtab.items[esym_index]; - if (esym.st_shndx != elf.SHN_UNDEF) continue; + if (esym.st_shndx != .UNDEF) continue; if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue; sym.value = 0; @@ -675,13 +675,13 @@ pub fn markLive(self: *Object, elf_file: *Elf) void { for (0..self.globals().len) |i| { const esym_idx = first_global + i; const esym = self.symtab.items[esym_idx]; - if (esym.st_bind() == elf.STB_WEAK) continue; + if (esym.st_info.bind == .WEAK) continue; const ref = self.resolveSymbol(@intCast(esym_idx), elf_file); const sym = elf_file.symbol(ref) orelse continue; const file = sym.file(elf_file).?; - const should_keep = esym.st_shndx == elf.SHN_UNDEF or - (esym.st_shndx == elf.SHN_COMMON and sym.elfSym(elf_file).st_shndx != elf.SHN_COMMON); + const should_keep = esym.st_shndx == .UNDEF or + (esym.st_shndx == .COMMON and sym.elfSym(elf_file).st_shndx != .COMMON); if (should_keep and !file.isAlive()) { file.setAlive(); file.markLive(elf_file); @@ -693,7 +693,7 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void { const cpu_arch = elf_file.getTarget().cpu.arch; for (self.atoms_indexes.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; - const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == elf.SHT_X86_64_UNWIND) or + const is_eh_frame = (cpu_arch == .x86_64 and atom_ptr.inputShdr(elf_file).sh_type == .X86_64_UNWIND) or mem.eql(u8, atom_ptr.name(elf_file), ".eh_frame"); if (atom_ptr.alive and is_eh_frame) atom_ptr.alive = false; } @@ -733,12 +733,12 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutO const ref_file = ref_sym.file(elf_file).?; if (self.index == ref_file.index() or - esym.st_shndx == elf.SHN_UNDEF or - esym.st_bind() == elf.STB_WEAK or - esym.st_shndx == elf.SHN_COMMON) continue; + esym.st_shndx == .UNDEF or + esym.st_info.bind == .WEAK or + esym.st_shndx == .COMMON) continue; - if (esym.st_shndx != elf.SHN_ABS) { - const atom_index = self.atoms_indexes.items[esym.st_shndx]; + if (esym.st_shndx != .ABS) { + const atom_index = self.atoms_indexes.items[esym.shndx()]; const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.alive) continue; } @@ -881,9 +881,9 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ for (self.symtab.items, 0..) |*esym, idx| { const sym = &self.symbols.items[idx]; - if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue; + if (esym.st_shndx == .COMMON or esym.st_shndx == .UNDEF or esym.st_shndx == .ABS) continue; - const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx]; + const imsec_index = self.input_merge_sections_indexes.items[esym.shndx()]; const imsec = self.inputMergeSection(imsec_index) orelse continue; if (imsec.offsets.items.len == 0) continue; const res = imsec.findSubsection(@intCast(esym.st_value)) orelse { @@ -905,10 +905,10 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ const extras = atom_ptr.extra(elf_file); const relocs = self.relocs.items[extras.rel_index..][0..extras.rel_count]; for (relocs) |*rel| { - const esym = self.symtab.items[rel.r_sym()]; - if (esym.st_type() != elf.STT_SECTION) continue; + const esym = self.symtab.items[rel.r_info.sym]; + if (esym.st_info.type != .SECTION) continue; - const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx]; + const imsec_index = self.input_merge_sections_indexes.items[esym.shndx()]; const imsec = self.inputMergeSection(imsec_index) orelse continue; if (imsec.offsets.items.len == 0) continue; const msec = elf_file.mergeSection(imsec.merge_section_index); @@ -944,13 +944,13 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { for (self.globals(), self.symbols_resolver.items, 0..) |*sym, resolv, i| { const esym_idx = @as(u32, @intCast(first_global + i)); const esym = self.symtab.items[esym_idx]; - if (esym.st_shndx != elf.SHN_COMMON) continue; + if (esym.st_shndx != .COMMON) continue; if (elf_file.resolver.get(resolv).?.file != self.index) continue; const comp = elf_file.base.comp; const gpa = comp.gpa; - const is_tls = sym.type(elf_file) == elf.STT_TLS; + const is_tls = sym.type(elf_file) == .TLS; const name = if (is_tls) ".tls_common" else ".common"; const name_offset = @as(u32, @intCast(self.strtab.items.len)); try self.strtab.writer(gpa).print("{s}\x00", .{name}); @@ -962,7 +962,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void { const sh_size = math.cast(usize, esym.st_size) orelse return error.Overflow; shdr.* = .{ .sh_name = name_offset, - .sh_type = elf.SHT_NOBITS, + .sh_type = .NOBITS, .sh_flags = sh_flags, .sh_addr = 0, .sh_offset = 0, @@ -1048,8 +1048,8 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { }); const out_shdr = &elf_file.sections.items(.shdr)[out_shndx]; out_shdr.sh_type = elf.SHT_RELA; - out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela); - out_shdr.sh_entsize = @sizeOf(elf.Elf64_Rela); + out_shdr.sh_addralign = @alignOf(elf.elf64.Rela); + out_shdr.sh_entsize = @sizeOf(elf.elf64.Rela); out_shdr.sh_flags |= elf.SHF_INFO_LINK; } } @@ -1086,7 +1086,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.symtab.items.len - start); for (self.symtab.items[start..]) |sym| { - if (sym.st_shndx == elf.SHN_UNDEF) continue; + if (sym.st_shndx == .UNDEF) continue; const off = try ar_symtab.strtab.insert(gpa, self.getString(sym.st_name)); ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index }); } @@ -1132,9 +1132,9 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void { for (self.locals()) |*local| { if (!isAlive(local, elf_file)) continue; const esym = local.elfSym(elf_file); - switch (esym.st_type()) { - elf.STT_SECTION => continue, - elf.STT_NOTYPE => if (esym.st_shndx == elf.SHN_UNDEF) continue, + switch (esym.st_info.type) { + .SECTION => continue, + .NOTYPE => if (esym.st_shndx == .UNDEF) continue, else => {}, } local.flags.output_symtab = true; @@ -1196,10 +1196,10 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index defer if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) gpa.free(data); if (shdr.sh_flags & elf.SHF_COMPRESSED != 0) { - const chdr = @as(*align(1) const elf.Elf64_Chdr, @ptrCast(data.ptr)).*; + const chdr = @as(*align(1) const elf.elf64.Chdr, @ptrCast(data.ptr)).*; switch (chdr.ch_type) { .ZLIB => { - var stream = std.io.fixedBufferStream(data[@sizeOf(elf.Elf64_Chdr)..]); + var stream = std.io.fixedBufferStream(data[@sizeOf(elf.elf64.Chdr)..]); var zlib_stream = std.compress.zlib.decompressor(stream.reader()); const size = std.math.cast(usize, chdr.ch_size) orelse return error.Overflow; const decomp = try gpa.alloc(u8, size); @@ -1319,10 +1319,10 @@ fn preadShdrContentsAlloc(self: Object, gpa: Allocator, handle: fs.File, index: } /// Caller owns the memory. -fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: fs.File, shndx: u32) ![]align(1) const elf.Elf64_Rela { +fn preadRelocsAlloc(self: Object, gpa: Allocator, handle: fs.File, shndx: u32) ![]align(1) const elf.elf64.Rela { const raw = try self.preadShdrContentsAlloc(gpa, handle, shndx); - const num = @divExact(raw.len, @sizeOf(elf.Elf64_Rela)); - return @as([*]align(1) const elf.Elf64_Rela, @ptrCast(raw.ptr))[0..num]; + const num = @divExact(raw.len, @sizeOf(elf.elf64.Rela)); + return @as([*]align(1) const elf.elf64.Rela, @ptrCast(raw.ptr))[0..num]; } const AddAtomArgs = struct { diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index ac3b3857a1c9..c3cbe20080e6 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -25,11 +25,11 @@ pub fn deinit(so: *SharedObject, gpa: Allocator) void { } pub const Header = struct { - dynamic_table: []const elf.Elf64_Dyn, + dynamic_table: []const elf.elf64.Dyn, soname_index: ?u32, verdefnum: ?u32, - sections: []const elf.Elf64_Shdr, + sections: []const elf.elf64.Shdr, dynsym_sect_index: ?u32, versym_sect_index: ?u32, verdef_sect_index: ?u32, @@ -54,10 +54,10 @@ pub const Parsed = struct { stat: Stat, strtab: []const u8, soname_index: ?u32, - sections: []const elf.Elf64_Shdr, + sections: []const elf.elf64.Shdr, /// Nonlocal symbols only. - symtab: []const elf.Elf64_Sym, + symtab: []const elf.elf64.Sym, /// Version symtab contains version strings of the symbols if present. /// Nonlocal symbols only. versyms: []const elf.Versym, @@ -98,14 +98,14 @@ pub fn parseHeader( stat: Stat, target: std.Target, ) !Header { - var ehdr: elf.Elf64_Ehdr = undefined; + var ehdr: elf.elf64.Ehdr = undefined; { const buf = mem.asBytes(&ehdr); const amt = try fs_file.preadAll(buf, 0); if (amt != buf.len) return error.UnexpectedEndOfFile; } if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic; - if (ehdr.e_ident[elf.EI_VERSION] != 1) return error.BadElfVersion; + if (ehdr.e_ident.ei_version != .CURRENT) return error.BadElfVersion; if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject; if (target.toElfMachine() != ehdr.e_machine) @@ -114,7 +114,7 @@ pub fn parseHeader( const shoff = std.math.cast(usize, ehdr.e_shoff) orelse return error.Overflow; const shnum = std.math.cast(u32, ehdr.e_shnum) orelse return error.Overflow; - const sections = try gpa.alloc(elf.Elf64_Shdr, shnum); + const sections = try gpa.alloc(elf.elf64.Shdr, shnum); errdefer gpa.free(sections); { const buf = mem.sliceAsBytes(sections); @@ -129,18 +129,18 @@ pub fn parseHeader( for (sections, 0..) |shdr, i_usize| { const i: u32 = @intCast(i_usize); switch (shdr.sh_type) { - elf.SHT_DYNSYM => dynsym_sect_index = i, - elf.SHT_DYNAMIC => dynamic_sect_index = i, - elf.SHT_GNU_VERSYM => versym_sect_index = i, - elf.SHT_GNU_VERDEF => verdef_sect_index = i, + .DYNSYM => dynsym_sect_index = i, + .DYNAMIC => dynamic_sect_index = i, + .GNU_VERSYM => versym_sect_index = i, + .GNU_VERDEF => verdef_sect_index = i, else => continue, } } - const dynamic_table: []elf.Elf64_Dyn = if (dynamic_sect_index) |index| dt: { + const dynamic_table: []elf.elf64.Dyn = if (dynamic_sect_index) |index| dt: { const shdr = sections[index]; - const n = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.Elf64_Dyn)) orelse return error.Overflow; - const dynamic_table = try gpa.alloc(elf.Elf64_Dyn, n); + const n = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.elf64.Dyn)) orelse return error.Overflow; + const dynamic_table = try gpa.alloc(elf.elf64.Dyn, n); errdefer gpa.free(dynamic_table); const buf = mem.sliceAsBytes(dynamic_table); const amt = try fs_file.preadAll(buf, shdr.sh_offset); @@ -165,11 +165,11 @@ pub fn parseHeader( var soname_index: ?u32 = null; var verdefnum: ?u32 = null; for (dynamic_table) |entry| switch (entry.d_tag) { - elf.DT_SONAME => { + .SONAME => { if (entry.d_val >= strtab.items.len) return error.BadSonameIndex; soname_index = @intCast(entry.d_val); }, - elf.DT_VERDEFNUM => { + .VERDEFNUM => { verdefnum = @intCast(entry.d_val); }, else => continue, @@ -196,8 +196,8 @@ pub fn parse( ) !Parsed { const symtab = if (header.dynsym_sect_index) |index| st: { const shdr = header.sections[index]; - const n = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.Elf64_Sym)) orelse return error.Overflow; - const symtab = try gpa.alloc(elf.Elf64_Sym, n); + const n = std.math.cast(usize, shdr.sh_size / @sizeOf(elf.elf64.Sym)) orelse return error.Overflow; + const symtab = try gpa.alloc(elf.elf64.Sym, n); errdefer gpa.free(symtab); const buf = mem.sliceAsBytes(symtab); const amt = try fs_file.preadAll(buf, shdr.sh_offset); @@ -243,7 +243,7 @@ pub fn parse( } else &.{}; defer gpa.free(versyms); - var nonlocal_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .empty; + var nonlocal_esyms: std.ArrayListUnmanaged(elf.elf64.Sym) = .empty; defer nonlocal_esyms.deinit(gpa); var nonlocal_versyms: std.ArrayListUnmanaged(elf.Versym) = .empty; @@ -257,21 +257,19 @@ pub fn parse( defer strtab.deinit(gpa); for (symtab, 0..) |sym, i| { - const ver: elf.Versym = if (versyms.len == 0 or sym.st_shndx == elf.SHN_UNDEF) - .GLOBAL + const ver: elf.Versym = if (versyms.len == 0 or sym.st_shndx == .UNDEF) + .global else - .{ .VERSION = versyms[i].VERSION, .HIDDEN = false }; + .{ .version = versyms[i].version, .hidden = false }; - // https://github.com/ziglang/zig/issues/21678 - //if (ver == .LOCAL) continue; - if (@as(u16, @bitCast(ver)) == 0) continue; + if (ver == .local) continue; try nonlocal_esyms.ensureUnusedCapacity(gpa, 1); try nonlocal_versyms.ensureUnusedCapacity(gpa, 1); try nonlocal_symbols.ensureUnusedCapacity(gpa, 1); const name = Elf.stringTableLookup(strtab.items, sym.st_name); - const is_default = versyms.len == 0 or !versyms[i].HIDDEN; + const is_default = versyms.len == 0 or !versyms[i].hidden; const mangled_name = if (is_default) sym.st_name else mn: { const off: u32 = @intCast(strtab.items.len); const version_string = versionStringLookup(strtab.items, verstrings.items, versyms[i]); @@ -322,7 +320,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void { } resolv.* = gop.index; - if (esym.st_shndx == elf.SHN_UNDEF) continue; + if (esym.st_shndx == .UNDEF) continue; if (elf_file.symbol(gop.ref.*) == null) { gop.ref.* = .{ .index = @intCast(i), .file = self.index }; continue; @@ -336,7 +334,7 @@ pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void { pub fn markLive(self: *SharedObject, elf_file: *Elf) void { for (self.parsed.symtab, 0..) |esym, i| { - if (esym.st_shndx != elf.SHN_UNDEF) continue; + if (esym.st_shndx != .UNDEF) continue; const ref = self.resolveSymbol(@intCast(i), elf_file); const sym = elf_file.symbol(ref) orelse continue; @@ -395,7 +393,7 @@ pub fn versionString(self: SharedObject, index: elf.Versym) [:0]const u8 { } fn versionStringLookup(strtab: []const u8, verstrings: []const u32, index: elf.Versym) [:0]const u8 { - const off = verstrings[index.VERSION]; + const off = verstrings[index.version]; return Elf.stringTableLookup(strtab, off); } diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 31584ca406ce..ec8cf87966d8 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -14,7 +14,7 @@ file_index: File.Index = 0, ref: Elf.Ref = .{}, /// Assigned output section index for this symbol. -output_section_index: u32 = 0, +output_section_index: elf.SHN = .UNDEF, /// Index of the source symbol this symbol references. /// Use `elfSym` to pull the source symbol from the relevant file. @@ -22,7 +22,7 @@ esym_index: Index = 0, /// Index of the source version symbol this symbol references if any. /// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL. -version_index: elf.Versym = .LOCAL, +version_index: elf.Versym = .local, /// Misc flags for the symbol packaged as packed struct for compression. flags: Flags = .{}, @@ -31,35 +31,35 @@ extra_index: u32 = 0, pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool { const file_ptr = symbol.file(elf_file).?; - if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == elf.SHN_ABS; + if (file_ptr == .shared_object) return symbol.elfSym(elf_file).st_shndx == .ABS; return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.mergeSubsection(elf_file) == null and symbol.outputShndx(elf_file) == null and file_ptr != .linker_defined; } -pub fn outputShndx(symbol: Symbol, elf_file: *Elf) ?u32 { +pub fn outputShndx(symbol: Symbol, elf_file: *Elf) ?elf.SHN { if (symbol.mergeSubsection(elf_file)) |msub| return if (msub.alive) msub.mergeSection(elf_file).output_section_index else null; if (symbol.atom(elf_file)) |atom_ptr| return if (atom_ptr.alive) atom_ptr.output_section_index else null; - if (symbol.output_section_index == 0) return null; + if (symbol.output_section_index == .UNDEF) return null; return symbol.output_section_index; } pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool { - if (elf_file.base.isRelocatable()) return symbol.elfSym(elf_file).st_bind() == elf.STB_LOCAL; + if (elf_file.base.isRelocatable()) return symbol.elfSym(elf_file).st_info.bind == .LOCAL; return !(symbol.flags.import or symbol.flags.@"export"); } pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool { - return symbol.type(elf_file) == elf.STT_GNU_IFUNC; + return symbol.type(elf_file) == .GNU_IFUNC; } -pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 { +pub fn @"type"(symbol: Symbol, elf_file: *Elf) elf.STT { const esym = symbol.elfSym(elf_file); const file_ptr = symbol.file(elf_file).?; - if (esym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared_object) return elf.STT_FUNC; - return esym.st_type(); + if (esym.st_info.type == .GNU_IFUNC and file_ptr == .shared_object) return .FUNC; + return esym.st_info.type; } pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 { @@ -84,7 +84,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File { return elf_file.file(symbol.file_index); } -pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym { +pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.elf64.Sym { return switch (symbol.file(elf_file).?) { .zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index], .shared_object => |so| so.parsed.symtab[symbol.esym_index], @@ -136,7 +136,7 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true, trampoline: bool if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or mem.startsWith(u8, sym_name, ".eh_frame_seg") or - symbol.elfSym(elf_file).st_type() == elf.STT_SECTION) + symbol.elfSym(elf_file).st_info.type == .SECTION) { return @intCast(sh_addr); } @@ -283,33 +283,33 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { const file_ptr = symbol.file(elf_file).?; const esym = symbol.elfSym(elf_file); const st_type = symbol.type(elf_file); - const st_bind: u8 = blk: { + const st_bind: elf.STB = blk: { if (symbol.isLocal(elf_file)) break :blk 0; - if (symbol.flags.weak) break :blk elf.STB_WEAK; - if (file_ptr == .shared_object) break :blk elf.STB_GLOBAL; - break :blk esym.st_bind(); + if (symbol.flags.weak) break :blk .WEAK; + if (file_ptr == .shared_object) break :blk .GLOBAL; + break :blk esym.st_info.bind; }; - const st_shndx: u16 = blk: { + const st_shndx: elf.SHN = blk: { if (symbol.flags.has_copy_rel) break :blk @intCast(elf_file.section_indexes.copy_rel.?); - if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF; - if (elf_file.base.isRelocatable() and esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON; + if (file_ptr == .shared_object or esym.st_shndx == .UNDEF) break :blk .UNDEF; + if (elf_file.base.isRelocatable() and esym.st_shndx == .COMMON) break :blk .COMMON; if (symbol.mergeSubsection(elf_file)) |msub| break :blk @intCast(msub.mergeSection(elf_file).output_section_index); - if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk elf.SHN_ABS; - break :blk @intCast(symbol.outputShndx(elf_file) orelse elf.SHN_UNDEF); + if (symbol.atom(elf_file) == null and file_ptr != .linker_defined) break :blk .ABS; + break :blk @intCast(symbol.outputShndx(elf_file) orelse .UNDEF); }; const st_value = blk: { if (symbol.flags.has_copy_rel) break :blk symbol.address(.{}, elf_file); - if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) { + if (file_ptr == .shared_object or esym.st_shndx == .UNDEF) { if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file); break :blk 0; } - if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false }, elf_file); + if (st_shndx == .ABS or st_shndx == .COMMON) break :blk symbol.address(.{ .plt = false }, elf_file); const shdr = elf_file.sections.items(.shdr)[st_shndx]; if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress(); break :blk symbol.address(.{ .plt = false, .trampoline = false }, elf_file); }; - out.st_info = (st_bind << 4) | st_type; + out.st_info = .{ .type = st_type, .bind = st_bind }; out.st_other = esym.st_other; out.st_shndx = st_shndx; out.st_value = @intCast(st_value); @@ -352,8 +352,8 @@ fn formatName( const elf_file = ctx.elf_file; const symbol = ctx.symbol; try writer.writeAll(symbol.name(elf_file)); - switch (symbol.version_index.VERSION) { - @intFromEnum(elf.VER_NDX.LOCAL), @intFromEnum(elf.VER_NDX.GLOBAL) => {}, + switch (symbol.version_index) { + .local, .global => {}, else => { const file_ptr = symbol.file(elf_file).?; assert(file_ptr == .shared_object); @@ -387,7 +387,7 @@ fn format2( }); if (symbol.file(elf_file)) |file_ptr| { if (symbol.isAbs(elf_file)) { - if (symbol.elfSym(elf_file).st_shndx == elf.SHN_UNDEF) { + if (symbol.elfSym(elf_file).st_shndx == .UNDEF) { try writer.writeAll(" : undef"); } else { try writer.writeAll(" : absolute"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 86abc5e7ae38..46a2f4be708d 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -20,7 +20,7 @@ globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty, atoms: std.ArrayListUnmanaged(Atom) = .empty, atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .empty, atoms_extra: std.ArrayListUnmanaged(u32) = .empty, -relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .empty, +relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.elf64.Rela)) = .empty, num_dynrelocs: u32 = 0, @@ -92,8 +92,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { const symbol_index = try self.newLocalSymbol(gpa, name_off); const sym = self.symbol(symbol_index); const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; - esym.st_info = elf.STT_FILE; - esym.st_shndx = elf.SHN_ABS; + esym.st_info = .FILE; + esym.st_shndx = .ABS; } switch (comp.config.debug_format) { diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index bf46fb02621d..25773f2b96cc 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -43,7 +43,7 @@ pub const Fde = struct { return object.atom(atom_index).?; } - pub fn relocs(fde: Fde, object: *Object) []const elf.Elf64_Rela { + pub fn relocs(fde: Fde, object: *Object) []const elf.elf64.Rela { return object.relocs.items[fde.rel_index..][0..fde.rel_num]; } @@ -124,7 +124,7 @@ pub const Cie = struct { return cie.size + 4; } - pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.Elf64_Rela { + pub fn relocs(cie: Cie, elf_file: *Elf) []align(1) const elf.elf64.Rela { const object = elf_file.file(cie.file_index).?.object; return object.relocs.items[cie.rel_index..][0..cie.rel_num]; } @@ -138,13 +138,13 @@ pub const Cie = struct { for (cie_relocs, other_relocs) |cie_rel, other_rel| { if (cie_rel.r_offset - cie.offset != other_rel.r_offset - other.offset) return false; - if (cie_rel.r_type() != other_rel.r_type()) return false; + if (cie_rel.r_info.type != other_rel.r_info.type) return false; if (cie_rel.r_addend != other_rel.r_addend) return false; const cie_object = elf_file.file(cie.file_index).?.object; - const cie_ref = cie_object.resolveSymbol(cie_rel.r_sym(), elf_file); + const cie_ref = cie_object.resolveSymbol(cie_rel.r_info.sym, elf_file); const other_object = elf_file.file(other.file_index).?.object; - const other_ref = other_object.resolveSymbol(other_rel.r_sym(), elf_file); + const other_ref = other_object.resolveSymbol(other_rel.r_info.sym, elf_file); if (!cie_ref.eql(other_ref)) return false; } return true; @@ -309,7 +309,7 @@ pub fn calcEhFrameRelocs(elf_file: *Elf) usize { return count; } -fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void { +fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.elf64.Rela, elf_file: *Elf, contents: []u8) !void { const cpu_arch = elf_file.getTarget().cpu.arch; const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow; const P = math.cast(i64, rec.address(elf_file) + offset) orelse return error.Overflow; @@ -317,7 +317,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: const A = rel.r_addend; relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{ - relocation.fmtRelocType(rel.r_type(), cpu_arch), + relocation.fmtRelocType(rel.r_info.type, cpu_arch), offset, P, S + A, @@ -348,7 +348,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { const contents = cie.data(elf_file); for (cie.relocs(elf_file)) |rel| { - const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const ref = object.resolveSymbol(rel.r_info.sym, elf_file); const sym = elf_file.symbol(ref).?; resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, @@ -376,7 +376,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { ); for (fde.relocs(object)) |rel| { - const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const ref = object.resolveSymbol(rel.r_info.sym, elf_file); const sym = elf_file.symbol(ref).?; resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, @@ -423,13 +423,13 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void { } } -fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { +fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.elf64.Rela) elf.elf64.Rela { const cpu_arch = elf_file.getTarget().cpu.arch; - const r_type = rel.r_type(); + const r_type = rel.r_info.type; var r_addend = rel.r_addend; var r_sym: u32 = 0; switch (sym.type(elf_file)) { - elf.STT_SECTION => { + .SECTION => { r_addend += @intCast(sym.address(.{}, elf_file)); r_sym = sym.outputShndx(elf_file).?; }, @@ -449,11 +449,11 @@ fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_R return .{ .r_offset = r_offset, .r_addend = r_addend, - .r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type, + .r_info = .{ .type = r_type, .sym = r_sym }, }; } -pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela)) !void { +pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.elf64.Rela)) !void { relocs_log.debug("{x}: .eh_frame", .{ elf_file.sections.items(.shdr)[elf_file.section_indexes.eh_frame.?].sh_addr, }); @@ -464,7 +464,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela) const atom_ptr = zo.atom(sym.ref.index).?; if (!atom_ptr.alive) break :zo; for (atom_ptr.relocs(elf_file)) |rel| { - const ref = zo.resolveSymbol(rel.r_sym(), elf_file); + const ref = zo.resolveSymbol(rel.r_info.sym, elf_file); const target = elf_file.symbol(ref).?; try relocs.append(emitReloc(elf_file, rel.r_offset, target, rel)); } @@ -476,7 +476,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela) for (object.cies.items) |cie| { if (!cie.alive) continue; for (cie.relocs(elf_file)) |rel| { - const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const ref = object.resolveSymbol(rel.r_info.sym, elf_file); const sym = elf_file.symbol(ref).?; const r_offset = cie.address(elf_file) + rel.r_offset - cie.offset; try relocs.append(emitReloc(elf_file, r_offset, sym, rel)); @@ -486,7 +486,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, relocs: *std.ArrayList(elf.Elf64_Rela) for (object.fdes.items) |fde| { if (!fde.alive) continue; for (fde.relocs(object)) |rel| { - const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const ref = object.resolveSymbol(rel.r_info.sym, elf_file); const sym = elf_file.symbol(ref).?; const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset; try relocs.append(emitReloc(elf_file, r_offset, sym, rel)); @@ -545,7 +545,7 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { const relocs = fde.relocs(object); assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips... const rel = relocs[0]; - const ref = object.resolveSymbol(rel.r_sym(), elf_file); + const ref = object.resolveSymbol(rel.r_info.sym, elf_file); const sym = elf_file.symbol(ref).?; const P = @as(i64, @intCast(fde.address(elf_file))); const S = @as(i64, @intCast(sym.address(.{}, elf_file))); @@ -567,8 +567,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { const eh_frame_hdr_header_size: usize = 12; const x86_64 = struct { - fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void { - const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); + fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.elf64.Rela, source: i64, target: i64, data: []u8) !void { + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_info.type); switch (r_type) { .NONE => {}, .@"32" => std.mem.writeInt(i32, data[0..4], @as(i32, @truncate(target)), .little), @@ -581,8 +581,8 @@ const x86_64 = struct { }; const aarch64 = struct { - fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void { - const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.elf64.Rela, source: i64, target: i64, data: []u8) !void { + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_info.type); switch (r_type) { .NONE => {}, .ABS64 => std.mem.writeInt(i64, data[0..8], target, .little), @@ -594,8 +594,8 @@ const aarch64 = struct { }; const riscv = struct { - fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void { - const r_type: elf.R_RISCV = @enumFromInt(rel.r_type()); + fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.elf64.Rela, source: i64, target: i64, data: []u8) !void { + const r_type: elf.R_RISCV = @enumFromInt(rel.r_info.type); switch (r_type) { .NONE => {}, .@"32_PCREL" => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little), @@ -604,11 +604,11 @@ const riscv = struct { } }; -fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void { +fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.elf64.Rela) !void { const diags = &elf_file.base.comp.link_diags; var err = try diags.addErrorWithNotes(1); try err.addMsg("invalid relocation type {} at offset 0x{x}", .{ - relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch), + relocation.fmtRelocType(rel.r_info.type, elf_file.getTarget().cpu.arch), rel.r_offset, }); err.addNote("in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()}); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 836484601929..256c4d3875c2 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -99,129 +99,129 @@ pub const DynamicSection = struct { // NEEDED for (dt.needed.items) |off| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .NEEDED, .d_val = off }); } if (dt.soname) |off| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .SONAME, .d_val = off }); } // RUNPATH // TODO add option in Options to revert to old RPATH tag if (dt.rpath > 0) { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .RUNPATH, .d_val = dt.rpath }); } // INIT if (elf_file.sectionByName(".init")) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .INIT, .d_val = addr }); } // FINI if (elf_file.sectionByName(".fini")) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .FINI, .d_val = addr }); } // INIT_ARRAY if (elf_file.sectionByName(".init_array")) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .INIT_ARRAY, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .INIT_ARRAYSZ, .d_val = shdr.sh_size }); } // FINI_ARRAY if (elf_file.sectionByName(".fini_array")) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .FINI_ARRAY, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .FINI_ARRAYSZ, .d_val = shdr.sh_size }); } // RELA if (elf_file.section_indexes.rela_dyn) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .RELA, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .RELASZ, .d_val = shdr.sh_size }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .RELAENT, .d_val = shdr.sh_entsize }); } // JMPREL if (elf_file.section_indexes.rela_plt) |shndx| { const shdr = shdrs[shndx]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .JMPREL, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .PLTRELSZ, .d_val = shdr.sh_size }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .PLTREL, .d_val = @intCast(@intFromEnum(elf.elf64.DT.RELA)) }); } // PLTGOT if (elf_file.section_indexes.got_plt) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .PLTGOT, .d_val = addr }); } { assert(elf_file.section_indexes.hash != null); const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .HASH, .d_val = addr }); } if (elf_file.section_indexes.gnu_hash) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .GNU_HASH, .d_val = addr }); } // TEXTREL if (elf_file.has_text_reloc) { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .TEXTREL, .d_val = 0 }); } // SYMTAB + SYMENT { assert(elf_file.section_indexes.dynsymtab != null); const shdr = shdrs[elf_file.section_indexes.dynsymtab.?]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .SYMTAB, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .SYMENT, .d_val = shdr.sh_entsize }); } // STRTAB + STRSZ { assert(elf_file.section_indexes.dynstrtab != null); const shdr = shdrs[elf_file.section_indexes.dynstrtab.?]; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }); - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .STRTAB, .d_val = shdr.sh_addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .STRSZ, .d_val = shdr.sh_size }); } // VERSYM if (elf_file.section_indexes.versym) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .VERSYM, .d_val = addr }); } // VERNEED + VERNEEDNUM if (elf_file.section_indexes.verneed) |shndx| { const addr = shdrs[shndx].sh_addr; - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr }); - try writer.writeStruct(elf.Elf64_Dyn{ - .d_tag = elf.DT_VERNEEDNUM, + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .VERNEED, .d_val = addr }); + try writer.writeStruct(elf.elf64.Dyn{ + .d_tag = .VERNEEDNUM, .d_val = elf_file.verneed.verneed.items.len, }); } // FLAGS if (dt.getFlags(elf_file)) |flags| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .FLAGS, .d_val = flags }); } // FLAGS_1 if (dt.getFlags1(elf_file)) |flags_1| { - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .FLAGS_1, .d_val = flags_1 }); } // DEBUG - if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 }); + if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .DEBUG, .d_val = 0 }); // NULL - try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 }); + try writer.writeStruct(elf.elf64.Dyn{ .d_tag = .NULL, .d_val = 0 }); } }; diff --git a/test/standalone/pie/main.zig b/test/standalone/pie/main.zig index edf6a3fcaae8..aecd25db5d8f 100644 --- a/test/standalone/pie/main.zig +++ b/test/standalone/pie/main.zig @@ -5,7 +5,7 @@ threadlocal var foo: u8 = 42; test "Check ELF header" { // PIE executables are marked as ET_DYN, regular exes as ET_EXEC. - const header = @as(*elf.Ehdr, @ptrFromInt(std.process.getBaseAddress())); + const header = @as(*elf.native_elf.Ehdr, @ptrFromInt(std.process.getBaseAddress())); try std.testing.expectEqual(elf.ET.DYN, header.e_type); } diff --git a/tools/gen_stubs.zig b/tools/gen_stubs.zig index 31095399d3ac..6d2fa7b961a4 100644 --- a/tools/gen_stubs.zig +++ b/tools/gen_stubs.zig @@ -151,9 +151,9 @@ const arches: [@typeInfo(Arch).@"enum".fields.len]Arch = blk: { const MultiSym = struct { size: [arches.len]u64, present: [arches.len]bool, - binding: [arches.len]u4, + binding: [arches.len]elf.STB, section: u16, - ty: u4, + ty: elf.STT, visib: elf.STV, fn isSingleArch(ms: MultiSym) ?Arch { @@ -215,7 +215,7 @@ const MultiSym = struct { return size.?; } - fn commonBinding(ms: MultiSym) ?u4 { + fn commonBinding(ms: MultiSym) ?elf.STB { var binding: ?u4 = null; for (arches, 0..) |_, i| { if (!ms.present[i]) continue; @@ -245,9 +245,9 @@ const MultiSym = struct { inline for (@typeInfo(Arch).@"enum".fields) |field| { const arch: Arch = @enumFromInt(field.value); const arch_index = archIndex(arch); - const binding: u4 = switch (arch.ptrSize()) { - 4 => std.elf.STB_GLOBAL, - 8 => std.elf.STB_WEAK, + const binding: elf.STB = switch (arch.ptrSize()) { + 4 => .GLOBAL, + 8 => .WEAK, else => unreachable, }; if (ms.present[arch_index] and ms.binding[arch_index] != binding) { @@ -261,7 +261,7 @@ const MultiSym = struct { inline for (@typeInfo(Arch).@"enum".fields) |field| { const arch: Arch = @enumFromInt(field.value); const arch_index = archIndex(arch); - const binding: u4 = if (arch.isTime32()) std.elf.STB_GLOBAL else std.elf.STB_WEAK; + const binding: elf.STB = if (arch.isTime32()) .GLOBAL else .WEAK; if (ms.present[arch_index] and ms.binding[arch_index] != binding) { return false; } @@ -274,7 +274,7 @@ const Parse = struct { arena: mem.Allocator, sym_table: *std.StringArrayHashMap(MultiSym), sections: *std.StringArrayHashMap(void), - elf_bytes: []align(@alignOf(elf.Elf64_Ehdr)) u8, + elf_bytes: []align(@alignOf(elf.elf64.Ehdr)) u8, header: elf.Header, arch: Arch, }; @@ -303,14 +303,14 @@ pub fn main() !void { libc_so_path, 100 * 1024 * 1024, 1 * 1024 * 1024, - @alignOf(elf.Elf64_Ehdr), + @alignOf(elf.elf64.Ehdr), null, ) catch |err| { std.debug.panic("unable to read '{s}/{s}': {s}", .{ build_all_path, libc_so_path, @errorName(err), }); }; - const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]); + const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.elf64.Ehdr)]); const parse: Parse = .{ .arena = arena, @@ -474,10 +474,10 @@ pub fn main() !void { if (multi_sym.commonBinding()) |binding| { switch (binding) { - elf.STB_GLOBAL => { + .GLOBAL => { try stdout.print(".globl {s}\n", .{name}); }, - elf.STB_WEAK => { + .WEAK => { try stdout.print(".weak {s}\n", .{name}); }, else => unreachable, @@ -495,12 +495,12 @@ pub fn main() !void { } switch (multi_sym.ty) { - elf.STT_NOTYPE => {}, - elf.STT_FUNC => { + .NOTYPE => {}, + .FUNC => { try stdout.print(".type {s}, %function;\n", .{name}); // omitting the size is OK for functions }, - elf.STT_OBJECT => { + .OBJECT => { try stdout.print(".type {s}, %object;\n", .{name}); if (multi_sym.commonSize()) |size| { try stdout.print(".size {s}, {d}\n", .{ name, size }); @@ -536,10 +536,10 @@ pub fn main() !void { } fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) !void { + const native_elf = if (is_64) elf.elf64 else elf.elf32; const arena = parse.arena; const elf_bytes = parse.elf_bytes; const header = parse.header; - const Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym; const S = struct { fn endianSwap(x: anytype) @TypeOf(x) { if (endian != native_endian) { @@ -548,7 +548,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) return x; } } - fn symbolAddrLessThan(_: void, lhs: Sym, rhs: Sym) bool { + fn symbolAddrLessThan(_: void, lhs: native_elf.Sym, rhs: native_elf.Sym) bool { return endianSwap(lhs.st_value) < endianSwap(rhs.st_value); } }; @@ -556,8 +556,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) const s = S.endianSwap; // Obtain list of sections. - const Shdr = if (is_64) elf.Elf64_Shdr else elf.Elf32_Shdr; - const shdrs = mem.bytesAsSlice(Shdr, elf_bytes[header.shoff..])[0..header.shnum]; + const shdrs = mem.bytesAsSlice(native_elf.Shdr, elf_bytes[header.shoff..])[0..header.shnum]; // Obtain the section header string table. const shstrtab_offset = s(shdrs[header.shstrndx].sh_offset); @@ -585,7 +584,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) // Read the dynamic symbols into a list. const dyn_syms_off = s(shdrs[dynsym_index].sh_offset); const dyn_syms_size = s(shdrs[dynsym_index].sh_size); - const dyn_syms = mem.bytesAsSlice(Sym, elf_bytes[dyn_syms_off..][0..dyn_syms_size]); + const dyn_syms = mem.bytesAsSlice(native_elf.Sym, elf_bytes[dyn_syms_off..][0..dyn_syms_size]); const dynstr_offset = s(shdrs[s(shdrs[dynsym_index].sh_link)].sh_offset); const dynstr = elf_bytes[dynstr_offset..]; @@ -593,17 +592,17 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) // Sort the list by address, ascending. // We need a copy to fix alignment. const copied_dyn_syms = copy: { - const ptr = try arena.alloc(Sym, dyn_syms.len); + const ptr = try arena.alloc(native_elf.Sym, dyn_syms.len); @memcpy(ptr, dyn_syms); break :copy ptr; }; - mem.sort(Sym, copied_dyn_syms, {}, S.symbolAddrLessThan); + mem.sort(native_elf.Sym, copied_dyn_syms, {}, S.symbolAddrLessThan); for (copied_dyn_syms) |sym| { const this_section = s(sym.st_shndx); const name = try arena.dupe(u8, mem.sliceTo(dynstr[s(sym.st_name)..], 0)); - const ty = @as(u4, @truncate(sym.st_info)); - const binding = @as(u4, @truncate(sym.st_info >> 4)); + const ty = sym.st_info.type; + const binding = sym.st_info.bind; const visib = @as(elf.STV, @enumFromInt(@as(u2, @truncate(sym.st_other)))); const size = s(sym.st_size); @@ -611,7 +610,7 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) log.warn("{s}: symbol '{s}' has size 0", .{ @tagName(parse.arch), name }); } - if (sym.st_shndx == elf.SHN_UNDEF) { + if (sym.st_shndx == .UNDEF) { log.debug("{s}: skipping '{s}' due to it being undefined", .{ @tagName(parse.arch), name, }); @@ -619,20 +618,20 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) } switch (binding) { - elf.STB_GLOBAL, elf.STB_WEAK => {}, + .GLOBAL, .WEAK => {}, else => { - log.debug("{s}: skipping '{s}' due to it having binding '{d}'", .{ - @tagName(parse.arch), name, binding, + log.debug("{s}: skipping '{s}' due to it having binding '{s}'", .{ + @tagName(parse.arch), name, @tagName(binding), }); continue; }, } switch (ty) { - elf.STT_NOTYPE, elf.STT_FUNC, elf.STT_OBJECT => {}, + .NOTYPE, .FUNC, .OBJECT => {}, else => { - log.debug("{s}: skipping '{s}' due to it having type '{d}'", .{ - @tagName(parse.arch), name, ty, + log.debug("{s}: skipping '{s}' due to it having type '{s}'", .{ + @tagName(parse.arch), name, @tagName(ty), }); continue; }, @@ -661,33 +660,33 @@ fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) }); } if (gop.value_ptr.ty != ty) blk: { - if (ty == elf.STT_NOTYPE) { - log.warn("symbol '{s}' in arch {s} has type {d} but in arch {s} has type {d}. going with the one that is not STT_NOTYPE", .{ + if (ty == .NOTYPE) { + log.warn("symbol '{s}' in arch {s} has type {s} but in arch {s} has type {s}. going with the one that is not STT_NOTYPE", .{ name, @tagName(parse.arch), - ty, + @tagName(ty), archSetName(gop.value_ptr.present), - gop.value_ptr.ty, + @tagName(gop.value_ptr.ty), }); break :blk; } - if (gop.value_ptr.ty == elf.STT_NOTYPE) { - log.warn("symbol '{s}' in arch {s} has type {d} but in arch {s} has type {d}. going with the one that is not STT_NOTYPE", .{ + if (gop.value_ptr.ty == .NOTYPE) { + log.warn("symbol '{s}' in arch {s} has type {s} but in arch {s} has type {s}. going with the one that is not STT_NOTYPE", .{ name, @tagName(parse.arch), - ty, + @tagName(ty), archSetName(gop.value_ptr.present), - gop.value_ptr.ty, + @tagName(gop.value_ptr.ty), }); gop.value_ptr.ty = ty; break :blk; } - fatal("symbol '{s}' in arch {s} has type {d} but in arch {s} has type {d}", .{ + fatal("symbol '{s}' in arch {s} has type {s} but in arch {s} has type {s}", .{ name, @tagName(parse.arch), - ty, + @tagName(ty), archSetName(gop.value_ptr.present), - gop.value_ptr.ty, + @tagName(gop.value_ptr.ty), }); } if (gop.value_ptr.visib != visib) {