authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-05 01:55:37-04:00
committergravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2026-06-23 00:27:16-04:00
log344d0ab72c049035cacdca63094c07cd512f89cd
treeb2916958cd0c4161a484aa6e9b675e76ff663629
parentc14bc1bbe09069a2371085e3a1275e30f4665c6b

Coff: handle relocations of absolute symbols

test/link: add absolute symbol tests

5 files changed, 292 insertions(+), 149 deletions(-)

lib/compiler/objdump.zig+6-5
......@@ -1069,11 +1069,12 @@ const coff = struct {
10691069 for (sections.items, 0..) |section, section_i| {
10701070 if (section.header.pointer_to_relocations == 0) continue;
10711071
1072 try w.print(
1073 \\Relocs for section {x} '{s}' in {s}:
1074 \\ Offset Type Symbol -> Sect Name
1075 \\
1076 , .{ section_i + 1, section.name, obj_name });
1072 if (d.element(.@"table-header"))
1073 try w.print(
1074 \\Relocs for section {x} '{s}' in {s}:
1075 \\ Offset Type Symbol -> Sect Name
1076 \\
1077 , .{ section_i + 1, section.name, obj_name });
10771078
10781079 fr.seekTo(file_location + section.header.pointer_to_relocations) catch |err|
10791080 return d.failParse("unable to seek to section {x} relocation table: {t}", .{ section_i + 1, err });
src/link/Coff.zig+216-144
......@@ -1051,11 +1051,11 @@ pub const Symbol = struct {
10511051 };
10521052 }
10531053
1054 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {
1054 pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void {
10551055 const sym = si.get(coff);
10561056 sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff);
1057 si.applyLocationRelocs(coff);
1058 si.applyTargetRelocs(coff, .none);
1057 try si.applyLocationRelocs(coff);
1058 try si.applyTargetRelocs(coff, .none);
10591059
10601060 var alias_sym = sym;
10611061 while (alias_sym.flags.extra_tag == .next_alias_si) {
......@@ -1063,7 +1063,7 @@ pub const Symbol = struct {
10631063 alias_sym = alias_si.get(coff);
10641064 assert(alias_sym.ni == sym.ni);
10651065 alias_sym.rva = sym.rva;
1066 alias_si.applyTargetRelocs(coff, .none);
1066 try alias_si.applyTargetRelocs(coff, .none);
10671067 }
10681068 }
10691069
......@@ -1080,7 +1080,7 @@ pub const Symbol = struct {
10801080 }
10811081 }
10821082
1083 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void {
1083 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) !void {
10841084 const sym = si.get(coff);
10851085 switch (sym.loc_relocs) {
10861086 .none => {},
......@@ -1091,20 +1091,20 @@ pub const Symbol = struct {
10911091 &entry.virtual_address,
10921092 @intCast(coff.computeSymbolSectionOffset(sym) + reloc.offset),
10931093 );
1094 reloc.apply(coff);
1094 try reloc.apply(coff);
10951095 }
10961096 },
10971097 }
10981098 }
10991099
1100 pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff, end: Reloc.Index) void {
1100 pub fn applyTargetRelocs(si: Symbol.Index, coff: *Coff, end: Reloc.Index) !void {
11011101 const sym = si.get(coff);
11021102
11031103 var ri = sym.target_relocs;
11041104 while (ri != end) {
11051105 const reloc = ri.get(coff);
11061106 assert(reloc.target == si);
1107 reloc.apply(coff);
1107 try reloc.apply(coff);
11081108 ri = reloc.next;
11091109 }
11101110 }
......@@ -1166,7 +1166,7 @@ pub const Reloc = extern struct {
11661166 }
11671167 };
11681168
1169 pub fn apply(reloc: *Reloc, coff: *Coff) void {
1169 pub fn apply(reloc: *Reloc, coff: *Coff) !void {
11701170 const loc_sym = reloc.loc.get(coff);
11711171 switch (loc_sym.ni) {
11721172 .none => return,
......@@ -1300,118 +1300,163 @@ pub const Reloc = extern struct {
13001300 }
13011301
13021302 const target_sym = reloc.target.get(coff);
1303 switch (target_sym.ni) {
1304 .none => return,
1305 else => |ni| if (ni.hasMoved(&coff.mf)) return,
1306 }
1303 const is_abs = switch (target_sym.ni) {
1304 .none => if (target_sym.section_number == .ABSOLUTE) true else return,
1305 else => |ni| if (ni.hasMoved(&coff.mf)) return else false,
1306 };
13071307
13081308 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
1309 switch (target_machine) {
1310 else => |machine| @panic(@tagName(machine)),
1311 .AMD64 => switch (reloc.type.AMD64) {
1312 else => |kind| @panic(@tagName(kind)),
1313 .ABSOLUTE => {},
1314 .ADDR64 => std.mem.writeInt(
1315 u64,
1316 loc_slice[0..8],
1317 coff.optionalHeaderField(.image_base) + target_rva,
1318 target_endian,
1319 ),
1320 .ADDR32 => std.mem.writeInt(
1321 u32,
1322 loc_slice[0..4],
1323 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1324 target_endian,
1325 ),
1326 .ADDR32NB => std.mem.writeInt(
1327 u32,
1328 loc_slice[0..4],
1329 @intCast(target_rva),
1330 target_endian,
1331 ),
1332 .REL32 => std.mem.writeInt(
1333 i32,
1334 loc_slice[0..4],
1335 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
1336 target_endian,
1337 ),
1338 .REL32_1 => std.mem.writeInt(
1339 i32,
1340 loc_slice[0..4],
1341 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))),
1342 target_endian,
1343 ),
1344 .REL32_2 => std.mem.writeInt(
1345 i32,
1346 loc_slice[0..4],
1347 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))),
1348 target_endian,
1349 ),
1350 .REL32_3 => std.mem.writeInt(
1351 i32,
1352 loc_slice[0..4],
1353 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))),
1354 target_endian,
1355 ),
1356 .REL32_4 => std.mem.writeInt(
1357 i32,
1358 loc_slice[0..4],
1359 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))),
1360 target_endian,
1361 ),
1362 .REL32_5 => std.mem.writeInt(
1363 i32,
1364 loc_slice[0..4],
1365 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),
1366 target_endian,
1367 ),
1368 .SECREL => std.mem.writeInt(
1369 u32,
1370 loc_slice[0..4],
1371 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
1372 target_endian,
1373 ),
1374 },
1375 .I386 => switch (reloc.type.I386) {
1376 else => |kind| @panic(@tagName(kind)),
1377 .ABSOLUTE => {},
1378 .DIR16 => std.mem.writeInt(
1379 u16,
1380 loc_slice[0..2],
1381 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1382 target_endian,
1383 ),
1384 .REL16 => std.mem.writeInt(
1385 i16,
1386 loc_slice[0..2],
1387 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))),
1388 target_endian,
1389 ),
1390 .DIR32 => std.mem.writeInt(
1391 u32,
1392 loc_slice[0..4],
1393 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1394 target_endian,
1395 ),
1396 .DIR32NB => std.mem.writeInt(
1397 u32,
1398 loc_slice[0..4],
1399 @intCast(target_rva),
1400 target_endian,
1401 ),
1402 .REL32 => std.mem.writeInt(
1403 i32,
1404 loc_slice[0..4],
1405 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
1406 target_endian,
1407 ),
1408 .SECREL => std.mem.writeInt(
1409 u32,
1410 loc_slice[0..4],
1411 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
1412 target_endian,
1413 ),
1414 },
1309 if (is_abs) {
1310 switch (target_machine) {
1311 else => |machine| @panic(@tagName(machine)),
1312 .AMD64 => switch (reloc.type.AMD64) {
1313 // TODO: Report these later, in reportUndefs -> reportRelocErrs ?
1314 else => |kind| return coff.base.comp.link_diags.fail(
1315 "absolute symbol '{s}' targeted by invalid relocation type: {t}",
1316 .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind },
1317 ),
1318 .ABSOLUTE => {},
1319 .ADDR64 => std.mem.writeInt(
1320 u64,
1321 loc_slice[0..8],
1322 target_rva,
1323 target_endian,
1324 ),
1325 .ADDR32 => std.mem.writeInt(
1326 u32,
1327 loc_slice[0..4],
1328 @intCast(target_rva),
1329 target_endian,
1330 ),
1331 },
1332 .I386 => switch (reloc.type.I386) {
1333 else => |kind| return coff.base.comp.link_diags.fail(
1334 "absolute symbol '{s}' targeted by invalid relocation type: {t}",
1335 .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind },
1336 ),
1337 .ABSOLUTE => {},
1338 .DIR16 => std.mem.writeInt(
1339 u16,
1340 loc_slice[0..2],
1341 @intCast(target_rva),
1342 target_endian,
1343 ),
1344 .DIR32 => std.mem.writeInt(
1345 u32,
1346 loc_slice[0..4],
1347 @intCast(target_rva),
1348 target_endian,
1349 ),
1350 },
1351 }
1352 } else {
1353 switch (target_machine) {
1354 else => |machine| @panic(@tagName(machine)),
1355 .AMD64 => switch (reloc.type.AMD64) {
1356 else => |kind| @panic(@tagName(kind)),
1357 .ABSOLUTE => {},
1358 .ADDR64 => std.mem.writeInt(
1359 u64,
1360 loc_slice[0..8],
1361 coff.optionalHeaderField(.image_base) + target_rva,
1362 target_endian,
1363 ),
1364 .ADDR32 => std.mem.writeInt(
1365 u32,
1366 loc_slice[0..4],
1367 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1368 target_endian,
1369 ),
1370 .ADDR32NB => std.mem.writeInt(
1371 u32,
1372 loc_slice[0..4],
1373 @intCast(target_rva),
1374 target_endian,
1375 ),
1376 .REL32 => std.mem.writeInt(
1377 i32,
1378 loc_slice[0..4],
1379 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
1380 target_endian,
1381 ),
1382 .REL32_1 => std.mem.writeInt(
1383 i32,
1384 loc_slice[0..4],
1385 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))),
1386 target_endian,
1387 ),
1388 .REL32_2 => std.mem.writeInt(
1389 i32,
1390 loc_slice[0..4],
1391 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))),
1392 target_endian,
1393 ),
1394 .REL32_3 => std.mem.writeInt(
1395 i32,
1396 loc_slice[0..4],
1397 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))),
1398 target_endian,
1399 ),
1400 .REL32_4 => std.mem.writeInt(
1401 i32,
1402 loc_slice[0..4],
1403 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))),
1404 target_endian,
1405 ),
1406 .REL32_5 => std.mem.writeInt(
1407 i32,
1408 loc_slice[0..4],
1409 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),
1410 target_endian,
1411 ),
1412 .SECREL => std.mem.writeInt(
1413 u32,
1414 loc_slice[0..4],
1415 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
1416 target_endian,
1417 ),
1418 },
1419 .I386 => switch (reloc.type.I386) {
1420 else => |kind| @panic(@tagName(kind)),
1421 .ABSOLUTE => {},
1422 .DIR16 => std.mem.writeInt(
1423 u16,
1424 loc_slice[0..2],
1425 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1426 target_endian,
1427 ),
1428 .REL16 => std.mem.writeInt(
1429 i16,
1430 loc_slice[0..2],
1431 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))),
1432 target_endian,
1433 ),
1434 .DIR32 => std.mem.writeInt(
1435 u32,
1436 loc_slice[0..4],
1437 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1438 target_endian,
1439 ),
1440 .DIR32NB => std.mem.writeInt(
1441 u32,
1442 loc_slice[0..4],
1443 @intCast(target_rva),
1444 target_endian,
1445 ),
1446 .REL32 => std.mem.writeInt(
1447 i32,
1448 loc_slice[0..4],
1449 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
1450 target_endian,
1451 ),
1452 .SECREL => std.mem.writeInt(
1453 u32,
1454 loc_slice[0..4],
1455 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),
1456 target_endian,
1457 ),
1458 },
1459 }
14151460 }
14161461 }
14171462
......@@ -3170,7 +3215,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {
31703215 });
31713216 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
31723217 return error.EndOfStream;
3173 si.applyLocationRelocs(coff);
3218 try si.applyLocationRelocs(coff);
31743219}
31753220
31763221fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
......@@ -3874,9 +3919,12 @@ fn loadObject(
38743919 value: union(enum) {
38753920 // Size of the section
38763921 section: u32,
3877 // Offset within the section
3922 // If section is absolute, the symbol value.
3923 // Otherwise, offset within the section.
38783924 static: u32,
3879 // If section is undefined, the symbol size. Otherwise offset within the section.
3925 // If section is undefined, the symbol size.
3926 // If section is absolute, the symbol value.
3927 // Otherwise offset within the section.
38803928 external: u32,
38813929 // The index of the target symbol of this weak external
38823930 weak_external: u32,
......@@ -3945,7 +3993,10 @@ fn loadObject(
39453993 .STATIC, .LABEL => |storage_class| switch (section_number) {
39463994 // TODO: Do we need to do anything with @feat.00?
39473995 // https://llvm.org/doxygen/namespacellvm_1_1COFF.html#aeffa16735e18df727a173beaf748c392
3948 .UNDEFINED, .DEBUG, .ABSOLUTE => &.{},
3996 .UNDEFINED,
3997 .DEBUG,
3998 => &.{},
3999 .ABSOLUTE => &.{.{ .static = symbol.value }},
39494000 else => |sn| {
39504001 const section = &sections[sn.toIndex()];
39514002
......@@ -4049,12 +4100,9 @@ fn loadObject(
40494100 ),
40504101 },
40514102 .EXTERNAL => switch (section_number) {
4052 .UNDEFINED => &.{.{ .external = symbol.value }},
4053 .ABSOLUTE => return diags.failParse(
4054 path,
4055 "TODO unhandled external absolute symbol 0x{x}: '{s}'",
4056 .{ symbol_i, name },
4057 ),
4103 .UNDEFINED,
4104 .ABSOLUTE,
4105 => &.{.{ .external = symbol.value }},
40584106 .DEBUG => return diags.failParse(
40594107 path,
40604108 "unexpected external symbol 0x{x} in DEBUG section: '{s}'",
......@@ -4517,7 +4565,28 @@ fn loadObject(
45174565 continue;
45184566 },
45194567 },
4520 .ABSOLUTE, .DEBUG => continue,
4568 .ABSOLUTE => {
4569 const value = sym: switch (symbol.value) {
4570 .static => |value| {
4571 symbol.si = coff.addSymbolAssumeCapacity();
4572 break :sym value;
4573 },
4574 .external => |value| {
4575 const global_gop = try coff.getOrPutGlobalSymbol(.{ .name = symbol.name.toSlice(coff) });
4576 symbol.si = global_gop.value_ptr.*;
4577 if (global_gop.found_existing)
4578 return coff.failMultipleDefinitions(path, member_name, symbol.name, index, global_gop.value_ptr.*, .none);
4579 break :sym value;
4580 },
4581 else => unreachable,
4582 };
4583
4584 const sym = symbol.si.get(coff);
4585 sym.rva = value;
4586 sym.section_number = .ABSOLUTE;
4587 continue;
4588 },
4589 .DEBUG => continue,
45214590 else => |sn| &sections[sn.toIndex()],
45224591 };
45234592
......@@ -5198,7 +5267,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
51985267 else => |e| return e,
51995268 };
52005269 si.get(coff).extra.size = @intCast(nw.interface.end);
5201 si.applyLocationRelocs(coff);
5270 try si.applyLocationRelocs(coff);
52025271 }
52035272
52045273 if (nav.resolved.?.@"linksection".unwrap()) |_| {
......@@ -5331,7 +5400,7 @@ fn updateFuncInner(
53315400 else => |e| return e,
53325401 };
53335402 si.get(coff).extra.size = @intCast(nw.interface.end);
5334 si.applyLocationRelocs(coff);
5403 try si.applyLocationRelocs(coff);
53355404}
53365405
53375406pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
......@@ -5433,6 +5502,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
54335502 switch (target_sym.ni) {
54345503 .none => {
54355504 assert(target_sym.gmi != .none);
5505 if (target_sym.section_number == .ABSOLUTE) continue;
54365506 (try undef_indices.addOne(gpa)).* = @intCast(reloc_i);
54375507 },
54385508 else => continue,
......@@ -5481,6 +5551,8 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
54815551 defer prev_loc_si = loc_si;
54825552
54835553 const loc_sym = loc_si.get(coff);
5554
5555 // TODO: Make this a helper for anything that needs to report "referenced by" notes
54845556 switch (coff.getNode(loc_sym.ni)) {
54855557 .data_directories => {
54865558 const dir_align = std.mem.Alignment.of(std.coff.ImageDataDirectory);
......@@ -5958,7 +6030,7 @@ fn flushUav(
59586030 else => |e| return e,
59596031 };
59606032 si.get(coff).extra.size = @intCast(nw.interface.end);
5961 si.applyLocationRelocs(coff);
6033 try si.applyLocationRelocs(coff);
59626034}
59636035
59646036fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !void {
......@@ -5998,7 +6070,7 @@ fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !v
59986070 sym.gmi = alias_sym.gmi;
59996071 coff.globals.values()[gmi.unwrap().?] = alias_si;
60006072 // Only apply the new relocs
6001 alias_si.applyTargetRelocs(coff, prev_target_relocs);
6073 try alias_si.applyTargetRelocs(coff, prev_target_relocs);
60026074}
60036075
60046076fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
......@@ -6407,7 +6479,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
64076479 },
64086480 }
64096481
6410 si.flushMoved(coff);
6482 try si.flushMoved(coff);
64116483 return true;
64126484}
64136485
......@@ -6575,7 +6647,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
65756647 else => |e| return e,
65766648 };
65776649 si.get(coff).extra.size = @intCast(nw.interface.end);
6578 si.applyLocationRelocs(coff);
6650 try si.applyLocationRelocs(coff);
65796651}
65806652
65816653fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
......@@ -6644,10 +6716,10 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
66446716 }
66456717 },
66466718 .input_section => |isi| {
6647 isi.symbol(coff).flushMoved(coff);
6719 try isi.symbol(coff).flushMoved(coff);
66486720 for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |input_symbol| {
66496721 if (input_symbol.si.get(coff).ni != ni) break;
6650 input_symbol.si.flushMoved(coff);
6722 try input_symbol.si.flushMoved(coff);
66516723 }
66526724 },
66536725 .import_directory_table => coff.targetStore(
......@@ -6661,14 +6733,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
66616733 .import_address_table => |import_index| {
66626734 const entry = import_index.get(coff);
66636735 const import_address_table_si = entry.import_address_table_si;
6664 import_address_table_si.flushMoved(coff);
6736 try import_address_table_si.flushMoved(coff);
66656737 coff.targetStore(
66666738 &coff.importDirectoryEntryPtr(import_index).import_address_table_rva,
66676739 import_address_table_si.get(coff).rva,
66686740 );
66696741
66706742 for (entry.import_address_table_symbols.items) |iat_ptr_si|
6671 iat_ptr_si.flushMoved(coff);
6743 try iat_ptr_si.flushMoved(coff);
66726744 },
66736745 .import_hint_name_table => |import_index| {
66746746 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
......@@ -6721,12 +6793,12 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
67216793 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));
67226794 },
67236795 .export_address_table => {
6724 coff.export_table.export_address_table_si.flushMoved(coff);
6796 try coff.export_table.export_address_table_si.flushMoved(coff);
67256797
67266798 // These relocs are applied directly here instead of via the above flushMoved call as
67276799 // they are non-contiguous, and not tracked under export_address_table_si.
67286800 for (coff.export_table.entries.values()) |entry|
6729 entry.export_address_table_ri.get(coff).apply(coff);
6801 try entry.export_address_table_ri.get(coff).apply(coff);
67306802
67316803 coff.targetStore(
67326804 &coff.exportDirectoryTable().export_address_table_rva,
......@@ -6762,7 +6834,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
67626834 .uav,
67636835 .lazy_code,
67646836 .lazy_const_data,
6765 => |mi| mi.symbol(coff).flushMoved(coff),
6837 => |mi| try mi.symbol(coff).flushMoved(coff),
67666838 }
67676839 try ni.childrenMoved(coff.base.comp.gpa, &coff.mf);
67686840}
......@@ -7131,7 +7203,7 @@ fn updateExportsInner(
71317203 export_sym.ni = exported_ni;
71327204 export_sym.rva = exported_sym.rva;
71337205 export_sym.section_number = exported_sym.section_number;
7134 defer export_si.applyTargetRelocs(coff, .none);
7206 defer export_si.applyTargetRelocs(coff, .none) catch unreachable;
71357207
71367208 const prev_alias_sym = prev_alias_si.get(coff);
71377209 switch (prev_alias_sym.flags.extra_tag) {
test/link.zig+59
......@@ -93,6 +93,65 @@ pub fn addCases(ctx: *LinkContext) void {
9393 const run = case.addRunArtifact(exe);
9494 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
9595 }
96
97 if (ctx.includeTest("abs-symbol")) |case| {
98 const abs = case.addObject(.{
99 .name = "abs",
100 .use_llvm = true, // TODO: .globl not supported on self-hosted
101 .use_lld = true,
102 .asm_source_bytes =
103 \\.globl foo
104 \\foo = 0xcafecafe
105 \\
106 ,
107 });
108
109 const abs_reloc = case.addObject(.{
110 .name = "abs_reloc",
111 .use_llvm = true, // TODO: .globl not supported on self-hosted
112 .use_lld = true,
113 .asm_source_bytes =
114 \\.data
115 \\.globl foo_copy
116 \\foo_copy:
117 \\.long foo
118 ,
119 });
120
121 case.verifyObjdump(abs_reloc, &.{
122 "-s",
123 "--relocs",
124 }, .{ .arch = true });
125
126 const exe_reloc_err = case.addExecutable(.{
127 .name = "test-reloc-err",
128 .zig_source_bytes =
129 \\extern const foo: usize;
130 \\pub fn main() !u8 {
131 \\ return @intFromBool(foo != 0xcafecafe);
132 \\}
133 ,
134 });
135 exe_reloc_err.root_module.addObject(abs);
136 case.expectLinkErrors(exe_reloc_err, .{
137 .contains = "error: absolute symbol 'foo' targeted by invalid relocation type: /?/",
138 });
139
140 const exe = case.addExecutable(.{
141 .name = "test",
142 .zig_source_bytes =
143 \\extern var foo_copy: u32;
144 \\pub fn main() !u8 {
145 \\ return @intFromBool(foo_copy != 0xcafecafe);
146 \\}
147 ,
148 });
149 exe.root_module.addObject(abs);
150 exe.root_module.addObject(abs_reloc);
151
152 const run = case.addRunArtifact(exe);
153 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
154 }
96155}
97156
98157const LinkContext = @import("tests.zig").LinkContext;
test/link/snapshots/abs-symbol-x86_64.dmp created+1
......@@ -0,0 +1 @@
1xxxxxxxx ADDR32 xxxxxxxx UNDEF | foo
test/src/Link.zig+10
......@@ -90,6 +90,16 @@ pub const Case = struct {
9090 });
9191 }
9292
93 pub fn expectLinkErrors(
94 self: *const Case,
95 comp: *Step.Compile,
96 expected_errors: Step.Compile.ExpectedCompileErrors,
97 ) void {
98 comp.expect_errors = expected_errors;
99 const bin_file = comp.getEmittedBin();
100 bin_file.addStepDependencies(self.ctx.step);
101 }
102
93103 const SnapshotScope = struct {
94104 /// If a test case has multiple verifyObjdump calls, `opt_sub_name` can
95105 /// be used to differentiate them.