authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:03:38-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-10-29 18:14:16-04:00
log40901440a620caf1849c627cff0d3a96eda273f5
tree951d56b9233963cec61f08b0620dee9b43422481
parentc4478e078b88c836b53d0e42065b0f68e62c0add

Elf2: simplify archive loading


2 files changed, 36 insertions(+), 67 deletions(-)

src/link/Elf/Archive.zig+1-3
......@@ -34,8 +34,6 @@ pub fn parse(
3434 defer strtab.deinit(gpa);
3535
3636 while (pos < size) {
37 pos = mem.alignForward(usize, pos, 2);
38
3937 var hdr: elf.ar_hdr = undefined;
4038 {
4139 const n = try handle.preadAll(mem.asBytes(&hdr), pos);
......@@ -50,7 +48,7 @@ pub fn parse(
5048 }
5149
5250 const obj_size = try hdr.size();
53 defer pos += obj_size;
51 defer pos = std.mem.alignForward(usize, pos + obj_size, 2);
5452
5553 if (hdr.isSymtab() or hdr.isSymtab64()) continue;
5654 if (hdr.isStrtab()) {
src/link/Elf2.zig+35-64
......@@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError ||
12681268 switch (input) {
12691269 else => {},
12701270 .object => |object| {
1271 var fsr: FileSliceReader = .init(object.file.reader(io, &.{}));
1272 fsr.reset(try fsr.file.getSize(), &buf);
1273 elf.loadObject(object.path, null, &fsr) catch |err| switch (err) {
1274 error.ReadFailed => return fsr.file.err.?,
1271 var fr = object.file.reader(io, &buf);
1272 elf.loadObject(object.path, null, &fr, .{
1273 .offset = fr.logicalPos(),
1274 .size = try fr.getSize(),
1275 }) catch |err| switch (err) {
1276 error.ReadFailed => return fr.err.?,
12751277 else => |e| return e,
12761278 };
12771279 },
12781280 .archive => |archive| {
1279 var fsr: FileSliceReader = .init(archive.file.reader(io, &buf));
1280 elf.loadArchive(archive.path, &fsr) catch |err| switch (err) {
1281 error.ReadFailed => return fsr.file.err.?,
1281 var fr = archive.file.reader(io, &buf);
1282 elf.loadArchive(archive.path, &fr) catch |err| switch (err) {
1283 error.ReadFailed => return fr.err.?,
12821284 else => |e| return e,
12831285 };
12841286 },
12851287 }
12861288}
1287const FileSliceReader = struct {
1288 file: std.Io.File.Reader,
1289 file_location: MappedFile.Node.FileLocation,
1290 reader: std.Io.Reader.Limited,
1291
1292 pub fn init(file: std.Io.File.Reader) FileSliceReader {
1293 return .{ .file = file, .file_location = undefined, .reader = undefined };
1294 }
1295
1296 pub fn reset(fsr: *FileSliceReader, size: u64, buffer: []u8) void {
1297 fsr.file_location = .{
1298 .offset = fsr.file.logicalPos(),
1299 .size = size,
1300 };
1301 fsr.reader = .init(&fsr.file.interface, .limited(@intCast(size)), buffer);
1302 }
1303
1304 pub fn pos(fsr: *const FileSliceReader) u64 {
1305 return fsr.file.logicalPos() - fsr.file_location.offset;
1306 }
1307
1308 pub fn logicalPos(fsr: *const FileSliceReader) u64 {
1309 return fsr.pos() - fsr.reader.interface.bufferedLen();
1310 }
1311
1312 pub fn seekTo(fsr: *FileSliceReader, offset: u64) std.Io.File.Reader.SeekError!void {
1313 if (offset > fsr.file_location.size) return error.EndOfStream;
1314 const logical_pos = fsr.logicalPos();
1315 if (offset < logical_pos or offset >= fsr.pos()) {
1316 fsr.reader.interface.tossBuffered();
1317 try fsr.file.seekTo(fsr.file_location.offset + offset);
1318 fsr.reader.remaining = .limited(@intCast(fsr.file_location.size - offset));
1319 } else fsr.reader.interface.toss(@intCast(offset - logical_pos));
1320 }
1321};
1322fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !void {
1289fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void {
13231290 const comp = elf.base.comp;
13241291 const gpa = comp.gpa;
13251292 const diags = &comp.link_diags;
1326 const r = &fsr.file.interface;
1293 const r = &fr.interface;
13271294
13281295 log.debug("loadArchive({f})", .{path.fmtEscapeString()});
13291296 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
13331300 while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| {
13341301 if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG))
13351302 return diags.failParse(path, "bad file magic", .{});
1303 const offset = fr.logicalPos();
13361304 const size = header.size() catch
13371305 return diags.failParse(path, "bad member size", .{});
13381306 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
13611329 error.Overflow => return diags.failParse(path, "bad member name offset", .{}),
13621330 };
13631331 if (!std.mem.endsWith(u8, member, ".o")) break :load_object;
1364 var buf: [4096]u8 = undefined;
1365 fsr.reset(size, &buf);
1366 try elf.loadObject(path, member, fsr);
1367 try fsr.seekTo(size);
1368 continue;
1332 try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size });
13691333 }
1370 try r.discardAll(size);
1334 try fr.seekTo(std.mem.alignForward(u64, offset + size, 2));
13711335 } else |err| switch (err) {
1372 error.EndOfStream => if (!fsr.file.atEnd()) return error.EndOfStream,
1336 error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream,
13731337 else => |e| return e,
13741338 }
13751339}
......@@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc
13791343fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void {
13801344 try w.print("({f})", .{std.zig.fmtString(member orelse return)});
13811345}
1382fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *FileSliceReader) !void {
1346fn loadObject(
1347 elf: *Elf,
1348 path: std.Build.Cache.Path,
1349 member: ?[]const u8,
1350 fr: *std.Io.File.Reader,
1351 fl: MappedFile.Node.FileLocation,
1352) !void {
13831353 const comp = elf.base.comp;
13841354 const gpa = comp.gpa;
13851355 const diags = &comp.link_diags;
1386 const r = &fsr.reader.interface;
1356 const r = &fr.interface;
13871357
13881358 const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len);
13891359 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: *
14111381 if (ehdr.machine != elf.ehdrField(.machine))
14121382 return diags.failParse(path, "bad machine", .{});
14131383 if (ehdr.shoff == 0 or ehdr.shnum <= 1) return;
1384 if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size)
1385 return diags.failParse(path, "bad section header offset/size", .{});
14141386 if (ehdr.shentsize < @sizeOf(ElfN.Shdr))
14151387 return diags.failParse(path, "unsupported shentsize", .{});
14161388 const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum);
14171389 defer gpa.free(sections);
1418 try fsr.seekTo(ehdr.shoff);
1390 try fr.seekTo(fl.offset + ehdr.shoff);
14191391 for (sections) |*section| {
14201392 section.* = .{
14211393 .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: *
14241396 try r.discardAll(ehdr.shentsize);
14251397 switch (section.shdr.type) {
14261398 std.elf.SHT_NULL, std.elf.SHT_NOBITS => {},
1427 else => if (section.shdr.offset + section.shdr.size > fsr.file_location.size)
1399 else => if (section.shdr.offset + section.shdr.size > fl.size)
14281400 return diags.failParse(path, "bad section offset/size", .{}),
14291401 }
14301402 }
......@@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
14361408 return diags.failParse(path, "invalid shstrtab type", .{});
14371409 const shstrtab = try gpa.alloc(u8, @intCast(shdr.size));
14381410 errdefer gpa.free(shstrtab);
1439 try fsr.seekTo(shdr.offset);
1411 try fr.seekTo(fl.offset + shdr.offset);
14401412 try r.readSliceAll(shstrtab);
14411413 break :shstrtab shstrtab;
14421414 };
......@@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
14701442 .ii = ii,
14711443 .si = section.si,
14721444 .file_location = .{
1473 .offset = fsr.file_location.offset + section.shdr.offset,
1445 .offset = fl.offset + section.shdr.offset,
14741446 .size = section.shdr.size,
14751447 },
14761448 };
......@@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
14921464 return diags.failParse(path, "invalid strtab type", .{});
14931465 const strtab = try gpa.alloc(u8, @intCast(shdr.size));
14941466 errdefer gpa.free(strtab);
1495 try fsr.seekTo(shdr.offset);
1467 try fr.seekTo(fl.offset + shdr.offset);
14961468 try r.readSliceAll(strtab);
14971469 break :strtab strtab;
14981470 };
......@@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
15071479 .{ symtab.shdr.size, symtab.shdr.entsize },
15081480 );
15091481 symmap.clearRetainingCapacity();
1510 try symmap.resize(gpa, symnum);
1482 try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue);
15111483 try elf.symtab.ensureUnusedCapacity(gpa, symnum);
15121484 try elf.globals.ensureUnusedCapacity(gpa, symnum);
1513 try fsr.seekTo(symtab.shdr.offset + symtab.shdr.entsize);
1514 symmap.items[0] = .null;
1515 for (symmap.items[1..]) |*si| {
1485 try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize);
1486 for (symmap.items) |*si| {
15161487 si.* = .null;
15171488 const input_sym = try r.peekStruct(ElfN.Sym, target_endian);
15181489 try r.discardAll64(symtab.shdr.entsize);
......@@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *
15941565 .{ rels.shdr.size, rels.shdr.entsize },
15951566 );
15961567 try elf.relocs.ensureUnusedCapacity(gpa, relnum);
1597 try fsr.seekTo(rels.shdr.offset);
1568 try fr.seekTo(fl.offset + rels.shdr.offset);
15981569 for (0..relnum) |_| {
15991570 const rel = try r.peekStruct(Rel, target_endian);
16001571 try r.discardAll64(rels.shdr.entsize);
16011572 if (rel.info.sym >= symnum) continue;
1602 const target_si = symmap.items[rel.info.sym];
1573 const target_si = symmap.items[rel.info.sym - 1];
16031574 if (target_si == .null) continue;
16041575 elf.addRelocAssumeCapacity(
16051576 loc_sec.si,