| author | |
| committer | |
| log | ed13cffca4c42718cc7239faf7aab642ac67ef77 |
| tree | 0aeae1f6b9e8dec311bca1904093e3529bd85521 |
| parent | bd14a81e301401b5b2a8b849d17d6ae0750272b8 |
| signature |
3 files changed, 120 insertions(+), 303 deletions(-)
lib/std/build/emit_raw.zig+38-74| ... | ... | @@ -14,11 +14,6 @@ const io = std.io; |
| 14 | 14 | const sort = std.sort; |
| 15 | 15 | const warn = std.debug.warn; |
| 16 | 16 | |
| 17 | const BinOutStream = io.OutStream(anyerror); | |
| 18 | const BinSeekStream = io.SeekableStream(anyerror, anyerror); | |
| 19 | const ElfSeekStream = io.SeekableStream(anyerror, anyerror); | |
| 20 | const ElfInStream = io.InStream(anyerror); | |
| 21 | ||
| 22 | 17 | const BinaryElfSection = struct { |
| 23 | 18 | elfOffset: u64, |
| 24 | 19 | binaryOffset: u64, |
| ... | ... | @@ -41,22 +36,21 @@ const BinaryElfOutput = struct { |
| 41 | 36 | |
| 42 | 37 | const Self = @This(); |
| 43 | 38 | |
| 44 | pub fn init(allocator: *Allocator) Self { | |
| 45 | return Self{ | |
| 46 | .segments = ArrayList(*BinaryElfSegment).init(allocator), | |
| 47 | .sections = ArrayList(*BinaryElfSection).init(allocator), | |
| 48 | }; | |
| 49 | } | |
| 50 | ||
| 51 | 39 | pub fn deinit(self: *Self) void { |
| 52 | 40 | self.sections.deinit(); |
| 53 | 41 | self.segments.deinit(); |
| 54 | 42 | } |
| 55 | 43 | |
| 56 | pub fn parseElf(self: *Self, elfFile: elf.Elf) !void { | |
| 57 | const allocator = self.segments.allocator; | |
| 44 | pub fn parse(allocator: *Allocator, elf_file: File) !Self { | |
| 45 | var self: Self = .{ | |
| 46 | .segments = ArrayList(*BinaryElfSegment).init(allocator), | |
| 47 | .sections = ArrayList(*BinaryElfSection).init(allocator), | |
| 48 | }; | |
| 49 | const elf_hdrs = try std.elf.readAllHeaders(allocator, elf_file); | |
| 58 | 50 | |
| 59 | for (elfFile.section_headers) |section, i| { | |
| 51 | var binaryElfOutput = BinaryElfOutput.init(arena_allocator); | |
| 52 | ||
| 53 | for (elf_hdrs.section_headers) |section, i| { | |
| 60 | 54 | if (sectionValidForOutput(section)) { |
| 61 | 55 | const newSection = try allocator.create(BinaryElfSection); |
| 62 | 56 | |
| ... | ... | @@ -69,19 +63,19 @@ const BinaryElfOutput = struct { |
| 69 | 63 | } |
| 70 | 64 | } |
| 71 | 65 | |
| 72 | for (elfFile.program_headers) |programHeader, i| { | |
| 73 | if (programHeader.p_type == elf.PT_LOAD) { | |
| 66 | for (elf_hdrs.program_headers) |phdr, i| { | |
| 67 | if (phdr.p_type == elf.PT_LOAD) { | |
| 74 | 68 | const newSegment = try allocator.create(BinaryElfSegment); |
| 75 | 69 | |
| 76 | newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr; | |
| 77 | newSegment.virtualAddress = programHeader.p_vaddr; | |
| 78 | newSegment.fileSize = @intCast(usize, programHeader.p_filesz); | |
| 79 | newSegment.elfOffset = programHeader.p_offset; | |
| 70 | newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr; | |
| 71 | newSegment.virtualAddress = phdr.p_vaddr; | |
| 72 | newSegment.fileSize = @intCast(usize, phdr.p_filesz); | |
| 73 | newSegment.elfOffset = phdr.p_offset; | |
| 80 | 74 | newSegment.binaryOffset = 0; |
| 81 | 75 | newSegment.firstSection = null; |
| 82 | 76 | |
| 83 | 77 | for (self.sections.toSlice()) |section| { |
| 84 | if (sectionWithinSegment(section, programHeader)) { | |
| 78 | if (sectionWithinSegment(section, phdr)) { | |
| 85 | 79 | if (section.segment) |sectionSegment| { |
| 86 | 80 | if (sectionSegment.elfOffset > newSegment.elfOffset) { |
| 87 | 81 | section.segment = newSegment; |
| ... | ... | @@ -126,14 +120,17 @@ const BinaryElfOutput = struct { |
| 126 | 120 | } |
| 127 | 121 | |
| 128 | 122 | sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare); |
| 123 | ||
| 124 | return self; | |
| 129 | 125 | } |
| 130 | 126 | |
| 131 | fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool { | |
| 127 | fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool { | |
| 132 | 128 | return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize); |
| 133 | 129 | } |
| 134 | 130 | |
| 135 | fn sectionValidForOutput(section: elf.SectionHeader) bool { | |
| 136 | return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC); | |
| 131 | fn sectionValidForOutput(shdr: var) bool { | |
| 132 | return shdr.sh_size > 0 and shdr.sh_type != elf.SHT_NOBITS and | |
| 133 | ((shdr.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC); | |
| 137 | 134 | } |
| 138 | 135 | |
| 139 | 136 | fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool { |
| ... | ... | @@ -151,60 +148,27 @@ const BinaryElfOutput = struct { |
| 151 | 148 | } |
| 152 | 149 | }; |
| 153 | 150 | |
| 154 | const WriteContext = struct { | |
| 155 | inStream: *ElfInStream, | |
| 156 | inSeekStream: *ElfSeekStream, | |
| 157 | outStream: *BinOutStream, | |
| 158 | outSeekStream: *BinSeekStream, | |
| 159 | }; | |
| 160 | ||
| 161 | fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void { | |
| 162 | var readBuffer = try allocator.alloc(u8, section.fileSize); | |
| 163 | defer allocator.free(readBuffer); | |
| 151 | fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void { | |
| 152 | try out_file.seekTo(section.binaryOffset); | |
| 164 | 153 | |
| 165 | try context.inSeekStream.seekTo(section.elfOffset); | |
| 166 | _ = try context.inStream.read(readBuffer); | |
| 167 | ||
| 168 | try context.outSeekStream.seekTo(section.binaryOffset); | |
| 169 | try context.outStream.write(readBuffer); | |
| 154 | try out_file.writeFileAll(elf_file, .{ | |
| 155 | .in_offset = section.elfOffset, | |
| 156 | .in_len = section.fileSize, | |
| 157 | }); | |
| 170 | 158 | } |
| 171 | 159 | |
| 172 | fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void { | |
| 173 | var arenaAlloc = ArenaAllocator.init(allocator); | |
| 174 | errdefer arenaAlloc.deinit(); | |
| 175 | var arena_allocator = &arenaAlloc.allocator; | |
| 176 | ||
| 177 | const currentDir = fs.cwd(); | |
| 178 | ||
| 179 | var file = try currentDir.openFile(elf_path, File.OpenFlags{}); | |
| 180 | defer file.close(); | |
| 181 | ||
| 182 | var fileInStream = file.inStream(); | |
| 183 | var fileSeekStream = file.seekableStream(); | |
| 184 | ||
| 185 | var elfFile = try elf.Elf.openStream(allocator, @ptrCast(*ElfSeekStream, &fileSeekStream.stream), @ptrCast(*ElfInStream, &fileInStream.stream)); | |
| 186 | defer elfFile.close(); | |
| 187 | ||
| 188 | var outFile = try currentDir.createFile(raw_path, File.CreateFlags{}); | |
| 189 | defer outFile.close(); | |
| 190 | ||
| 191 | var outFileOutStream = outFile.outStream(); | |
| 192 | var outFileSeekStream = outFile.seekableStream(); | |
| 193 | ||
| 194 | const writeContext = WriteContext{ | |
| 195 | .inStream = @ptrCast(*ElfInStream, &fileInStream.stream), | |
| 196 | .inSeekStream = @ptrCast(*ElfSeekStream, &fileSeekStream.stream), | |
| 197 | .outStream = @ptrCast(*BinOutStream, &outFileOutStream.stream), | |
| 198 | .outSeekStream = @ptrCast(*BinSeekStream, &outFileSeekStream.stream), | |
| 199 | }; | |
| 160 | fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void { | |
| 161 | var elf_file = try fs.cwd().openFile(elf_path, .{}); | |
| 162 | defer elf_file.close(); | |
| 200 | 163 | |
| 201 | var binaryElfOutput = BinaryElfOutput.init(arena_allocator); | |
| 202 | defer binaryElfOutput.deinit(); | |
| 164 | var out_file = try fs.cwd().createFile(raw_path, .{}); | |
| 165 | defer out_file.close(); | |
| 203 | 166 | |
| 204 | try binaryElfOutput.parseElf(elfFile); | |
| 167 | const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file); | |
| 168 | defer binary_elf_output.deinit(); | |
| 205 | 169 | |
| 206 | for (binaryElfOutput.sections.toSlice()) |section| { | |
| 207 | try writeBinaryElfSection(allocator, writeContext, section); | |
| 170 | for (binary_elf_output.sections.toSlice()) |section| { | |
| 171 | try writeBinaryElfSection(elf_file, out_file, section); | |
| 208 | 172 | } |
| 209 | 173 | } |
| 210 | 174 | |
| ... | ... | @@ -250,6 +214,6 @@ pub const InstallRawStep = struct { |
| 250 | 214 | const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename); |
| 251 | 215 | |
| 252 | 216 | fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable; |
| 253 | try emit_raw(builder.allocator, full_src_path, full_dest_path); | |
| 217 | try emitRaw(builder.allocator, full_src_path, full_dest_path); | |
| 254 | 218 | } |
| 255 | 219 | }; |
lib/std/elf.zig+72-204| ... | ... | @@ -330,9 +330,7 @@ pub const ET = extern enum(u16) { |
| 330 | 330 | pub const HIPROC = 0xffff; |
| 331 | 331 | }; |
| 332 | 332 | |
| 333 | pub const SectionHeader = Elf64_Shdr; | |
| 334 | pub const ProgramHeader = Elf64_Phdr; | |
| 335 | ||
| 333 | /// All integers are native endian. | |
| 336 | 334 | const Header = struct { |
| 337 | 335 | endian: builtin.Endian, |
| 338 | 336 | is_64: bool, |
| ... | ... | @@ -346,9 +344,9 @@ const Header = struct { |
| 346 | 344 | shstrndx: u16, |
| 347 | 345 | }; |
| 348 | 346 | |
| 349 | pub fn readHeader(in_stream: var) !Header { | |
| 347 | pub fn readHeader(file: File) !Header { | |
| 350 | 348 | var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined; |
| 351 | try in_stream.readAll(&hdr_buf); | |
| 349 | try in_stream.preadAll(&hdr_buf, 0); | |
| 352 | 350 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); |
| 353 | 351 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); |
| 354 | 352 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; |
| ... | ... | @@ -381,215 +379,85 @@ pub fn readHeader(in_stream: var) !Header { |
| 381 | 379 | }); |
| 382 | 380 | } |
| 383 | 381 | |
| 384 | pub const Elf = struct { | |
| 385 | seekable_stream: *io.SeekableStream(anyerror, anyerror), | |
| 386 | in_stream: *io.InStream(anyerror), | |
| 387 | is_64: bool, | |
| 388 | endian: builtin.Endian, | |
| 389 | file_type: ET, | |
| 390 | arch: EM, | |
| 391 | entry_addr: u64, | |
| 392 | program_header_offset: u64, | |
| 393 | section_header_offset: u64, | |
| 394 | string_section_index: usize, | |
| 395 | string_section: *SectionHeader, | |
| 396 | section_headers: []SectionHeader, | |
| 397 | program_headers: []ProgramHeader, | |
| 382 | /// All integers are native endian. | |
| 383 | pub const AllHeaders = struct { | |
| 384 | header: Header, | |
| 385 | section_headers: []Elf64_Shdr, | |
| 386 | program_headers: []Elf64_Phdr, | |
| 398 | 387 | allocator: *mem.Allocator, |
| 388 | }; | |
| 399 | 389 | |
| 400 | pub fn openStream( | |
| 401 | allocator: *mem.Allocator, | |
| 402 | seekable_stream: *io.SeekableStream(anyerror, anyerror), | |
| 403 | in: *io.InStream(anyerror), | |
| 404 | ) !Elf { | |
| 405 | var elf: Elf = undefined; | |
| 406 | elf.allocator = allocator; | |
| 407 | elf.seekable_stream = seekable_stream; | |
| 408 | elf.in_stream = in; | |
| 409 | ||
| 410 | var magic: [4]u8 = undefined; | |
| 411 | try in.readNoEof(magic[0..]); | |
| 412 | if (!mem.eql(u8, &magic, "\x7fELF")) return error.InvalidFormat; | |
| 413 | ||
| 414 | elf.is_64 = switch (try in.readByte()) { | |
| 415 | 1 => false, | |
| 416 | 2 => true, | |
| 417 | else => return error.InvalidFormat, | |
| 390 | pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders { | |
| 391 | var hdrs: AllHeaders = .{ | |
| 392 | .allocator = allocator, | |
| 393 | .header = try readHeader(file), | |
| 394 | .section_headers = undefined, | |
| 395 | .program_headers = undefined, | |
| 396 | }; | |
| 397 | const is_64 = hdrs.header.is_64; | |
| 398 | const need_bswap = hdrs.header.endian != std.builtin.endian; | |
| 399 | ||
| 400 | hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum); | |
| 401 | errdefer hdrs.allocator.free(hdrs.section_headers); | |
| 402 | ||
| 403 | hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum); | |
| 404 | errdefer hdrs.allocator.free(hdrs.program_headers); | |
| 405 | ||
| 406 | // Treat section headers and program headers as byte buffers. For 32-bit ELF and | |
| 407 | // non-matching endian files, we post-process to correct integer endianness and offsets. | |
| 408 | ||
| 409 | const shdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.shentsize * hdrs.header.shnum]; | |
| 410 | const phdr_buf = std.mem.sliceToBytes(hdrs.section_headers)[0 .. hdrs.header.phentsize * hdrs.header.phnum]; | |
| 411 | ||
| 412 | try file.preadAll(phdr_buf, hdrs.header.phoff); | |
| 413 | try file.preadAll(shdr_buf, hdrs.header.shoff); | |
| 414 | ||
| 415 | const shdrs32 = @ptrCast([*]Elf32_Shdr, @alignCast(@alignOf(Elf32_Shdr), shdr_buf.ptr))[0..hdrs.header.shnum]; | |
| 416 | const phdrs32 = @ptrCast([*]Elf32_Phdr, @alignCast(@alignOf(Elf32_Phdr), phdr_buf.ptr))[0..hdrs.header.phnum]; | |
| 417 | for (hdrs.section_headers) |*shdr, i| { | |
| 418 | shdr.* = .{ | |
| 419 | .sh_name = int(is_64, need_bswap, shdrs32[i].sh_name, shdr.sh_name), | |
| 420 | .sh_type = int(is_64, need_bswap, shdrs32[i].sh_type, shdr.sh_type), | |
| 421 | .sh_flags = int(is_64, need_bswap, shdrs32[i].sh_flags, shdr.sh_flags), | |
| 422 | .sh_addr = int(is_64, need_bswap, shdrs32[i].sh_addr, shdr.sh_addr), | |
| 423 | .sh_offset = int(is_64, need_bswap, shdrs32[i].sh_offset, shdr.sh_offset), | |
| 424 | .sh_size = int(is_64, need_bswap, shdrs32[i].sh_size, shdr.sh_size), | |
| 425 | .sh_link = int(is_64, need_bswap, shdrs32[i].sh_link, shdr.sh_link), | |
| 426 | .sh_info = int(is_64, need_bswap, shdrs32[i].sh_info, shdr.sh_info), | |
| 427 | .sh_addralign = int(is_64, need_bswap, shdrs32[i].sh_addralign, shdr.sh_addralign), | |
| 428 | .sh_entsize = int(is_64, need_bswap, shdrs32[i].sh_entsize, shdr.sh_entsize), | |
| 418 | 429 | }; |
| 419 | ||
| 420 | elf.endian = switch (try in.readByte()) { | |
| 421 | 1 => .Little, | |
| 422 | 2 => .Big, | |
| 423 | else => return error.InvalidFormat, | |
| 430 | } | |
| 431 | for (hdrs.program_headers) |*phdr, i| { | |
| 432 | phdr.* = .{ | |
| 433 | .p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type), | |
| 434 | .p_offset = int(is_64, need_bswap, phdrs32[i].p_offset, shdr.p_offset), | |
| 435 | .p_vaddr = int(is_64, need_bswap, phdrs32[i].p_vaddr, shdr.p_vaddr), | |
| 436 | .p_paddr = int(is_64, need_bswap, phdrs32[i].p_paddr, shdr.p_paddr), | |
| 437 | .p_filesz = int(is_64, need_bswap, phdrs32[i].p_filesz, shdr.p_filesz), | |
| 438 | .p_memsz = int(is_64, need_bswap, phdrs32[i].p_memsz, shdr.p_memsz), | |
| 439 | .p_flags = int(is_64, need_bswap, phdrs32[i].p_flags, shdr.p_flags), | |
| 440 | .p_align = int(is_64, need_bswap, phdrs32[i].p_align, shdr.p_align), | |
| 424 | 441 | }; |
| 442 | } | |
| 443 | return hdrs; | |
| 444 | } | |
| 425 | 445 | |
| 426 | const version_byte = try in.readByte(); | |
| 427 | if (version_byte != 1) return error.InvalidFormat; | |
| 428 | ||
| 429 | // skip over padding | |
| 430 | try seekable_stream.seekBy(9); | |
| 431 | ||
| 432 | elf.file_type = try in.readEnum(ET, elf.endian); | |
| 433 | elf.arch = try in.readEnum(EM, elf.endian); | |
| 434 | ||
| 435 | const elf_version = try in.readInt(u32, elf.endian); | |
| 436 | if (elf_version != 1) return error.InvalidFormat; | |
| 437 | ||
| 438 | if (elf.is_64) { | |
| 439 | elf.entry_addr = try in.readInt(u64, elf.endian); | |
| 440 | elf.program_header_offset = try in.readInt(u64, elf.endian); | |
| 441 | elf.section_header_offset = try in.readInt(u64, elf.endian); | |
| 442 | } else { | |
| 443 | elf.entry_addr = @as(u64, try in.readInt(u32, elf.endian)); | |
| 444 | elf.program_header_offset = @as(u64, try in.readInt(u32, elf.endian)); | |
| 445 | elf.section_header_offset = @as(u64, try in.readInt(u32, elf.endian)); | |
| 446 | } | |
| 447 | ||
| 448 | // skip over flags | |
| 449 | try seekable_stream.seekBy(4); | |
| 450 | ||
| 451 | const header_size = try in.readInt(u16, elf.endian); | |
| 452 | if ((elf.is_64 and header_size != @sizeOf(Elf64_Ehdr)) or (!elf.is_64 and header_size != @sizeOf(Elf32_Ehdr))) { | |
| 453 | return error.InvalidFormat; | |
| 454 | } | |
| 455 | ||
| 456 | const ph_entry_size = try in.readInt(u16, elf.endian); | |
| 457 | const ph_entry_count = try in.readInt(u16, elf.endian); | |
| 458 | ||
| 459 | if ((elf.is_64 and ph_entry_size != @sizeOf(Elf64_Phdr)) or (!elf.is_64 and ph_entry_size != @sizeOf(Elf32_Phdr))) { | |
| 460 | return error.InvalidFormat; | |
| 461 | } | |
| 462 | ||
| 463 | const sh_entry_size = try in.readInt(u16, elf.endian); | |
| 464 | const sh_entry_count = try in.readInt(u16, elf.endian); | |
| 465 | ||
| 466 | if ((elf.is_64 and sh_entry_size != @sizeOf(Elf64_Shdr)) or (!elf.is_64 and sh_entry_size != @sizeOf(Elf32_Shdr))) { | |
| 467 | return error.InvalidFormat; | |
| 468 | } | |
| 469 | ||
| 470 | elf.string_section_index = @as(usize, try in.readInt(u16, elf.endian)); | |
| 471 | ||
| 472 | if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; | |
| 473 | ||
| 474 | const sh_byte_count = @as(u64, sh_entry_size) * @as(u64, sh_entry_count); | |
| 475 | const end_sh = try math.add(u64, elf.section_header_offset, sh_byte_count); | |
| 476 | const ph_byte_count = @as(u64, ph_entry_size) * @as(u64, ph_entry_count); | |
| 477 | const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); | |
| 478 | ||
| 479 | const stream_end = try seekable_stream.getEndPos(); | |
| 480 | if (stream_end < end_sh or stream_end < end_ph) { | |
| 481 | return error.InvalidFormat; | |
| 482 | } | |
| 483 | ||
| 484 | try seekable_stream.seekTo(elf.program_header_offset); | |
| 485 | ||
| 486 | elf.program_headers = try elf.allocator.alloc(ProgramHeader, ph_entry_count); | |
| 487 | errdefer elf.allocator.free(elf.program_headers); | |
| 488 | ||
| 489 | if (elf.is_64) { | |
| 490 | for (elf.program_headers) |*elf_program| { | |
| 491 | elf_program.p_type = try in.readInt(Elf64_Word, elf.endian); | |
| 492 | elf_program.p_flags = try in.readInt(Elf64_Word, elf.endian); | |
| 493 | elf_program.p_offset = try in.readInt(Elf64_Off, elf.endian); | |
| 494 | elf_program.p_vaddr = try in.readInt(Elf64_Addr, elf.endian); | |
| 495 | elf_program.p_paddr = try in.readInt(Elf64_Addr, elf.endian); | |
| 496 | elf_program.p_filesz = try in.readInt(Elf64_Xword, elf.endian); | |
| 497 | elf_program.p_memsz = try in.readInt(Elf64_Xword, elf.endian); | |
| 498 | elf_program.p_align = try in.readInt(Elf64_Xword, elf.endian); | |
| 499 | } | |
| 446 | pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { | |
| 447 | if (is_64) { | |
| 448 | if (need_bswap) { | |
| 449 | return @byteSwap(@TypeOf(int_64), int_64); | |
| 500 | 450 | } else { |
| 501 | for (elf.program_headers) |*elf_program| { | |
| 502 | elf_program.p_type = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); | |
| 503 | elf_program.p_offset = @as(Elf64_Off, try in.readInt(Elf32_Off, elf.endian)); | |
| 504 | elf_program.p_vaddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); | |
| 505 | elf_program.p_paddr = @as(Elf64_Addr, try in.readInt(Elf32_Addr, elf.endian)); | |
| 506 | elf_program.p_filesz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); | |
| 507 | elf_program.p_memsz = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); | |
| 508 | elf_program.p_flags = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); | |
| 509 | elf_program.p_align = @as(Elf64_Word, try in.readInt(Elf32_Word, elf.endian)); | |
| 510 | } | |
| 451 | return int_64; | |
| 511 | 452 | } |
| 512 | ||
| 513 | try seekable_stream.seekTo(elf.section_header_offset); | |
| 514 | ||
| 515 | elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); | |
| 516 | errdefer elf.allocator.free(elf.section_headers); | |
| 517 | ||
| 518 | if (elf.is_64) { | |
| 519 | for (elf.section_headers) |*elf_section| { | |
| 520 | elf_section.sh_name = try in.readInt(u32, elf.endian); | |
| 521 | elf_section.sh_type = try in.readInt(u32, elf.endian); | |
| 522 | elf_section.sh_flags = try in.readInt(u64, elf.endian); | |
| 523 | elf_section.sh_addr = try in.readInt(u64, elf.endian); | |
| 524 | elf_section.sh_offset = try in.readInt(u64, elf.endian); | |
| 525 | elf_section.sh_size = try in.readInt(u64, elf.endian); | |
| 526 | elf_section.sh_link = try in.readInt(u32, elf.endian); | |
| 527 | elf_section.sh_info = try in.readInt(u32, elf.endian); | |
| 528 | elf_section.sh_addralign = try in.readInt(u64, elf.endian); | |
| 529 | elf_section.sh_entsize = try in.readInt(u64, elf.endian); | |
| 530 | } | |
| 453 | } else { | |
| 454 | if (need_bswap) { | |
| 455 | return @byteSwap(@TypeOf(int_32), int_32); | |
| 531 | 456 | } else { |
| 532 | for (elf.section_headers) |*elf_section| { | |
| 533 | // TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ? | |
| 534 | elf_section.sh_name = try in.readInt(u32, elf.endian); | |
| 535 | elf_section.sh_type = try in.readInt(u32, elf.endian); | |
| 536 | elf_section.sh_flags = @as(u64, try in.readInt(u32, elf.endian)); | |
| 537 | elf_section.sh_addr = @as(u64, try in.readInt(u32, elf.endian)); | |
| 538 | elf_section.sh_offset = @as(u64, try in.readInt(u32, elf.endian)); | |
| 539 | elf_section.sh_size = @as(u64, try in.readInt(u32, elf.endian)); | |
| 540 | elf_section.sh_link = try in.readInt(u32, elf.endian); | |
| 541 | elf_section.sh_info = try in.readInt(u32, elf.endian); | |
| 542 | elf_section.sh_addralign = @as(u64, try in.readInt(u32, elf.endian)); | |
| 543 | elf_section.sh_entsize = @as(u64, try in.readInt(u32, elf.endian)); | |
| 544 | } | |
| 545 | } | |
| 546 | ||
| 547 | for (elf.section_headers) |*elf_section| { | |
| 548 | if (elf_section.sh_type != SHT_NOBITS) { | |
| 549 | const file_end_offset = try math.add(u64, elf_section.sh_offset, elf_section.sh_size); | |
| 550 | if (stream_end < file_end_offset) return error.InvalidFormat; | |
| 551 | } | |
| 552 | } | |
| 553 | ||
| 554 | elf.string_section = &elf.section_headers[elf.string_section_index]; | |
| 555 | if (elf.string_section.sh_type != SHT_STRTAB) { | |
| 556 | // not a string table | |
| 557 | return error.InvalidFormat; | |
| 558 | } | |
| 559 | ||
| 560 | return elf; | |
| 561 | } | |
| 562 | ||
| 563 | pub fn close(elf: *Elf) void { | |
| 564 | elf.allocator.free(elf.section_headers); | |
| 565 | elf.allocator.free(elf.program_headers); | |
| 566 | } | |
| 567 | ||
| 568 | pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { | |
| 569 | section_loop: for (elf.section_headers) |*elf_section| { | |
| 570 | if (elf_section.sh_type == SHT_NULL) continue; | |
| 571 | ||
| 572 | const name_offset = elf.string_section.sh_offset + elf_section.sh_name; | |
| 573 | try elf.seekable_stream.seekTo(name_offset); | |
| 574 | ||
| 575 | for (name) |expected_c| { | |
| 576 | const target_c = try elf.in_stream.readByte(); | |
| 577 | if (target_c == 0 or expected_c != target_c) continue :section_loop; | |
| 578 | } | |
| 579 | ||
| 580 | { | |
| 581 | const null_byte = try elf.in_stream.readByte(); | |
| 582 | if (null_byte == 0) return elf_section; | |
| 583 | } | |
| 457 | return int_32; | |
| 584 | 458 | } |
| 585 | ||
| 586 | return null; | |
| 587 | } | |
| 588 | ||
| 589 | pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { | |
| 590 | try elf.seekable_stream.seekTo(elf_section.sh_offset); | |
| 591 | 459 | } |
| 592 | }; | |
| 460 | } | |
| 593 | 461 | |
| 594 | 462 | pub const EI_NIDENT = 16; |
| 595 | 463 |
lib/std/zig/system.zig+10-25| ... | ... | @@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct { |
| 570 | 570 | cross_target: CrossTarget, |
| 571 | 571 | ) AbiAndDynamicLinkerFromFileError!NativeTargetInfo { |
| 572 | 572 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; |
| 573 | _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len); | |
| 573 | _ = try preadMin(file, &hdr_buf, 0, hdr_buf.len); | |
| 574 | 574 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); |
| 575 | 575 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); |
| 576 | 576 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; |
| ... | ... | @@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct { |
| 587 | 587 | elf.ELFCLASS64 => true, |
| 588 | 588 | else => return error.InvalidElfClass, |
| 589 | 589 | }; |
| 590 | const elfInt = elf.int; | |
| 590 | 591 | var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff); |
| 591 | 592 | const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize); |
| 592 | 593 | const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum); |
| ... | ... | @@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct { |
| 610 | 611 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 611 | 612 | // even when the ELF file is 32-bits. |
| 612 | 613 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); |
| 613 | const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); | |
| 614 | const ph_read_byte_len = try preadMin(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); | |
| 614 | 615 | var ph_buf_i: usize = 0; |
| 615 | 616 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ |
| 616 | 617 | ph_i += 1; |
| ... | ... | @@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct { |
| 625 | 626 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 626 | 627 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 627 | 628 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; |
| 628 | _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); | |
| 629 | _ = try preadMin(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); | |
| 629 | 630 | // PT_INTERP includes a null byte in p_filesz. |
| 630 | 631 | const len = p_filesz - 1; |
| 631 | 632 | // dynamic_linker.max_byte is "max", not "len". |
| ... | ... | @@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct { |
| 656 | 657 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 657 | 658 | // even when the ELF file is 32-bits. |
| 658 | 659 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); |
| 659 | const dyn_read_byte_len = try preadFull( | |
| 660 | const dyn_read_byte_len = try preadMin( | |
| 660 | 661 | file, |
| 661 | 662 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], |
| 662 | 663 | dyn_off, |
| ... | ... | @@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct { |
| 701 | 702 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; |
| 702 | 703 | if (sh_buf.len < shentsize) return error.InvalidElfFile; |
| 703 | 704 | |
| 704 | _ = try preadFull(file, &sh_buf, str_section_off, shentsize); | |
| 705 | _ = try preadMin(file, &sh_buf, str_section_off, shentsize); | |
| 705 | 706 | const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); |
| 706 | 707 | const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); |
| 707 | 708 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); |
| 708 | 709 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); |
| 709 | 710 | var strtab_buf: [4096:0]u8 = undefined; |
| 710 | 711 | const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); |
| 711 | const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len); | |
| 712 | const shstrtab_read_len = try preadMin(file, &strtab_buf, shstrtab_off, shstrtab_len); | |
| 712 | 713 | const shstrtab = strtab_buf[0..shstrtab_read_len]; |
| 713 | 714 | |
| 714 | 715 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); |
| ... | ... | @@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct { |
| 717 | 718 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 718 | 719 | // even when the ELF file is 32-bits. |
| 719 | 720 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); |
| 720 | const sh_read_byte_len = try preadFull( | |
| 721 | const sh_read_byte_len = try preadMin( | |
| 721 | 722 | file, |
| 722 | 723 | sh_buf[0 .. sh_buf.len - sh_reserve], |
| 723 | 724 | shoff, |
| ... | ... | @@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct { |
| 751 | 752 | |
| 752 | 753 | if (dynstr) |ds| { |
| 753 | 754 | const strtab_len = std.math.min(ds.size, strtab_buf.len); |
| 754 | const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len); | |
| 755 | const strtab_read_len = try preadMin(file, &strtab_buf, ds.offset, shstrtab_len); | |
| 755 | 756 | const strtab = strtab_buf[0..strtab_read_len]; |
| 756 | 757 | // TODO this pointer cast should not be necessary |
| 757 | 758 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); |
| ... | ... | @@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct { |
| 813 | 814 | return result; |
| 814 | 815 | } |
| 815 | 816 | |
| 816 | fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { | |
| 817 | fn preadMin(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { | |
| 817 | 818 | var i: u64 = 0; |
| 818 | 819 | while (i < min_read_len) { |
| 819 | 820 | const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) { |
| ... | ... | @@ -853,22 +854,6 @@ pub const NativeTargetInfo = struct { |
| 853 | 854 | abi: Target.Abi, |
| 854 | 855 | }; |
| 855 | 856 | |
| 856 | fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { | |
| 857 | if (is_64) { | |
| 858 | if (need_bswap) { | |
| 859 | return @byteSwap(@TypeOf(int_64), int_64); | |
| 860 | } else { | |
| 861 | return int_64; | |
| 862 | } | |
| 863 | } else { | |
| 864 | if (need_bswap) { | |
| 865 | return @byteSwap(@TypeOf(int_32), int_32); | |
| 866 | } else { | |
| 867 | return int_32; | |
| 868 | } | |
| 869 | } | |
| 870 | } | |
| 871 | ||
| 872 | 857 | fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu { |
| 873 | 858 | // Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`, |
| 874 | 859 | // although it is a runtime value, is guaranteed to be one of the architectures in the set |