authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-10 22:01:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-03-10 22:01:58-04:00
loged13cffca4c42718cc7239faf7aab642ac67ef77
tree0aeae1f6b9e8dec311bca1904093e3529bd85521
parentbd14a81e301401b5b2a8b849d17d6ae0750272b8
signaturelock-open Commit is signed but in an unrecognized format.

rework some old ELF parsing code and start to fix emitRaw


3 files changed, 120 insertions(+), 303 deletions(-)

lib/std/build/emit_raw.zig+38-74
...@@ -14,11 +14,6 @@ const io = std.io;...@@ -14,11 +14,6 @@ const io = std.io;
14const sort = std.sort;14const sort = std.sort;
15const warn = std.debug.warn;15const warn = std.debug.warn;
1616
17const BinOutStream = io.OutStream(anyerror);
18const BinSeekStream = io.SeekableStream(anyerror, anyerror);
19const ElfSeekStream = io.SeekableStream(anyerror, anyerror);
20const ElfInStream = io.InStream(anyerror);
21
22const BinaryElfSection = struct {17const BinaryElfSection = struct {
23 elfOffset: u64,18 elfOffset: u64,
24 binaryOffset: u64,19 binaryOffset: u64,
...@@ -41,22 +36,21 @@ const BinaryElfOutput = struct {...@@ -41,22 +36,21 @@ const BinaryElfOutput = struct {
4136
42 const Self = @This();37 const Self = @This();
4338
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 pub fn deinit(self: *Self) void {39 pub fn deinit(self: *Self) void {
52 self.sections.deinit();40 self.sections.deinit();
53 self.segments.deinit();41 self.segments.deinit();
54 }42 }
5543
56 pub fn parseElf(self: *Self, elfFile: elf.Elf) !void {44 pub fn parse(allocator: *Allocator, elf_file: File) !Self {
57 const allocator = self.segments.allocator;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);
5850
59 for (elfFile.section_headers) |section, i| {51 var binaryElfOutput = BinaryElfOutput.init(arena_allocator);
52
53 for (elf_hdrs.section_headers) |section, i| {
60 if (sectionValidForOutput(section)) {54 if (sectionValidForOutput(section)) {
61 const newSection = try allocator.create(BinaryElfSection);55 const newSection = try allocator.create(BinaryElfSection);
6256
...@@ -69,19 +63,19 @@ const BinaryElfOutput = struct {...@@ -69,19 +63,19 @@ const BinaryElfOutput = struct {
69 }63 }
70 }64 }
7165
72 for (elfFile.program_headers) |programHeader, i| {66 for (elf_hdrs.program_headers) |phdr, i| {
73 if (programHeader.p_type == elf.PT_LOAD) {67 if (phdr.p_type == elf.PT_LOAD) {
74 const newSegment = try allocator.create(BinaryElfSegment);68 const newSegment = try allocator.create(BinaryElfSegment);
7569
76 newSegment.physicalAddress = if (programHeader.p_paddr != 0) programHeader.p_paddr else programHeader.p_vaddr;70 newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
77 newSegment.virtualAddress = programHeader.p_vaddr;71 newSegment.virtualAddress = phdr.p_vaddr;
78 newSegment.fileSize = @intCast(usize, programHeader.p_filesz);72 newSegment.fileSize = @intCast(usize, phdr.p_filesz);
79 newSegment.elfOffset = programHeader.p_offset;73 newSegment.elfOffset = phdr.p_offset;
80 newSegment.binaryOffset = 0;74 newSegment.binaryOffset = 0;
81 newSegment.firstSection = null;75 newSegment.firstSection = null;
8276
83 for (self.sections.toSlice()) |section| {77 for (self.sections.toSlice()) |section| {
84 if (sectionWithinSegment(section, programHeader)) {78 if (sectionWithinSegment(section, phdr)) {
85 if (section.segment) |sectionSegment| {79 if (section.segment) |sectionSegment| {
86 if (sectionSegment.elfOffset > newSegment.elfOffset) {80 if (sectionSegment.elfOffset > newSegment.elfOffset) {
87 section.segment = newSegment;81 section.segment = newSegment;
...@@ -126,14 +120,17 @@ const BinaryElfOutput = struct {...@@ -126,14 +120,17 @@ const BinaryElfOutput = struct {
126 }120 }
127121
128 sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare);122 sort.sort(*BinaryElfSection, self.sections.toSlice(), sectionSortCompare);
123
124 return self;
129 }125 }
130126
131 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.ProgramHeader) bool {127 fn sectionWithinSegment(section: *BinaryElfSection, segment: elf.Elf64_Phdr) bool {
132 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);128 return segment.p_offset <= section.elfOffset and (segment.p_offset + segment.p_filesz) >= (section.elfOffset + section.fileSize);
133 }129 }
134130
135 fn sectionValidForOutput(section: elf.SectionHeader) bool {131 fn sectionValidForOutput(shdr: var) bool {
136 return section.sh_size > 0 and section.sh_type != elf.SHT_NOBITS and ((section.sh_flags & elf.SHF_ALLOC) == elf.SHF_ALLOC);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 }
138135
139 fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool {136 fn segmentSortCompare(left: *BinaryElfSegment, right: *BinaryElfSegment) bool {
...@@ -151,60 +148,27 @@ const BinaryElfOutput = struct {...@@ -151,60 +148,27 @@ const BinaryElfOutput = struct {
151 }148 }
152};149};
153150
154const WriteContext = struct {151fn writeBinaryElfSection(elf_file: File, out_file: File, section: *BinaryElfSection) !void {
155 inStream: *ElfInStream,152 try out_file.seekTo(section.binaryOffset);
156 inSeekStream: *ElfSeekStream,
157 outStream: *BinOutStream,
158 outSeekStream: *BinSeekStream,
159};
160
161fn writeBinaryElfSection(allocator: *Allocator, context: WriteContext, section: *BinaryElfSection) !void {
162 var readBuffer = try allocator.alloc(u8, section.fileSize);
163 defer allocator.free(readBuffer);
164153
165 try context.inSeekStream.seekTo(section.elfOffset);154 try out_file.writeFileAll(elf_file, .{
166 _ = try context.inStream.read(readBuffer);155 .in_offset = section.elfOffset,
167156 .in_len = section.fileSize,
168 try context.outSeekStream.seekTo(section.binaryOffset);157 });
169 try context.outStream.write(readBuffer);
170}158}
171159
172fn emit_raw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {160fn emitRaw(allocator: *Allocator, elf_path: []const u8, raw_path: []const u8) !void {
173 var arenaAlloc = ArenaAllocator.init(allocator);161 var elf_file = try fs.cwd().openFile(elf_path, .{});
174 errdefer arenaAlloc.deinit();162 defer elf_file.close();
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 };
200163
201 var binaryElfOutput = BinaryElfOutput.init(arena_allocator);164 var out_file = try fs.cwd().createFile(raw_path, .{});
202 defer binaryElfOutput.deinit();165 defer out_file.close();
203166
204 try binaryElfOutput.parseElf(elfFile);167 const binary_elf_output = BinaryElfOutput.parse(allocator, elf_file);
168 defer binary_elf_output.deinit();
205169
206 for (binaryElfOutput.sections.toSlice()) |section| {170 for (binary_elf_output.sections.toSlice()) |section| {
207 try writeBinaryElfSection(allocator, writeContext, section);171 try writeBinaryElfSection(elf_file, out_file, section);
208 }172 }
209}173}
210174
...@@ -250,6 +214,6 @@ pub const InstallRawStep = struct {...@@ -250,6 +214,6 @@ pub const InstallRawStep = struct {
250 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);214 const full_dest_path = builder.getInstallPath(self.dest_dir, self.dest_filename);
251215
252 fs.cwd().makePath(builder.getInstallPath(self.dest_dir, "")) catch unreachable;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,9 +330,7 @@ pub const ET = extern enum(u16) {
330 pub const HIPROC = 0xffff;330 pub const HIPROC = 0xffff;
331};331};
332332
333pub const SectionHeader = Elf64_Shdr;333/// All integers are native endian.
334pub const ProgramHeader = Elf64_Phdr;
335
336const Header = struct {334const Header = struct {
337 endian: builtin.Endian,335 endian: builtin.Endian,
338 is_64: bool,336 is_64: bool,
...@@ -346,9 +344,9 @@ const Header = struct {...@@ -346,9 +344,9 @@ const Header = struct {
346 shstrndx: u16,344 shstrndx: u16,
347};345};
348346
349pub fn readHeader(in_stream: var) !Header {347pub fn readHeader(file: File) !Header {
350 var hdr_buf: [@sizeOf(Elf64_Ehdr)]u8 align(@alignOf(Elf64_Ehdr)) = undefined;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 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);350 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
353 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);351 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
354 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;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,215 +379,85 @@ pub fn readHeader(in_stream: var) !Header {
381 });379 });
382}380}
383381
384pub const Elf = struct {382/// All integers are native endian.
385 seekable_stream: *io.SeekableStream(anyerror, anyerror),383pub const AllHeaders = struct {
386 in_stream: *io.InStream(anyerror),384 header: Header,
387 is_64: bool,385 section_headers: []Elf64_Shdr,
388 endian: builtin.Endian,386 program_headers: []Elf64_Phdr,
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,
398 allocator: *mem.Allocator,387 allocator: *mem.Allocator,
388};
399389
400 pub fn openStream(390pub fn readAllHeaders(allocator: *mem.Allocator, file: File) !AllHeaders {
401 allocator: *mem.Allocator,391 var hdrs: AllHeaders = .{
402 seekable_stream: *io.SeekableStream(anyerror, anyerror),392 .allocator = allocator,
403 in: *io.InStream(anyerror),393 .header = try readHeader(file),
404 ) !Elf {394 .section_headers = undefined,
405 var elf: Elf = undefined;395 .program_headers = undefined,
406 elf.allocator = allocator;396 };
407 elf.seekable_stream = seekable_stream;397 const is_64 = hdrs.header.is_64;
408 elf.in_stream = in;398 const need_bswap = hdrs.header.endian != std.builtin.endian;
409399
410 var magic: [4]u8 = undefined;400 hdrs.section_headers = try allocator.alloc(Elf64_Shdr, hdrs.header.shnum);
411 try in.readNoEof(magic[0..]);401 errdefer hdrs.allocator.free(hdrs.section_headers);
412 if (!mem.eql(u8, &magic, "\x7fELF")) return error.InvalidFormat;402
413403 hdrs.program_headers = try allocator.alloc(Elf64_Phdr, hdrs.header.phnum);
414 elf.is_64 = switch (try in.readByte()) {404 errdefer hdrs.allocator.free(hdrs.program_headers);
415 1 => false,405
416 2 => true,406 // Treat section headers and program headers as byte buffers. For 32-bit ELF and
417 else => return error.InvalidFormat,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 };
419430 }
420 elf.endian = switch (try in.readByte()) {431 for (hdrs.program_headers) |*phdr, i| {
421 1 => .Little,432 phdr.* = .{
422 2 => .Big,433 .p_type = int(is_64, need_bswap, phdrs32[i].p_type, shdr.p_type),
423 else => return error.InvalidFormat,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}
425445
426 const version_byte = try in.readByte();446pub fn int(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) {
427 if (version_byte != 1) return error.InvalidFormat;447 if (is_64) {
428448 if (need_bswap) {
429 // skip over padding449 return @byteSwap(@TypeOf(int_64), int_64);
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 }
500 } else {450 } else {
501 for (elf.program_headers) |*elf_program| {451 return int_64;
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 }
511 }452 }
512453 } else {
513 try seekable_stream.seekTo(elf.section_header_offset);454 if (need_bswap) {
514455 return @byteSwap(@TypeOf(int_32), int_32);
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 }
531 } else {456 } else {
532 for (elf.section_headers) |*elf_section| {457 return int_32;
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 }
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}
593461
594pub const EI_NIDENT = 16;462pub const EI_NIDENT = 16;
595463
lib/std/zig/system.zig+10-25
...@@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct {...@@ -570,7 +570,7 @@ pub const NativeTargetInfo = struct {
570 cross_target: CrossTarget,570 cross_target: CrossTarget,
571 ) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {571 ) AbiAndDynamicLinkerFromFileError!NativeTargetInfo {
572 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined;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 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);574 const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf);
575 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);575 const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf);
576 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;576 if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic;
...@@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct {...@@ -587,6 +587,7 @@ pub const NativeTargetInfo = struct {
587 elf.ELFCLASS64 => true,587 elf.ELFCLASS64 => true,
588 else => return error.InvalidElfClass,588 else => return error.InvalidElfClass,
589 };589 };
590 const elfInt = elf.int;
590 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);591 var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff);
591 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);592 const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize);
592 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);593 const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum);
...@@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct {...@@ -610,7 +611,7 @@ pub const NativeTargetInfo = struct {
610 // Reserve some bytes so that we can deref the 64-bit struct fields611 // Reserve some bytes so that we can deref the 64-bit struct fields
611 // even when the ELF file is 32-bits.612 // even when the ELF file is 32-bits.
612 const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr);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 var ph_buf_i: usize = 0;615 var ph_buf_i: usize = 0;
615 while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({616 while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({
616 ph_i += 1;617 ph_i += 1;
...@@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct {...@@ -625,7 +626,7 @@ pub const NativeTargetInfo = struct {
625 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);626 const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset);
626 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);627 const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz);
627 if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;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 // PT_INTERP includes a null byte in p_filesz.630 // PT_INTERP includes a null byte in p_filesz.
630 const len = p_filesz - 1;631 const len = p_filesz - 1;
631 // dynamic_linker.max_byte is "max", not "len".632 // dynamic_linker.max_byte is "max", not "len".
...@@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct {...@@ -656,7 +657,7 @@ pub const NativeTargetInfo = struct {
656 // Reserve some bytes so that we can deref the 64-bit struct fields657 // Reserve some bytes so that we can deref the 64-bit struct fields
657 // even when the ELF file is 32-bits.658 // even when the ELF file is 32-bits.
658 const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn);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 file,661 file,
661 dyn_buf[0 .. dyn_buf.len - dyn_reserve],662 dyn_buf[0 .. dyn_buf.len - dyn_reserve],
662 dyn_off,663 dyn_off,
...@@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct {...@@ -701,14 +702,14 @@ pub const NativeTargetInfo = struct {
701 var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;702 var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined;
702 if (sh_buf.len < shentsize) return error.InvalidElfFile;703 if (sh_buf.len < shentsize) return error.InvalidElfFile;
703704
704 _ = try preadFull(file, &sh_buf, str_section_off, shentsize);705 _ = try preadMin(file, &sh_buf, str_section_off, shentsize);
705 const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));706 const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf));
706 const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));707 const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf));
707 const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);708 const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset);
708 const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);709 const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size);
709 var strtab_buf: [4096:0]u8 = undefined;710 var strtab_buf: [4096:0]u8 = undefined;
710 const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len);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 const shstrtab = strtab_buf[0..shstrtab_read_len];713 const shstrtab = strtab_buf[0..shstrtab_read_len];
713714
714 const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);715 const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum);
...@@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct {...@@ -717,7 +718,7 @@ pub const NativeTargetInfo = struct {
717 // Reserve some bytes so that we can deref the 64-bit struct fields718 // Reserve some bytes so that we can deref the 64-bit struct fields
718 // even when the ELF file is 32-bits.719 // even when the ELF file is 32-bits.
719 const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr);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 file,722 file,
722 sh_buf[0 .. sh_buf.len - sh_reserve],723 sh_buf[0 .. sh_buf.len - sh_reserve],
723 shoff,724 shoff,
...@@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct {...@@ -751,7 +752,7 @@ pub const NativeTargetInfo = struct {
751752
752 if (dynstr) |ds| {753 if (dynstr) |ds| {
753 const strtab_len = std.math.min(ds.size, strtab_buf.len);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 const strtab = strtab_buf[0..strtab_read_len];756 const strtab = strtab_buf[0..strtab_read_len];
756 // TODO this pointer cast should not be necessary757 // TODO this pointer cast should not be necessary
757 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));758 const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr));
...@@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct {...@@ -813,7 +814,7 @@ pub const NativeTargetInfo = struct {
813 return result;814 return result;
814 }815 }
815816
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 var i: u64 = 0;818 var i: u64 = 0;
818 while (i < min_read_len) {819 while (i < min_read_len) {
819 const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) {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,22 +854,6 @@ pub const NativeTargetInfo = struct {
853 abi: Target.Abi,854 abi: Target.Abi,
854 };855 };
855856
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 fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {857 fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_target: CrossTarget) ?Target.Cpu {
873 // Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,858 // Here we switch on a comptime value rather than `cpu_arch`. This is valid because `cpu_arch`,
874 // although it is a runtime value, is guaranteed to be one of the architectures in the set859 // although it is a runtime value, is guaranteed to be one of the architectures in the set