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 {...@@ -1069,11 +1069,12 @@ const coff = struct {
1069 for (sections.items, 0..) |section, section_i| {1069 for (sections.items, 0..) |section, section_i| {
1070 if (section.header.pointer_to_relocations == 0) continue;1070 if (section.header.pointer_to_relocations == 0) continue;
10711071
1072 try w.print(1072 if (d.element(.@"table-header"))
1073 \\Relocs for section {x} '{s}' in {s}:1073 try w.print(
1074 \\ Offset Type Symbol -> Sect Name1074 \\Relocs for section {x} '{s}' in {s}:
1075 \\1075 \\ Offset Type Symbol -> Sect Name
1076 , .{ section_i + 1, section.name, obj_name });1076 \\
1077 , .{ section_i + 1, section.name, obj_name });
10771078
1078 fr.seekTo(file_location + section.header.pointer_to_relocations) catch |err|1079 fr.seekTo(file_location + section.header.pointer_to_relocations) catch |err|
1079 return d.failParse("unable to seek to section {x} relocation table: {t}", .{ section_i + 1, err });1080 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 {...@@ -1051,11 +1051,11 @@ pub const Symbol = struct {
1051 };1051 };
1052 }1052 }
10531053
1054 pub fn flushMoved(si: Symbol.Index, coff: *Coff) void {1054 pub fn flushMoved(si: Symbol.Index, coff: *Coff) !void {
1055 const sym = si.get(coff);1055 const sym = si.get(coff);
1056 sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff);1056 sym.rva = coff.computeNodeRva(sym.ni) + sym.nodeOffset(coff);
1057 si.applyLocationRelocs(coff);1057 try si.applyLocationRelocs(coff);
1058 si.applyTargetRelocs(coff, .none);1058 try si.applyTargetRelocs(coff, .none);
10591059
1060 var alias_sym = sym;1060 var alias_sym = sym;
1061 while (alias_sym.flags.extra_tag == .next_alias_si) {1061 while (alias_sym.flags.extra_tag == .next_alias_si) {
...@@ -1063,7 +1063,7 @@ pub const Symbol = struct {...@@ -1063,7 +1063,7 @@ pub const Symbol = struct {
1063 alias_sym = alias_si.get(coff);1063 alias_sym = alias_si.get(coff);
1064 assert(alias_sym.ni == sym.ni);1064 assert(alias_sym.ni == sym.ni);
1065 alias_sym.rva = sym.rva;1065 alias_sym.rva = sym.rva;
1066 alias_si.applyTargetRelocs(coff, .none);1066 try alias_si.applyTargetRelocs(coff, .none);
1067 }1067 }
1068 }1068 }
10691069
...@@ -1080,7 +1080,7 @@ pub const Symbol = struct {...@@ -1080,7 +1080,7 @@ pub const Symbol = struct {
1080 }1080 }
1081 }1081 }
10821082
1083 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) void {1083 pub fn applyLocationRelocs(si: Symbol.Index, coff: *Coff) !void {
1084 const sym = si.get(coff);1084 const sym = si.get(coff);
1085 switch (sym.loc_relocs) {1085 switch (sym.loc_relocs) {
1086 .none => {},1086 .none => {},
...@@ -1091,20 +1091,20 @@ pub const Symbol = struct {...@@ -1091,20 +1091,20 @@ pub const Symbol = struct {
1091 &entry.virtual_address,1091 &entry.virtual_address,
1092 @intCast(coff.computeSymbolSectionOffset(sym) + reloc.offset),1092 @intCast(coff.computeSymbolSectionOffset(sym) + reloc.offset),
1093 );1093 );
1094 reloc.apply(coff);1094 try reloc.apply(coff);
1095 }1095 }
1096 },1096 },
1097 }1097 }
1098 }1098 }
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 {
1101 const sym = si.get(coff);1101 const sym = si.get(coff);
11021102
1103 var ri = sym.target_relocs;1103 var ri = sym.target_relocs;
1104 while (ri != end) {1104 while (ri != end) {
1105 const reloc = ri.get(coff);1105 const reloc = ri.get(coff);
1106 assert(reloc.target == si);1106 assert(reloc.target == si);
1107 reloc.apply(coff);1107 try reloc.apply(coff);
1108 ri = reloc.next;1108 ri = reloc.next;
1109 }1109 }
1110 }1110 }
...@@ -1166,7 +1166,7 @@ pub const Reloc = extern struct {...@@ -1166,7 +1166,7 @@ pub const Reloc = extern struct {
1166 }1166 }
1167 };1167 };
11681168
1169 pub fn apply(reloc: *Reloc, coff: *Coff) void {1169 pub fn apply(reloc: *Reloc, coff: *Coff) !void {
1170 const loc_sym = reloc.loc.get(coff);1170 const loc_sym = reloc.loc.get(coff);
1171 switch (loc_sym.ni) {1171 switch (loc_sym.ni) {
1172 .none => return,1172 .none => return,
...@@ -1300,118 +1300,163 @@ pub const Reloc = extern struct {...@@ -1300,118 +1300,163 @@ pub const Reloc = extern struct {
1300 }1300 }
13011301
1302 const target_sym = reloc.target.get(coff);1302 const target_sym = reloc.target.get(coff);
1303 switch (target_sym.ni) {1303 const is_abs = switch (target_sym.ni) {
1304 .none => return,1304 .none => if (target_sym.section_number == .ABSOLUTE) true else return,
1305 else => |ni| if (ni.hasMoved(&coff.mf)) return,1305 else => |ni| if (ni.hasMoved(&coff.mf)) return else false,
1306 }1306 };
13071307
1308 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));1308 const target_rva = target_sym.rva +% @as(u64, @bitCast(reloc.addend));
1309 switch (target_machine) {1309 if (is_abs) {
1310 else => |machine| @panic(@tagName(machine)),1310 switch (target_machine) {
1311 .AMD64 => switch (reloc.type.AMD64) {1311 else => |machine| @panic(@tagName(machine)),
1312 else => |kind| @panic(@tagName(kind)),1312 .AMD64 => switch (reloc.type.AMD64) {
1313 .ABSOLUTE => {},1313 // TODO: Report these later, in reportUndefs -> reportRelocErrs ?
1314 .ADDR64 => std.mem.writeInt(1314 else => |kind| return coff.base.comp.link_diags.fail(
1315 u64,1315 "absolute symbol '{s}' targeted by invalid relocation type: {t}",
1316 loc_slice[0..8],1316 .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind },
1317 coff.optionalHeaderField(.image_base) + target_rva,1317 ),
1318 target_endian,1318 .ABSOLUTE => {},
1319 ),1319 .ADDR64 => std.mem.writeInt(
1320 .ADDR32 => std.mem.writeInt(1320 u64,
1321 u32,1321 loc_slice[0..8],
1322 loc_slice[0..4],1322 target_rva,
1323 @intCast(coff.optionalHeaderField(.image_base) + target_rva),1323 target_endian,
1324 target_endian,1324 ),
1325 ),1325 .ADDR32 => std.mem.writeInt(
1326 .ADDR32NB => std.mem.writeInt(1326 u32,
1327 u32,1327 loc_slice[0..4],
1328 loc_slice[0..4],1328 @intCast(target_rva),
1329 @intCast(target_rva),1329 target_endian,
1330 target_endian,1330 ),
1331 ),1331 },
1332 .REL32 => std.mem.writeInt(1332 .I386 => switch (reloc.type.I386) {
1333 i32,1333 else => |kind| return coff.base.comp.link_diags.fail(
1334 loc_slice[0..4],1334 "absolute symbol '{s}' targeted by invalid relocation type: {t}",
1335 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),1335 .{ target_sym.gmi.globalName(coff).name.toSlice(coff), kind },
1336 target_endian,1336 ),
1337 ),1337 .ABSOLUTE => {},
1338 .REL32_1 => std.mem.writeInt(1338 .DIR16 => std.mem.writeInt(
1339 i32,1339 u16,
1340 loc_slice[0..4],1340 loc_slice[0..2],
1341 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))),1341 @intCast(target_rva),
1342 target_endian,1342 target_endian,
1343 ),1343 ),
1344 .REL32_2 => std.mem.writeInt(1344 .DIR32 => std.mem.writeInt(
1345 i32,1345 u32,
1346 loc_slice[0..4],1346 loc_slice[0..4],
1347 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))),1347 @intCast(target_rva),
1348 target_endian,1348 target_endian,
1349 ),1349 ),
1350 .REL32_3 => std.mem.writeInt(1350 },
1351 i32,1351 }
1352 loc_slice[0..4],1352 } else {
1353 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))),1353 switch (target_machine) {
1354 target_endian,1354 else => |machine| @panic(@tagName(machine)),
1355 ),1355 .AMD64 => switch (reloc.type.AMD64) {
1356 .REL32_4 => std.mem.writeInt(1356 else => |kind| @panic(@tagName(kind)),
1357 i32,1357 .ABSOLUTE => {},
1358 loc_slice[0..4],1358 .ADDR64 => std.mem.writeInt(
1359 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))),1359 u64,
1360 target_endian,1360 loc_slice[0..8],
1361 ),1361 coff.optionalHeaderField(.image_base) + target_rva,
1362 .REL32_5 => std.mem.writeInt(1362 target_endian,
1363 i32,1363 ),
1364 loc_slice[0..4],1364 .ADDR32 => std.mem.writeInt(
1365 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),1365 u32,
1366 target_endian,1366 loc_slice[0..4],
1367 ),1367 @intCast(coff.optionalHeaderField(.image_base) + target_rva),
1368 .SECREL => std.mem.writeInt(1368 target_endian,
1369 u32,1369 ),
1370 loc_slice[0..4],1370 .ADDR32NB => std.mem.writeInt(
1371 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),1371 u32,
1372 target_endian,1372 loc_slice[0..4],
1373 ),1373 @intCast(target_rva),
1374 },1374 target_endian,
1375 .I386 => switch (reloc.type.I386) {1375 ),
1376 else => |kind| @panic(@tagName(kind)),1376 .REL32 => std.mem.writeInt(
1377 .ABSOLUTE => {},1377 i32,
1378 .DIR16 => std.mem.writeInt(1378 loc_slice[0..4],
1379 u16,1379 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),
1380 loc_slice[0..2],1380 target_endian,
1381 @intCast(coff.optionalHeaderField(.image_base) + target_rva),1381 ),
1382 target_endian,1382 .REL32_1 => std.mem.writeInt(
1383 ),1383 i32,
1384 .REL16 => std.mem.writeInt(1384 loc_slice[0..4],
1385 i16,1385 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 5)))),
1386 loc_slice[0..2],1386 target_endian,
1387 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 2)))),1387 ),
1388 target_endian,1388 .REL32_2 => std.mem.writeInt(
1389 ),1389 i32,
1390 .DIR32 => std.mem.writeInt(1390 loc_slice[0..4],
1391 u32,1391 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 6)))),
1392 loc_slice[0..4],1392 target_endian,
1393 @intCast(coff.optionalHeaderField(.image_base) + target_rva),1393 ),
1394 target_endian,1394 .REL32_3 => std.mem.writeInt(
1395 ),1395 i32,
1396 .DIR32NB => std.mem.writeInt(1396 loc_slice[0..4],
1397 u32,1397 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 7)))),
1398 loc_slice[0..4],1398 target_endian,
1399 @intCast(target_rva),1399 ),
1400 target_endian,1400 .REL32_4 => std.mem.writeInt(
1401 ),1401 i32,
1402 .REL32 => std.mem.writeInt(1402 loc_slice[0..4],
1403 i32,1403 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 8)))),
1404 loc_slice[0..4],1404 target_endian,
1405 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 4)))),1405 ),
1406 target_endian,1406 .REL32_5 => std.mem.writeInt(
1407 ),1407 i32,
1408 .SECREL => std.mem.writeInt(1408 loc_slice[0..4],
1409 u32,1409 @intCast(@as(i64, @bitCast(target_rva -% (loc_sym.rva + reloc.offset + 9)))),
1410 loc_slice[0..4],1410 target_endian,
1411 @intCast(coff.computeSymbolSectionOffset(target_sym) + reloc.addend),1411 ),
1412 target_endian,1412 .SECREL => std.mem.writeInt(
1413 ),1413 u32,
1414 },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 }
1415 }1460 }
1416 }1461 }
14171462
...@@ -3170,7 +3215,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {...@@ -3170,7 +3215,7 @@ fn flushInputSection(coff: *Coff, isi: Node.InputSection.Index) !void {
3170 });3215 });
3171 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)3216 if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size)
3172 return error.EndOfStream;3217 return error.EndOfStream;
3173 si.applyLocationRelocs(coff);3218 try si.applyLocationRelocs(coff);
3174}3219}
31753220
3176fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index {3221fn addSection(coff: *Coff, name: String, flags: std.coff.SectionHeader.Flags) !Symbol.Index {
...@@ -3874,9 +3919,12 @@ fn loadObject(...@@ -3874,9 +3919,12 @@ fn loadObject(
3874 value: union(enum) {3919 value: union(enum) {
3875 // Size of the section3920 // Size of the section
3876 section: u32,3921 section: u32,
3877 // Offset within the section3922 // If section is absolute, the symbol value.
3923 // Otherwise, offset within the section.
3878 static: u32,3924 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.
3880 external: u32,3928 external: u32,
3881 // The index of the target symbol of this weak external3929 // The index of the target symbol of this weak external
3882 weak_external: u32,3930 weak_external: u32,
...@@ -3945,7 +3993,10 @@ fn loadObject(...@@ -3945,7 +3993,10 @@ fn loadObject(
3945 .STATIC, .LABEL => |storage_class| switch (section_number) {3993 .STATIC, .LABEL => |storage_class| switch (section_number) {
3946 // TODO: Do we need to do anything with @feat.00?3994 // TODO: Do we need to do anything with @feat.00?
3947 // https://llvm.org/doxygen/namespacellvm_1_1COFF.html#aeffa16735e18df727a173beaf748c3923995 // https://llvm.org/doxygen/namespacellvm_1_1COFF.html#aeffa16735e18df727a173beaf748c392
3948 .UNDEFINED, .DEBUG, .ABSOLUTE => &.{},3996 .UNDEFINED,
3997 .DEBUG,
3998 => &.{},
3999 .ABSOLUTE => &.{.{ .static = symbol.value }},
3949 else => |sn| {4000 else => |sn| {
3950 const section = &sections[sn.toIndex()];4001 const section = &sections[sn.toIndex()];
39514002
...@@ -4049,12 +4100,9 @@ fn loadObject(...@@ -4049,12 +4100,9 @@ fn loadObject(
4049 ),4100 ),
4050 },4101 },
4051 .EXTERNAL => switch (section_number) {4102 .EXTERNAL => switch (section_number) {
4052 .UNDEFINED => &.{.{ .external = symbol.value }},4103 .UNDEFINED,
4053 .ABSOLUTE => return diags.failParse(4104 .ABSOLUTE,
4054 path,4105 => &.{.{ .external = symbol.value }},
4055 "TODO unhandled external absolute symbol 0x{x}: '{s}'",
4056 .{ symbol_i, name },
4057 ),
4058 .DEBUG => return diags.failParse(4106 .DEBUG => return diags.failParse(
4059 path,4107 path,
4060 "unexpected external symbol 0x{x} in DEBUG section: '{s}'",4108 "unexpected external symbol 0x{x} in DEBUG section: '{s}'",
...@@ -4517,7 +4565,28 @@ fn loadObject(...@@ -4517,7 +4565,28 @@ fn loadObject(
4517 continue;4565 continue;
4518 },4566 },
4519 },4567 },
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,
4521 else => |sn| &sections[sn.toIndex()],4590 else => |sn| &sections[sn.toIndex()],
4522 };4591 };
45234592
...@@ -5198,7 +5267,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde...@@ -5198,7 +5267,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
5198 else => |e| return e,5267 else => |e| return e,
5199 };5268 };
5200 si.get(coff).extra.size = @intCast(nw.interface.end);5269 si.get(coff).extra.size = @intCast(nw.interface.end);
5201 si.applyLocationRelocs(coff);5270 try si.applyLocationRelocs(coff);
5202 }5271 }
52035272
5204 if (nav.resolved.?.@"linksection".unwrap()) |_| {5273 if (nav.resolved.?.@"linksection".unwrap()) |_| {
...@@ -5331,7 +5400,7 @@ fn updateFuncInner(...@@ -5331,7 +5400,7 @@ fn updateFuncInner(
5331 else => |e| return e,5400 else => |e| return e,
5332 };5401 };
5333 si.get(coff).extra.size = @intCast(nw.interface.end);5402 si.get(coff).extra.size = @intCast(nw.interface.end);
5334 si.applyLocationRelocs(coff);5403 try si.applyLocationRelocs(coff);
5335}5404}
53365405
5337pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {5406pub fn updateErrorData(coff: *Coff, pt: Zcu.PerThread) !void {
...@@ -5433,6 +5502,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {...@@ -5433,6 +5502,7 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
5433 switch (target_sym.ni) {5502 switch (target_sym.ni) {
5434 .none => {5503 .none => {
5435 assert(target_sym.gmi != .none);5504 assert(target_sym.gmi != .none);
5505 if (target_sym.section_number == .ABSOLUTE) continue;
5436 (try undef_indices.addOne(gpa)).* = @intCast(reloc_i);5506 (try undef_indices.addOne(gpa)).* = @intCast(reloc_i);
5437 },5507 },
5438 else => continue,5508 else => continue,
...@@ -5481,6 +5551,8 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {...@@ -5481,6 +5551,8 @@ fn reportUndefs(coff: *Coff, tid: Zcu.PerThread.Id) !void {
5481 defer prev_loc_si = loc_si;5551 defer prev_loc_si = loc_si;
54825552
5483 const loc_sym = loc_si.get(coff);5553 const loc_sym = loc_si.get(coff);
5554
5555 // TODO: Make this a helper for anything that needs to report "referenced by" notes
5484 switch (coff.getNode(loc_sym.ni)) {5556 switch (coff.getNode(loc_sym.ni)) {
5485 .data_directories => {5557 .data_directories => {
5486 const dir_align = std.mem.Alignment.of(std.coff.ImageDataDirectory);5558 const dir_align = std.mem.Alignment.of(std.coff.ImageDataDirectory);
...@@ -5958,7 +6030,7 @@ fn flushUav(...@@ -5958,7 +6030,7 @@ fn flushUav(
5958 else => |e| return e,6030 else => |e| return e,
5959 };6031 };
5960 si.get(coff).extra.size = @intCast(nw.interface.end);6032 si.get(coff).extra.size = @intCast(nw.interface.end);
5961 si.applyLocationRelocs(coff);6033 try si.applyLocationRelocs(coff);
5962}6034}
59636035
5964fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !void {6036fn 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...@@ -5998,7 +6070,7 @@ fn aliasGlobal(coff: *Coff, gmi: Node.GlobalMapIndex, alias_si: Symbol.Index) !v
5998 sym.gmi = alias_sym.gmi;6070 sym.gmi = alias_sym.gmi;
5999 coff.globals.values()[gmi.unwrap().?] = alias_si;6071 coff.globals.values()[gmi.unwrap().?] = alias_si;
6000 // Only apply the new relocs6072 // Only apply the new relocs
6001 alias_si.applyTargetRelocs(coff, prev_target_relocs);6073 try alias_si.applyTargetRelocs(coff, prev_target_relocs);
6002}6074}
60036075
6004fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {6076fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
...@@ -6407,7 +6479,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {...@@ -6407,7 +6479,7 @@ fn flushGlobal(coff: *Coff, gmi: Node.GlobalMapIndex) !bool {
6407 },6479 },
6408 }6480 }
64096481
6410 si.flushMoved(coff);6482 try si.flushMoved(coff);
6411 return true;6483 return true;
6412}6484}
64136485
...@@ -6575,7 +6647,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {...@@ -6575,7 +6647,7 @@ fn flushLazy(coff: *Coff, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void {
6575 else => |e| return e,6647 else => |e| return e,
6576 };6648 };
6577 si.get(coff).extra.size = @intCast(nw.interface.end);6649 si.get(coff).extra.size = @intCast(nw.interface.end);
6578 si.applyLocationRelocs(coff);6650 try si.applyLocationRelocs(coff);
6579}6651}
65806652
6581fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {6653fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
...@@ -6644,10 +6716,10 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6644,10 +6716,10 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6644 }6716 }
6645 },6717 },
6646 .input_section => |isi| {6718 .input_section => |isi| {
6647 isi.symbol(coff).flushMoved(coff);6719 try isi.symbol(coff).flushMoved(coff);
6648 for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |input_symbol| {6720 for (coff.input_symbols.items[@intFromEnum(isi.firstSymbol(coff))..]) |input_symbol| {
6649 if (input_symbol.si.get(coff).ni != ni) break;6721 if (input_symbol.si.get(coff).ni != ni) break;
6650 input_symbol.si.flushMoved(coff);6722 try input_symbol.si.flushMoved(coff);
6651 }6723 }
6652 },6724 },
6653 .import_directory_table => coff.targetStore(6725 .import_directory_table => coff.targetStore(
...@@ -6661,14 +6733,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6661,14 +6733,14 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6661 .import_address_table => |import_index| {6733 .import_address_table => |import_index| {
6662 const entry = import_index.get(coff);6734 const entry = import_index.get(coff);
6663 const import_address_table_si = entry.import_address_table_si;6735 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);
6665 coff.targetStore(6737 coff.targetStore(
6666 &coff.importDirectoryEntryPtr(import_index).import_address_table_rva,6738 &coff.importDirectoryEntryPtr(import_index).import_address_table_rva,
6667 import_address_table_si.get(coff).rva,6739 import_address_table_si.get(coff).rva,
6668 );6740 );
66696741
6670 for (entry.import_address_table_symbols.items) |iat_ptr_si|6742 for (entry.import_address_table_symbols.items) |iat_ptr_si|
6671 iat_ptr_si.flushMoved(coff);6743 try iat_ptr_si.flushMoved(coff);
6672 },6744 },
6673 .import_hint_name_table => |import_index| {6745 .import_hint_name_table => |import_index| {
6674 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);6746 const magic = coff.targetLoad(&coff.optionalHeaderStandardPtr().magic);
...@@ -6721,12 +6793,12 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6721,12 +6793,12 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6721 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));6793 coff.targetStore(&coff.exportDirectoryTable().name_rva, rva + @sizeOf(std.coff.ExportDirectoryTable));
6722 },6794 },
6723 .export_address_table => {6795 .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
6726 // These relocs are applied directly here instead of via the above flushMoved call as6798 // These relocs are applied directly here instead of via the above flushMoved call as
6727 // they are non-contiguous, and not tracked under export_address_table_si.6799 // they are non-contiguous, and not tracked under export_address_table_si.
6728 for (coff.export_table.entries.values()) |entry|6800 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
6731 coff.targetStore(6803 coff.targetStore(
6732 &coff.exportDirectoryTable().export_address_table_rva,6804 &coff.exportDirectoryTable().export_address_table_rva,
...@@ -6762,7 +6834,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {...@@ -6762,7 +6834,7 @@ fn flushMoved(coff: *Coff, ni: MappedFile.Node.Index) !void {
6762 .uav,6834 .uav,
6763 .lazy_code,6835 .lazy_code,
6764 .lazy_const_data,6836 .lazy_const_data,
6765 => |mi| mi.symbol(coff).flushMoved(coff),6837 => |mi| try mi.symbol(coff).flushMoved(coff),
6766 }6838 }
6767 try ni.childrenMoved(coff.base.comp.gpa, &coff.mf);6839 try ni.childrenMoved(coff.base.comp.gpa, &coff.mf);
6768}6840}
...@@ -7131,7 +7203,7 @@ fn updateExportsInner(...@@ -7131,7 +7203,7 @@ fn updateExportsInner(
7131 export_sym.ni = exported_ni;7203 export_sym.ni = exported_ni;
7132 export_sym.rva = exported_sym.rva;7204 export_sym.rva = exported_sym.rva;
7133 export_sym.section_number = exported_sym.section_number;7205 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
7136 const prev_alias_sym = prev_alias_si.get(coff);7208 const prev_alias_sym = prev_alias_si.get(coff);
7137 switch (prev_alias_sym.flags.extra_tag) {7209 switch (prev_alias_sym.flags.extra_tag) {
test/link.zig+59
...@@ -93,6 +93,65 @@ pub fn addCases(ctx: *LinkContext) void {...@@ -93,6 +93,65 @@ pub fn addCases(ctx: *LinkContext) void {
93 const run = case.addRunArtifact(exe);93 const run = case.addRunArtifact(exe);
94 run.addCheck(.{ .expect_term = .{ .exited = 0 } });94 run.addCheck(.{ .expect_term = .{ .exited = 0 } });
95 }95 }
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 }
96}155}
97156
98const LinkContext = @import("tests.zig").LinkContext;157const 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 {...@@ -90,6 +90,16 @@ pub const Case = struct {
90 });90 });
91 }91 }
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
93 const SnapshotScope = struct {103 const SnapshotScope = struct {
94 /// If a test case has multiple verifyObjdump calls, `opt_sub_name` can104 /// If a test case has multiple verifyObjdump calls, `opt_sub_name` can
95 /// be used to differentiate them.105 /// be used to differentiate them.