diff options
Diffstat (limited to 'lib/std/elf.zig')
| -rw-r--r-- | lib/std/elf.zig | 275 |
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, |
