aboutsummaryrefslogtreecommitdiff
path: root/lib/std/elf.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/elf.zig')
-rw-r--r--lib/std/elf.zig275
1 files changed, 103 insertions, 172 deletions
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 4e15cd3a09..2583e83d19 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -482,6 +482,7 @@ pub const Header = struct {
is_64: bool,
endian: std.builtin.Endian,
os_abi: OSABI,
+ /// The meaning of this value depends on `os_abi`.
abi_version: u8,
type: ET,
machine: EM,
@@ -494,205 +495,135 @@ 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 iterateProgramHeaders(h: Header, file_reader: *std.fs.File.Reader) ProgramHeaderIterator {
+ return .{
+ .elf_header = h,
+ .file_reader = file_reader,
};
}
- 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 iterateSectionHeaders(h: Header, file_reader: *std.fs.File.Reader) SectionHeaderIterator {
+ return .{
+ .elf_header = h,
+ .file_reader = file_reader,
};
}
- pub fn read(parse_source: anytype) !Header {
- var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;
- try parse_source.seekableStream().seekTo(0);
- try parse_source.deprecatedReader().readNoEof(&hdr_buf);
- return Header.parse(&hdr_buf);
- }
+ pub const ReadError = std.Io.Reader.Error || error{
+ InvalidElfMagic,
+ InvalidElfVersion,
+ InvalidElfClass,
+ InvalidElfEndian,
+ };
- 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 read(r: *std.Io.Reader) ReadError!Header {
+ const buf = try r.peek(@sizeOf(Elf64_Ehdr));
- const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
- ELFCLASS32 => false,
- ELFCLASS64 => true,
- else => return error.InvalidElfClass,
- };
+ if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic;
+ if (buf[EI_VERSION] != 1) return error.InvalidElfVersion;
- const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
+ const endian: std.builtin.Endian = switch (buf[EI_DATA]) {
ELFDATA2LSB => .little,
ELFDATA2MSB => .big,
else => return error.InvalidElfEndian,
};
- const need_bswap = endian != native_endian;
+ return switch (buf[EI_CLASS]) {
+ ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian),
+ ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian),
+ else => return error.InvalidElfClass,
+ };
+ }
+
+ pub fn init(hdr: anytype, endian: std.builtin.Endian) Header {
// 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]);
+ return .{
+ .is_64 = switch (@TypeOf(hdr)) {
+ Elf32_Ehdr => false,
+ Elf64_Ehdr => true,
+ else => @compileError("bad type"),
+ },
+ .endian = endian,
+ .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]),
+ .abi_version = hdr.e_ident[EI_ABIVERSION],
+ .type = hdr.e_type,
+ .machine = hdr.e_machine,
+ .entry = hdr.e_entry,
+ .phoff = hdr.e_phoff,
+ .shoff = hdr.e_shoff,
+ .phentsize = hdr.e_phentsize,
+ .phnum = hdr.e_phnum,
+ .shentsize = hdr.e_shentsize,
+ .shnum = hdr.e_shnum,
+ .shstrndx = hdr.e_shstrndx,
+ };
+ }
+};
- // The meaning of this value depends on `os_abi` so just make it available as `u8`.
- const abi_version = hdr32.e_ident[EI_ABIVERSION];
+pub const ProgramHeaderIterator = struct {
+ elf_header: Header,
+ file_reader: *std.fs.File.Reader,
+ index: usize = 0,
- const @"type" = if (need_bswap) blk: {
- comptime assert(!@typeInfo(ET).@"enum".is_exhaustive);
- const value = @intFromEnum(hdr32.e_type);
- break :blk @as(ET, @enumFromInt(@byteSwap(value)));
- } else hdr32.e_type;
+ pub fn next(it: *ProgramHeaderIterator) !?Elf64_Phdr {
+ if (it.index >= it.elf_header.phnum) return null;
+ defer it.index += 1;
- const machine = if (need_bswap) blk: {
- comptime assert(!@typeInfo(EM).@"enum".is_exhaustive);
- const value = @intFromEnum(hdr32.e_machine);
- break :blk @as(EM, @enumFromInt(@byteSwap(value)));
- } else hdr32.e_machine;
+ if (it.elf_header.is_64) {
+ const offset = it.elf_header.phoff + @sizeOf(Elf64_Phdr) * it.index;
+ try it.file_reader.seekTo(offset);
+ const phdr = try it.file_reader.interface.takeStruct(Elf64_Phdr, it.elf_header.endian);
+ return phdr;
+ }
- return @as(Header, .{
- .is_64 = is_64,
- .endian = endian,
- .os_abi = os_abi,
- .abi_version = abi_version,
- .type = @"type",
- .machine = machine,
- .entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
- .phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
- .shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
- .phentsize = int(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize),
- .phnum = int(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum),
- .shentsize = int(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize),
- .shnum = int(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum),
- .shstrndx = int(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx),
- });
+ const offset = it.elf_header.phoff + @sizeOf(Elf32_Phdr) * it.index;
+ try it.file_reader.seekTo(offset);
+ const phdr = try it.file_reader.interface.takeStruct(Elf32_Phdr, it.elf_header.endian);
+ return .{
+ .p_type = phdr.p_type,
+ .p_offset = phdr.p_offset,
+ .p_vaddr = phdr.p_vaddr,
+ .p_paddr = phdr.p_paddr,
+ .p_filesz = phdr.p_filesz,
+ .p_memsz = phdr.p_memsz,
+ .p_flags = phdr.p_flags,
+ .p_align = phdr.p_align,
+ };
}
};
-pub fn ProgramHeaderIterator(comptime ParseSource: anytype) type {
- return struct {
- elf_header: Header,
- parse_source: ParseSource,
- index: usize = 0,
-
- pub fn next(self: *@This()) !?Elf64_Phdr {
- if (self.index >= self.elf_header.phnum) return null;
- defer self.index += 1;
-
- 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.deprecatedReader().readNoEof(mem.asBytes(&phdr));
-
- // ELF endianness matches native endianness.
- if (self.elf_header.endian == native_endian) return phdr;
-
- // Convert fields to native endianness.
- 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.deprecatedReader().readNoEof(mem.asBytes(&phdr));
-
- // ELF endianness does NOT match native endianness.
- if (self.elf_header.endian != native_endian) {
- // Convert fields to native endianness.
- mem.byteSwapAllFields(Elf32_Phdr, &phdr);
- }
-
- // Convert 32-bit header to 64-bit.
- return Elf64_Phdr{
- .p_type = phdr.p_type,
- .p_offset = phdr.p_offset,
- .p_vaddr = phdr.p_vaddr,
- .p_paddr = phdr.p_paddr,
- .p_filesz = phdr.p_filesz,
- .p_memsz = phdr.p_memsz,
- .p_flags = phdr.p_flags,
- .p_align = phdr.p_align,
- };
- }
- };
-}
+pub const SectionHeaderIterator = struct {
+ elf_header: Header,
+ file_reader: *std.fs.File.Reader,
+ index: usize = 0,
-pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
- return struct {
- elf_header: Header,
- parse_source: ParseSource,
- index: usize = 0,
-
- pub fn next(self: *@This()) !?Elf64_Shdr {
- if (self.index >= self.elf_header.shnum) return null;
- defer self.index += 1;
-
- 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.deprecatedReader().readNoEof(mem.asBytes(&shdr));
-
- // ELF endianness matches native endianness.
- if (self.elf_header.endian == native_endian) return shdr;
-
- // Convert fields to native endianness.
- 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.deprecatedReader().readNoEof(mem.asBytes(&shdr));
-
- // ELF endianness does NOT match native endianness.
- if (self.elf_header.endian != native_endian) {
- // Convert fields to native endianness.
- mem.byteSwapAllFields(Elf32_Shdr, &shdr);
- }
-
- // Convert 32-bit header to 64-bit.
- return Elf64_Shdr{
- .sh_name = shdr.sh_name,
- .sh_type = shdr.sh_type,
- .sh_flags = shdr.sh_flags,
- .sh_addr = shdr.sh_addr,
- .sh_offset = shdr.sh_offset,
- .sh_size = shdr.sh_size,
- .sh_link = shdr.sh_link,
- .sh_info = shdr.sh_info,
- .sh_addralign = shdr.sh_addralign,
- .sh_entsize = shdr.sh_entsize,
- };
- }
- };
-}
+ pub fn next(it: *SectionHeaderIterator) !?Elf64_Shdr {
+ if (it.index >= it.elf_header.shnum) return null;
+ defer it.index += 1;
-fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
- if (is_64) {
- if (need_bswap) {
- return @byteSwap(int_64);
- } else {
- return int_64;
+ if (it.elf_header.is_64) {
+ try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf64_Shdr) * it.index);
+ const shdr = try it.file_reader.interface.takeStruct(Elf64_Shdr, it.elf_header.endian);
+ return shdr;
}
- } else {
- return int32(need_bswap, int_32, @TypeOf(int_64));
- }
-}
-fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
- if (need_bswap) {
- return @byteSwap(int_32);
- } else {
- return int_32;
+ try it.file_reader.seekTo(it.elf_header.shoff + @sizeOf(Elf32_Shdr) * it.index);
+ const shdr = try it.file_reader.interface.takeStruct(Elf32_Shdr, it.elf_header.endian);
+ return .{
+ .sh_name = shdr.sh_name,
+ .sh_type = shdr.sh_type,
+ .sh_flags = shdr.sh_flags,
+ .sh_addr = shdr.sh_addr,
+ .sh_offset = shdr.sh_offset,
+ .sh_size = shdr.sh_size,
+ .sh_link = shdr.sh_link,
+ .sh_info = shdr.sh_info,
+ .sh_addralign = shdr.sh_addralign,
+ .sh_entsize = shdr.sh_entsize,
+ };
}
-}
+};
pub const ELFCLASSNONE = 0;
pub const ELFCLASS32 = 1;
@@ -2070,7 +2001,7 @@ pub const R_AARCH64 = enum(u32) {
TLSLE_LDST64_TPREL_LO12 = 558,
/// Likewise; no check.
TLSLE_LDST64_TPREL_LO12_NC = 559,
- /// PC-rel. load immediate 20:2.
+ /// PC-rel. load immediate 20:2.
TLSDESC_LD_PREL19 = 560,
/// PC-rel. ADR immediate 20:0.
TLSDESC_ADR_PREL21 = 561,