From ed13cffca4c42718cc7239faf7aab642ac67ef77 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 10 Mar 2020 22:01:58 -0400 Subject: [PATCH] rework some old ELF parsing code and start to fix emitRaw --- lib/std/build/emit_raw.zig | 112 +++++--------- lib/std/elf.zig | 292 ++++++++++--------------------------- lib/std/zig/system.zig | 35 ++--- 3 files changed, 128 insertions(+), 311 deletions(-) diff --git a/lib/std/build/emit_raw.zig b/lib/std/build/emit_raw.zig index 44e0227b6e..63c2329947 100644 --- a/lib/std/build/emit_raw.zig +++ b/lib/std/build/emit_raw.zig @@ -14,11 +14,6 @@ const io = std.io; const sort = std.sort; const warn = std.debug.warn; -const BinOutStream = io.OutStream(anyerror); -const BinSeekStream = io.SeekableStream(anyerror, anyerror); -const ElfSeekStream = io.SeekableStream(anyerror, anyerror); -const ElfInStream = io.InStream(anyerror); - const BinaryElfSection = struct { elfOffset: u64, binaryOffset: u64, @@ -41,22 +36,21 @@ const BinaryElfOutput = struct { const Self = @This(); - pub fn init(allocator: *Allocator) Self { - return Self{ - .segments = ArrayList(*BinaryElfSegment).init(allocator), - .sections = ArrayList(*BinaryElfSection).init(allocator), - }; - } - pub fn deinit(self: *Self) void { self.sections.deinit(); self.segments.deinit(); } - pub fn parseElf(self: *Self, elfFile: elf.Elf) !void { - const allocator = self.segments.allocator; + pub fn parse(allocator: *Allocator, elf_file: File) !Self { + var self: Self = .{ + .segments = ArrayList(*BinaryElfSegment).init(allocator), + .sections = ArrayList(*BinaryElfSection).init(allocator), + }; + const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file); - for (elfFile.section_headers) |section, i| { + var binaryElfOutput = BinaryElfOutput.init(arena_allocator); + + for (elf_hdrs.section_headers) |section, i| { if (sectionValidForOutput(section)) { const newSection = try allocator.create(BinaryElfSection); @@ -69,19 +63,19 @@ const BinaryElfOutput = struct { } } - for (elfFile.program_headers) |programHeader, i| { - if (programHeader.p_type == elf.PT_LOAD) { + for (elf_hdrs.program_headers) |phdr, i| { + if (phdr.p_type == elf.PT_LOAD) { const newSegment = try allocator.create(BinaryElfSegment); - newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr; - newSegment.virtualAddress = programHeader.p_vaddr; - newSegment.fileSize = @intCast(usize, programHeader.p_filesz); - newSegment.elfOffset = programHeader.p_offset; + newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr; + newSegment.virtualAddress = phdr.p_vaddr; + newSegment.fileSize = @intCast(usize, phdr.p_filesz); + newSegment.elfOffset = phdr.p_offset; newSegment.binaryOffset = 0; newSegment.firstSection = null; for (self.sections.toSlice()) |section| { - if (sectionWithinSegment(section, programHeader)) { + if (sectionWithinSegment(section, phdr)) { if (section.segment) |sectionSegment| { if (sectionSegment.elfOffset > newSegment.elfOffset) { section.segment = newSegment; @@ -126,14 +120,17 @@ const BinaryElfOutput = struct { } sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare); + + return self; } - fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool { + fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool { return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize); } - fn sectionValidForOutput(section: elf.SectionHeader) bool { - return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC); + fn sectionValidForOutput(shdr: var) bool { + return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and + ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC); } fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool { @@ -151,60 +148,27 @@ const BinaryElfOutput = struct { } }; -const WriteContext = struct { - inStream: *ElfInStream, - inSeekStream: *ElfSeekStream, - outStream: *BinOutStream, - outSeekStream: *BinSeekStream, -}; +fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void { + try out_file.seekTo(section.binaryOffset); -fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void { - var readBuffer = try allocator.alloc(u8, section.fileSize); - defer allocator.free(readBuffer); - - try context.inSeekStream.seekTo(section.elfOffset); - _ = try context.inStream.read(readBuffer); - - try context.outSeekStream.seekTo(section.binaryOffset); - try context.outStream.write(readBuffer); + try out_file.writeFileAll(elf_file, .{ + .in_offset = section.elfOffset, + .in_len = section.fileSize, + }); } -fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void { - var arenaAlloc = ArenaAllocator.init(allocator); - errdefer arenaAlloc.deinit(); - var arena_allocator = &arenaAlloc.allocator; +fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void { + var elf_file = try fs.cwd().openFile(elf_path, .{}); + defer elf_file.close(); - const currentDir = fs.cwd(); + var out_file = try fs.cwd().createFile(raw_path, .{}); + defer out_file.close(); - var file = try currentDir.openFile(elf_path, File.OpenFlags{}); - defer file.close(); + const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file); + defer binary_elf_output.deinit(); - var fileInStream = file.inStream(); - var fileSeekStream = file.seekableStream(); - - var elfFile = try elf.Elf.openStream(allocator, @ptrCast(*ElfSeekStream, &fileSeekStream.stream), @ptrCast(*ElfInStream, &fileInStream.stream)); - defer elfFile.close(); - - var outFile = try currentDir.createFile(raw_path, File.CreateFlags{}); - defer outFile.close(); - - var outFileOutStream = outFile.outStream(); - var outFileSeekStream = outFile.seekableStream(); - - const writeContext = WriteContext{ - .inStream = @ptrCast(*ElfInStream, &fileInStream.stream), - .inSeekStream = @ptrCast(*ElfSeekStream, &fileSeekStream.stream), - .outStream = @ptrCast(*BinOutStream, &outFileOutStream.stream), - .outSeekStream = @ptrCast(*BinSeekStream, &outFileSeekStream.stream), - }; - - var binaryElfOutput = BinaryElfOutput.init(arena_allocator); - defer binaryElfOutput.deinit(); - - try binaryElfOutput.parseElf(elfFile); - - for (binaryElfOutput.sections.toSlice()) |section| { - try writeBinaryElfSection(allocator, writeContext, section); + for (binary_elf_output.sections.toSlice()) |section| { + try writeBinaryElfSection(elf_file, out_file, section); } } @@ -250,6 +214,6 @@ pub const InstallRawStep = struct { const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable; - try emit_raw(builder.allocator, full_src_path, full_dest_path); + try emitRaw(builder.allocator, full_src_path, full_dest_path); } }; diff --git a/lib/std/elf.zig b/lib/std/elf.zig index efaa4d6f06..3aefd87f09 100644 --- a/lib/std/elf.zig +++ b/lib/std/elf.zig @@ -330,9 +330,7 @@ pub const ET = extern enum(u16) { pub const HIPROC = 0xffff; }; -pub const SectionHeader = Elf64_Shdr; -pub const ProgramHeader = Elf64_Phdr; - +/// All integers are native endian. const Header = struct { endian: builtin.Endian, is_64: bool, @@ -346,9 +344,9 @@ const Header = struct { shstrndx: u16, }; -pub fn readHeader(in_stream: var) !Header { +pub fn readHeader(file: File) !Header { var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; - try in_stream.readAll(&hdr_buf); + try in_stream.preadAll(&hdr_buf, 0); const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; @@ -381,216 +379,86 @@ pub fn readHeader(in_stream: var) !Header { }); } -pub const Elf = struct { - seekable_stream: *io.SeekableStream(anyerror, anyerror), - in_stream: *io.InStream(anyerror), - is_64: bool, - endian: builtin.Endian, - file_type: ET, - arch: EM, - entry_addr: u64, - program_header_offset: u64, - section_header_offset: u64, - string_section_index: usize, - string_section: *SectionHeader, - section_headers: []SectionHeader, - program_headers: []ProgramHeader, +/// All integers are native endian. +pub const AllHeaders = struct { + header: Header, + section_headers: []Elf64_Shdr, + program_headers: []Elf64_Phdr, allocator: *mem.Allocator, - - pub fn openStream( - allocator: *mem.Allocator, - seekable_stream: *io.SeekableStream(anyerror, anyerror), - in: *io.InStream(anyerror), - ) !Elf { - var elf: Elf = undefined; - elf.allocator = allocator; - elf.seekable_stream = seekable_stream; - elf.in_stream = in; - - var magic: [4]u8 = undefined; - try in.readNoEof(magic[0..]); - if (!mem.eql(u8, &magic, "\x7fELF")) return error.InvalidFormat; - - elf.is_64 = switch (try in.readByte()) { - 1 => false, - 2 => true, - else => return error.InvalidFormat, - }; - - elf.endian = switch (try in.readByte()) { - 1 => .Little, - 2 => .Big, - else => return error.InvalidFormat, - }; - - const version_byte = try in.readByte(); - if (version_byte != 1) return error.InvalidFormat; - - // skip over padding - try seekable_stream.seekBy(9); - - elf.file_type = try in.readEnum(ET, elf.endian); - elf.arch = try in.readEnum(EM, elf.endian); - - const elf_version = try in.readInt(u32, elf.endian); - if (elf_version != 1) return error.InvalidFormat; - - if (elf.is_64) { - elf.entry_addr = try in.readInt(u64, elf.endian); - elf.program_header_offset = try in.readInt(u64, elf.endian); - elf.section_header_offset = try in.readInt(u64, elf.endian); - } else { - elf.entry_addr = @as(u64, try in.readInt(u32, elf.endian)); - elf.program_header_offset = @as(u64, try in.readInt(u32, elf.endian)); - elf.section_header_offset = @as(u64, try in.readInt(u32, elf.endian)); - } - - // skip over flags - try seekable_stream.seekBy(4); - - const header_size = try in.readInt(u16, elf.endian); - if ((elf.is_64 and header_size != @sizeOf(Elf64_Ehdr)) or (!elf.is_64 and header_size != @sizeOf(Elf32_Ehdr))) { - return error.InvalidFormat; - } - - const ph_entry_size = try in.readInt(u16, elf.endian); - const ph_entry_count = try in.readInt(u16, elf.endian); - - if ((elf.is_64 and ph_entry_size != @sizeOf(Elf64_Phdr)) or (!elf.is_64 and ph_entry_size != @sizeOf(Elf32_Phdr))) { - return error.InvalidFormat; - } - - const sh_entry_size = try in.readInt(u16, elf.endian); - const sh_entry_count = try in.readInt(u16, elf.endian); - - if ((elf.is_64 and sh_entry_size != @sizeOf(Elf64_Shdr)) or (!elf.is_64 and sh_entry_size != @sizeOf(Elf32_Shdr))) { - return error.InvalidFormat; - } - - elf.string_section_index = @as(usize, try in.readInt(u16, elf.endian)); - - if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; - - const sh_byte_count = @as(u64, sh_entry_size) * @as(u64, sh_entry_count); - const end_sh = try math.add(u64, elf.section_header_offset, sh_byte_count); - const ph_byte_count = @as(u64, ph_entry_size) * @as(u64, ph_entry_count); - const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); - - const stream_end = try seekable_stream.getEndPos(); - if (stream_end < end_sh or stream_end < end_ph) { - return error.InvalidFormat; - } - - try seekable_stream.seekTo(elf.program_header_offset); - - elf.program_headers = try elf.allocator.alloc(ProgramHeader, ph_entry_count); - errdefer elf.allocator.free(elf.program_headers); - - if (elf.is_64) { - for (elf.program_headers) |*elf_program| { - elf_program.p_type = try in.readInt(Elf64_Word, elf.endian); - elf_program.p_flags = try in.readInt(Elf64_Word, elf.endian); - elf_program.p_offset = try in.readInt(Elf64_Off, elf.endian); - elf_program.p_vaddr = try in.readInt(Elf64_Addr, elf.endian); - elf_program.p_paddr = try in.readInt(Elf64_Addr, elf.endian); - elf_program.p_filesz = try in.readInt(Elf64_Xword, elf.endian); - elf_program.p_memsz = try in.readInt(Elf64_Xword, elf.endian); - elf_program.p_align = try in.readInt(Elf64_Xword, elf.endian); - } - } else { - for (elf.program_headers) |*elf_program| { - elf_program.p_type = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); - elf_program.p_offset = @as(Elf64_Off, try in.readInt(Elf32_Off, elf.endian)); - elf_program.p_vaddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); - elf_program.p_paddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); - elf_program.p_filesz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); - elf_program.p_memsz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); - elf_program.p_flags = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); - elf_program.p_align = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); - } - } - - try seekable_stream.seekTo(elf.section_header_offset); - - elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); - errdefer elf.allocator.free(elf.section_headers); - - if (elf.is_64) { - for (elf.section_headers) |*elf_section| { - elf_section.sh_name = try in.readInt(u32, elf.endian); - elf_section.sh_type = try in.readInt(u32, elf.endian); - elf_section.sh_flags = try in.readInt(u64, elf.endian); - elf_section.sh_addr = try in.readInt(u64, elf.endian); - elf_section.sh_offset = try in.readInt(u64, elf.endian); - elf_section.sh_size = try in.readInt(u64, elf.endian); - elf_section.sh_link = try in.readInt(u32, elf.endian); - elf_section.sh_info = try in.readInt(u32, elf.endian); - elf_section.sh_addralign = try in.readInt(u64, elf.endian); - elf_section.sh_entsize = try in.readInt(u64, elf.endian); - } - } else { - for (elf.section_headers) |*elf_section| { - // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? - elf_section.sh_name = try in.readInt(u32, elf.endian); - elf_section.sh_type = try in.readInt(u32, elf.endian); - elf_section.sh_flags = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.sh_addr = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.sh_offset = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.sh_size = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.sh_link = try in.readInt(u32, elf.endian); - elf_section.sh_info = try in.readInt(u32, elf.endian); - elf_section.sh_addralign = @as(u64, try in.readInt(u32, elf.endian)); - elf_section.sh_entsize = @as(u64, try in.readInt(u32, elf.endian)); - } - } - - for (elf.section_headers) |*elf_section| { - if (elf_section.sh_type != SHT_NOBITS) { - const file_end_offset = try math.add(u64, elf_section.sh_offset, elf_section.sh_size); - if (stream_end < file_end_offset) return error.InvalidFormat; - } - } - - elf.string_section = &elf.section_headers[elf.string_section_index]; - if (elf.string_section.sh_type != SHT_STRTAB) { - // not a string table - return error.InvalidFormat; - } - - return elf; - } - - pub fn close(elf: *Elf) void { - elf.allocator.free(elf.section_headers); - elf.allocator.free(elf.program_headers); - } - - pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { - section_loop: for (elf.section_headers) |*elf_section| { - if (elf_section.sh_type == SHT_NULL) continue; - - const name_offset = elf.string_section.sh_offset + elf_section.sh_name; - try elf.seekable_stream.seekTo(name_offset); - - for (name) |expected_c| { - const target_c = try elf.in_stream.readByte(); - if (target_c == 0 or expected_c != target_c) continue :section_loop; - } - - { - const null_byte = try elf.in_stream.readByte(); - if (null_byte == 0) return elf_section; - } - } - - return null; - } - - pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { - try elf.seekable_stream.seekTo(elf_section.sh_offset); - } }; +pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders { + var hdrs: AllHeaders = .{ + .allocator = allocator, + .header = try readHeader(file), + .section_headers = undefined, + .program_headers = undefined, + }; + const is_64 = hdrs.header.is_64; + const need_bswap = hdrs.header.endian != std.builtin.endian; + + hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum); + errdefer hdrs.allocator.free(hdrs.section_headers); + + hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum); + errdefer hdrs.allocator.free(hdrs.program_headers); + + // Treat section headers and program headers as byte buffers. For 32-bit ELF and + // non-matching endian files, we post-process to correct integer endianness and offsets. + + const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum]; + const phdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum]; + + try file.preadAll(phdr_buf, hdrs.header.phoff); + try file.preadAll(shdr_buf, hdrs.header.shoff); + + const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum]; + const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum]; + for (hdrs.section_headers) |*shdr, i| { + shdr.* = .{ + .sh_name = int(is_64, need_bswap, shdrs32[i].sh_name, shdr.sh_name), + .sh_type = int(is_64, need_bswap, shdrs32[i].sh_type, shdr.sh_type), + .sh_flags = int(is_64, need_bswap, shdrs32[i].sh_flags, shdr.sh_flags), + .sh_addr = int(is_64, need_bswap, shdrs32[i].sh_addr, shdr.sh_addr), + .sh_offset = int(is_64, need_bswap, shdrs32[i].sh_offset, shdr.sh_offset), + .sh_size = int(is_64, need_bswap, shdrs32[i].sh_size, shdr.sh_size), + .sh_link = int(is_64, need_bswap, shdrs32[i].sh_link, shdr.sh_link), + .sh_info = int(is_64, need_bswap, shdrs32[i].sh_info, shdr.sh_info), + .sh_addralign = int(is_64, need_bswap, shdrs32[i].sh_addralign, shdr.sh_addralign), + .sh_entsize = int(is_64, need_bswap, shdrs32[i].sh_entsize, shdr.sh_entsize), + }; + } + for (hdrs.program_headers) |*phdr, i| { + phdr.* = .{ + .p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type), + .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset), + .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr), + .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr), + .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz), + .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz), + .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags), + .p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align), + }; + } + return hdrs; +} + +pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { + if (is_64) { + if (need_bswap) { + return @byteSwap(@TypeOf(int_64), int_64); + } else { + return int_64; + } + } else { + if (need_bswap) { + return @byteSwap(@TypeOf(int_32), int_32); + } else { + return int_32; + } + } +} + pub const EI_NIDENT = 16; pub const EI_CLASS = 4; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 336dd0d314..e7953a1a91 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct { cross_target: CrossTarget, ) AbiAndDynamicLinkerFromFileError!NativeTargetInfo { var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; - _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len); + _ = try preadMin(file, &hdr_buf, 0, hdr_buf.len); const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; @@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct { elf.ELFCLASS64 => true, else => return error.InvalidElfClass, }; + const elfInt = elf.int; var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff); const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize); const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum); @@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct { // Reserve some bytes so that we can deref the 64-bit struct fields // even when the ELF file is 32-bits. const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); - const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); + const ph_read_byte_len = try preadMin(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); var ph_buf_i: usize = 0; while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ ph_i += 1; @@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct { const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; - _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); + _ = try preadMin(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); // PT_INTERP includes a null byte in p_filesz. const len = p_filesz - 1; // dynamic_linker.max_byte is "max", not "len". @@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct { // Reserve some bytes so that we can deref the 64-bit struct fields // even when the ELF file is 32-bits. const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); - const dyn_read_byte_len = try preadFull( + const dyn_read_byte_len = try preadMin( file, dyn_buf[0 .. dyn_buf.len - dyn_reserve], dyn_off, @@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct { var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; if (sh_buf.len < shentsize) return error.InvalidElfFile; - _ = try preadFull(file, &sh_buf, str_section_off, shentsize); + _ = try preadMin(file, &sh_buf, str_section_off, shentsize); const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); var strtab_buf: [4096:0]u8 = undefined; const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); - const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len); + const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len); const shstrtab = strtab_buf[0..shstrtab_read_len]; const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); @@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct { // Reserve some bytes so that we can deref the 64-bit struct fields // even when the ELF file is 32-bits. const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); - const sh_read_byte_len = try preadFull( + const sh_read_byte_len = try preadMin( file, sh_buf[0 .. sh_buf.len - sh_reserve], shoff, @@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct { if (dynstr) |ds| { const strtab_len = std.math.min(ds.size, strtab_buf.len); - const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len); + const strtab_read_len = try preadMin(file, &strtab_buf, ds.offset, shstrtab_len); const strtab = strtab_buf[0..strtab_read_len]; // TODO this pointer cast should not be necessary const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); @@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct { return result; } - fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { + fn preadMin(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { var i: u64 = 0; while (i < min_read_len) { const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) { @@ -853,22 +854,6 @@ pub const NativeTargetInfo = struct { abi: Target.Abi, }; - fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { - if (is_64) { - if (need_bswap) { - return @byteSwap(@TypeOf(int_64), int_64); - } else { - return int_64; - } - } else { - if (need_bswap) { - return @byteSwap(@TypeOf(int_32), int_32); - } else { - return int_32; - } - } - } - fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu { // Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`, // although it is a runtime value, is guaranteed to be one of the architectures in the set