| ... | @@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || | ... | @@ -1268,62 +1268,29 @@ pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || |
| 1268 | switch (input) { | 1268 | switch (input) { |
| 1269 | else => {}, | 1269 | else => {}, |
| 1270 | .object => |object| { | 1270 | .object => |object| { |
| 1271 | var fsr: FileSliceReader = .init(object.file.reader(io, &.{})); | 1271 | var fr = object.file.reader(io, &buf); |
| 1272 | fsr.reset(try fsr.file.getSize(), &buf); | 1272 | elf.loadObject(object.path, null, &fr, .{ |
| 1273 | elf.loadObject(object.path, null, &fsr) catch |err| switch (err) { | 1273 | .offset = fr.logicalPos(), |
| 1274 | error.ReadFailed => return fsr.file.err.?, | 1274 | .size = try fr.getSize(), |
| | 1275 | }) catch |err| switch (err) { |
| | 1276 | error.ReadFailed => return fr.err.?, |
| 1275 | else => |e| return e, | 1277 | else => |e| return e, |
| 1276 | }; | 1278 | }; |
| 1277 | }, | 1279 | }, |
| 1278 | .archive => |archive| { | 1280 | .archive => |archive| { |
| 1279 | var fsr: FileSliceReader = .init(archive.file.reader(io, &buf)); | 1281 | var fr = archive.file.reader(io, &buf); |
| 1280 | elf.loadArchive(archive.path, &fsr) catch |err| switch (err) { | 1282 | elf.loadArchive(archive.path, &fr) catch |err| switch (err) { |
| 1281 | error.ReadFailed => return fsr.file.err.?, | 1283 | error.ReadFailed => return fr.err.?, |
| 1282 | else => |e| return e, | 1284 | else => |e| return e, |
| 1283 | }; | 1285 | }; |
| 1284 | }, | 1286 | }, |
| 1285 | } | 1287 | } |
| 1286 | } | 1288 | } |
| 1287 | const FileSliceReader = struct { | 1289 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void { |
| 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 | }; | | |
| 1322 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !void { | | |
| 1323 | const comp = elf.base.comp; | 1290 | const comp = elf.base.comp; |
| 1324 | const gpa = comp.gpa; | 1291 | const gpa = comp.gpa; |
| 1325 | const diags = &comp.link_diags; | 1292 | const diags = &comp.link_diags; |
| 1326 | const r = &fsr.file.interface; | 1293 | const r = &fr.interface; |
| 1327 | | 1294 | |
| 1328 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); | 1295 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 1329 | if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) | 1296 | 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 | ... | @@ -1333,6 +1300,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo |
| 1333 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { | 1300 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { |
| 1334 | if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) | 1301 | if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) |
| 1335 | return diags.failParse(path, "bad file magic", .{}); | 1302 | return diags.failParse(path, "bad file magic", .{}); |
| | 1303 | const offset = fr.logicalPos(); |
| 1336 | const size = header.size() catch | 1304 | const size = header.size() catch |
| 1337 | return diags.failParse(path, "bad member size", .{}); | 1305 | return diags.failParse(path, "bad member size", .{}); |
| 1338 | if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) { | 1306 | 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 | ... | @@ -1361,15 +1329,11 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fsr: *FileSliceReader) !vo |
| 1361 | error.Overflow => return diags.failParse(path, "bad member name offset", .{}), | 1329 | error.Overflow => return diags.failParse(path, "bad member name offset", .{}), |
| 1362 | }; | 1330 | }; |
| 1363 | if (!std.mem.endsWith(u8, member, ".o")) break :load_object; | 1331 | if (!std.mem.endsWith(u8, member, ".o")) break :load_object; |
| 1364 | var buf: [4096]u8 = undefined; | 1332 | try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size }); |
| 1365 | fsr.reset(size, &buf); | | |
| 1366 | try elf.loadObject(path, member, fsr); | | |
| 1367 | try fsr.seekTo(size); | | |
| 1368 | continue; | | |
| 1369 | } | 1333 | } |
| 1370 | try r.discardAll(size); | 1334 | try fr.seekTo(std.mem.alignForward(u64, offset + size, 2)); |
| 1371 | } else |err| switch (err) { | 1335 | } else |err| switch (err) { |
| 1372 | error.EndOfStream => if (!fsr.file.atEnd()) return error.EndOfStream, | 1336 | error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream, |
| 1373 | else => |e| return e, | 1337 | else => |e| return e, |
| 1374 | } | 1338 | } |
| 1375 | } | 1339 | } |
| ... | @@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc | ... | @@ -1379,11 +1343,17 @@ fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEsc |
| 1379 | fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { | 1343 | fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 1380 | try w.print("({f})", .{std.zig.fmtString(member orelse return)}); | 1344 | try w.print("({f})", .{std.zig.fmtString(member orelse return)}); |
| 1381 | } | 1345 | } |
| 1382 | fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: *FileSliceReader) !void { | 1346 | fn 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 { |
| 1383 | const comp = elf.base.comp; | 1353 | const comp = elf.base.comp; |
| 1384 | const gpa = comp.gpa; | 1354 | const gpa = comp.gpa; |
| 1385 | const diags = &comp.link_diags; | 1355 | const diags = &comp.link_diags; |
| 1386 | const r = &fsr.reader.interface; | 1356 | const r = &fr.interface; |
| 1387 | | 1357 | |
| 1388 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); | 1358 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| 1389 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); | 1359 | 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: * | ... | @@ -1411,11 +1381,13 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1411 | if (ehdr.machine != elf.ehdrField(.machine)) | 1381 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 1412 | return diags.failParse(path, "bad machine", .{}); | 1382 | return diags.failParse(path, "bad machine", .{}); |
| 1413 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; | 1383 | 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", .{}); |
| 1414 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) | 1386 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 1415 | return diags.failParse(path, "unsupported shentsize", .{}); | 1387 | return diags.failParse(path, "unsupported shentsize", .{}); |
| 1416 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); | 1388 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); |
| 1417 | defer gpa.free(sections); | 1389 | defer gpa.free(sections); |
| 1418 | try fsr.seekTo(ehdr.shoff); | 1390 | try fr.seekTo(fl.offset + ehdr.shoff); |
| 1419 | for (sections) |*section| { | 1391 | for (sections) |*section| { |
| 1420 | section.* = .{ | 1392 | section.* = .{ |
| 1421 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), | 1393 | .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: * | ... | @@ -1424,7 +1396,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1424 | try r.discardAll(ehdr.shentsize); | 1396 | try r.discardAll(ehdr.shentsize); |
| 1425 | switch (section.shdr.type) { | 1397 | switch (section.shdr.type) { |
| 1426 | std.elf.SHT_NULL, std.elf.SHT_NOBITS => {}, | 1398 | 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) |
| 1428 | return diags.failParse(path, "bad section offset/size", .{}), | 1400 | return diags.failParse(path, "bad section offset/size", .{}), |
| 1429 | } | 1401 | } |
| 1430 | } | 1402 | } |
| ... | @@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * | ... | @@ -1436,7 +1408,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1436 | return diags.failParse(path, "invalid shstrtab type", .{}); | 1408 | return diags.failParse(path, "invalid shstrtab type", .{}); |
| 1437 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); | 1409 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1438 | errdefer gpa.free(shstrtab); | 1410 | errdefer gpa.free(shstrtab); |
| 1439 | try fsr.seekTo(shdr.offset); | 1411 | try fr.seekTo(fl.offset + shdr.offset); |
| 1440 | try r.readSliceAll(shstrtab); | 1412 | try r.readSliceAll(shstrtab); |
| 1441 | break :shstrtab shstrtab; | 1413 | break :shstrtab shstrtab; |
| 1442 | }; | 1414 | }; |
| ... | @@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * | ... | @@ -1470,7 +1442,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1470 | .ii = ii, | 1442 | .ii = ii, |
| 1471 | .si = section.si, | 1443 | .si = section.si, |
| 1472 | .file_location = .{ | 1444 | .file_location = .{ |
| 1473 | .offset = fsr.file_location.offset + section.shdr.offset, | 1445 | .offset = fl.offset + section.shdr.offset, |
| 1474 | .size = section.shdr.size, | 1446 | .size = section.shdr.size, |
| 1475 | }, | 1447 | }, |
| 1476 | }; | 1448 | }; |
| ... | @@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * | ... | @@ -1492,7 +1464,7 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1492 | return diags.failParse(path, "invalid strtab type", .{}); | 1464 | return diags.failParse(path, "invalid strtab type", .{}); |
| 1493 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); | 1465 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1494 | errdefer gpa.free(strtab); | 1466 | errdefer gpa.free(strtab); |
| 1495 | try fsr.seekTo(shdr.offset); | 1467 | try fr.seekTo(fl.offset + shdr.offset); |
| 1496 | try r.readSliceAll(strtab); | 1468 | try r.readSliceAll(strtab); |
| 1497 | break :strtab strtab; | 1469 | break :strtab strtab; |
| 1498 | }; | 1470 | }; |
| ... | @@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * | ... | @@ -1507,12 +1479,11 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1507 | .{ symtab.shdr.size, symtab.shdr.entsize }, | 1479 | .{ symtab.shdr.size, symtab.shdr.entsize }, |
| 1508 | ); | 1480 | ); |
| 1509 | symmap.clearRetainingCapacity(); | 1481 | symmap.clearRetainingCapacity(); |
| 1510 | try symmap.resize(gpa, symnum); | 1482 | try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue); |
| 1511 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); | 1483 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); |
| 1512 | try elf.globals.ensureUnusedCapacity(gpa, symnum); | 1484 | try elf.globals.ensureUnusedCapacity(gpa, symnum); |
| 1513 | try fsr.seekTo(symtab.shdr.offset + symtab.shdr.entsize); | 1485 | try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize); |
| 1514 | symmap.items[0] = .null; | 1486 | for (symmap.items) |*si| { |
| 1515 | for (symmap.items[1..]) |*si| { | | |
| 1516 | si.* = .null; | 1487 | si.* = .null; |
| 1517 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); | 1488 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 1518 | try r.discardAll64(symtab.shdr.entsize); | 1489 | try r.discardAll64(symtab.shdr.entsize); |
| ... | @@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * | ... | @@ -1594,12 +1565,12 @@ fn loadObject(elf: *Elf, path: std.Build.Cache.Path, member: ?[]const u8, fsr: * |
| 1594 | .{ rels.shdr.size, rels.shdr.entsize }, | 1565 | .{ rels.shdr.size, rels.shdr.entsize }, |
| 1595 | ); | 1566 | ); |
| 1596 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); | 1567 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); |
| 1597 | try fsr.seekTo(rels.shdr.offset); | 1568 | try fr.seekTo(fl.offset + rels.shdr.offset); |
| 1598 | for (0..relnum) |_| { | 1569 | for (0..relnum) |_| { |
| 1599 | const rel = try r.peekStruct(Rel, target_endian); | 1570 | const rel = try r.peekStruct(Rel, target_endian); |
| 1600 | try r.discardAll64(rels.shdr.entsize); | 1571 | try r.discardAll64(rels.shdr.entsize); |
| 1601 | if (rel.info.sym >= symnum) continue; | 1572 | 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]; |
| 1603 | if (target_si == .null) continue; | 1574 | if (target_si == .null) continue; |
| 1604 | elf.addRelocAssumeCapacity( | 1575 | elf.addRelocAssumeCapacity( |
| 1605 | loc_sec.si, | 1576 | loc_sec.si, |