diff --git a/src/link/Elf/Archive.zig b/src/link/Elf/Archive.zig index 0157b18fb4..d1216fcbba 100644 --- a/src/link/Elf/Archive.zig +++ b/src/link/Elf/Archive.zig @@ -34,8 +34,6 @@ pub fn parse( defer strtab.deinit(gpa); while (pos < size) { - pos = mem.alignForward(usize, pos, 2); - var hdr: elf.ar_hdr = undefined; { const n = try handle.preadAll(mem.asBytes(&hdr), pos); @@ -50,7 +48,7 @@ pub fn parse( } const obj_size = try hdr.size(); - defer pos += obj_size; + defer pos = std.mem.alignForward(usize, pos + obj_size, 2); if (hdr.isSymtab() or hdr.isSymtab64()) continue; if (hdr.isStrtab()) { diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig index 687aa5963b..c985c32fc9 100644 --- a/src/link/Elf2.zig +++ b/src/link/Elf2.zig @@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || switch (input) { else => {}, .object => |object| { - var fsr: FileSliceReader = .init(object.file.reader(io, &.{})); - fsr.reset(try fsr.file.getSize(), &buf); - elf.loadObject(object.path, null, &fsr) catch |err| switch (err) { - error.ReadFailed => return fsr.file.err.?, + var fr = object.file.reader(io, &buf); + elf.loadObject(object.path, null, &fr, .{ + .offset = fr.logicalPos(), + .size = try fr.getSize(), + }) catch |err| switch (err) { + error.ReadFailed => return fr.err.?, else => |e| return e, }; }, .archive => |archive| { - var fsr: FileSliceReader = .init(archive.file.reader(io, &buf)); - elf.loadArchive(archive.path, &fsr) catch |err| switch (err) { - error.ReadFailed => return fsr.file.err.?, + var fr = archive.file.reader(io, &buf); + elf.loadArchive(archive.path, &fr) catch |err| switch (err) { + error.ReadFailed => return fr.err.?, else => |e| return e, }; }, } } -const FileSliceReader = struct { - file: std.Io.File.Reader, - file_location: MappedFile.Node.FileLocation, - reader: std.Io.Reader.Limited, - - pub fn init(file: std.Io.File.Reader) FileSliceReader { - return .{ .file = file, .file_location = undefined, .reader = undefined }; - } - - pub fn reset(fsr: *FileSliceReader, size: u64, buffer: []u8) void { - fsr.file_location = .{ - .offset = fsr.file.logicalPos(), - .size = size, - }; - fsr.reader = .init(&fsr.file.interface, .limited(@intCast(size)), buffer); - } - - pub fn pos(fsr: *const FileSliceReader) u64 { - return fsr.file.logicalPos() - fsr.file_location.offset; - } - - pub fn logicalPos(fsr: *const FileSliceReader) u64 { - return fsr.pos() - fsr.reader.interface.bufferedLen(); - } - - pub fn seekTo(fsr: *FileSliceReader, offset: u64) std.Io.File.Reader.SeekError!void { - if (offset > fsr.file_location.size) return error.EndOfStream; - const logical_pos = fsr.logicalPos(); - if (offset < logical_pos or offset >= fsr.pos()) { - fsr.reader.interface.tossBuffered(); - try fsr.file.seekTo(fsr.file_location.offset + offset); - fsr.reader.remaining = .limited(@intCast(fsr.file_location.size - offset)); - } else fsr.reader.interface.toss(@intCast(offset - logical_pos)); - } -}; -fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !void { +fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void { const comp = elf.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; - const r = &fsr.file.interface; + const r = &fr.interface; log.debug("loadArchive({f})", .{path.fmtEscapeString()}); if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) @@ -1333,6 +1300,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) return diags.failParse(path, "bad file magic", .{}); + const offset = fr.logicalPos(); const size = header.size() catch return diags.failParse(path, "bad member size", .{}); if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) { @@ -1361,15 +1329,11 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo error.Overflow => return diags.failParse(path, "bad member name offset", .{}), }; if (!std.mem.endsWith(u8, member, ".o")) break :load_object; - var buf: [4096]u8 = undefined; - fsr.reset(size, &buf); - try elf.loadObject(path, member, fsr); - try fsr.seekTo(size); - continue; + try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size }); } - try r.discardAll(size); + try fr.seekTo(std.mem.alignForward(u64, offset + size, 2)); } else |err| switch (err) { - error.EndOfStream => if (!fsr.file.atEnd()) return error.EndOfStream, + error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream, else => |e| return e, } } @@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { try w.print("({f})", .{std.zig.fmtString(member orelse return)}); } -fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *FileSliceReader) !void { +fn loadObject( + elf: *Elf, + path: std.Build.Cache.Path, + member: ?[]const u8, + fr: *std.Io.File.Reader, + fl: MappedFile.Node.FileLocation, +) !void { const comp = elf.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; - const r = &fsr.reader.interface; + const r = &fr.interface; const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); @@ -1411,11 +1381,13 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * if (ehdr.machine != elf.ehdrField(.machine)) return diags.failParse(path, "bad machine", .{}); if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; + if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size) + return diags.failParse(path, "bad section header offset/size", .{}); if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) return diags.failParse(path, "unsupported shentsize", .{}); const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); defer gpa.free(sections); - try fsr.seekTo(ehdr.shoff); + try fr.seekTo(fl.offset + ehdr.shoff); for (sections) |*section| { section.* = .{ .shdr = try r.peekStruct(ElfN.Shdr, target_endian), @@ -1424,7 +1396,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * try r.discardAll(ehdr.shentsize); switch (section.shdr.type) { std.elf.SHT_NULL, std.elf.SHT_NOBITS => {}, - else => if (section.shdr.offset + section.shdr.size > fsr.file_location.size) + else => if (section.shdr.offset + section.shdr.size > fl.size) return diags.failParse(path, "bad section offset/size", .{}), } } @@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * return diags.failParse(path, "invalid shstrtab type", .{}); const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); errdefer gpa.free(shstrtab); - try fsr.seekTo(shdr.offset); + try fr.seekTo(fl.offset + shdr.offset); try r.readSliceAll(shstrtab); break :shstrtab shstrtab; }; @@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * .ii = ii, .si = section.si, .file_location = .{ - .offset = fsr.file_location.offset + section.shdr.offset, + .offset = fl.offset + section.shdr.offset, .size = section.shdr.size, }, }; @@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * return diags.failParse(path, "invalid strtab type", .{}); const strtab = try gpa.alloc(u8, @intCast(shdr.size)); errdefer gpa.free(strtab); - try fsr.seekTo(shdr.offset); + try fr.seekTo(fl.offset + shdr.offset); try r.readSliceAll(strtab); break :strtab strtab; }; @@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * .{ symtab.shdr.size, symtab.shdr.entsize }, ); symmap.clearRetainingCapacity(); - try symmap.resize(gpa, symnum); + try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue); try elf.symtab.ensureUnusedCapacity(gpa, symnum); try elf.globals.ensureUnusedCapacity(gpa, symnum); - try fsr.seekTo(symtab.shdr.offset + symtab.shdr.entsize); - symmap.items[0] = .null; - for (symmap.items[1..]) |*si| { + try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize); + for (symmap.items) |*si| { si.* = .null; const input_sym = try r.peekStruct(ElfN.Sym, target_endian); try r.discardAll64(symtab.shdr.entsize); @@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * .{ rels.shdr.size, rels.shdr.entsize }, ); try elf.relocs.ensureUnusedCapacity(gpa, relnum); - try fsr.seekTo(rels.shdr.offset); + try fr.seekTo(fl.offset + rels.shdr.offset); for (0..relnum) |_| { const rel = try r.peekStruct(Rel, target_endian); try r.discardAll64(rels.shdr.entsize); if (rel.info.sym >= symnum) continue; - const target_si = symmap.items[rel.info.sym]; + const target_si = symmap.items[rel.info.sym - 1]; if (target_si == .null) continue; elf.addRelocAssumeCapacity( loc_sec.si,