authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-21 13:07:43+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-25 00:21:55+01:00
logd74e9a786f96af052065c0d3a6c22ab38e9b697f
treef6e34da8396ea5e301dea73c69e219728b6a3ecb
parent7cc50a4fb3f8184742abe7a6939ae920c648ebab
signature Commit is signed but in an unrecognized format.

Elf2: prepare to support simple relaxations


1 files changed, 45 insertions(+), 7 deletions(-)

src/link/Elf2.zig+45-7
...@@ -1387,10 +1387,9 @@ const SymbolReloc = struct {...@@ -1387,10 +1387,9 @@ const SymbolReloc = struct {
1387 illegal_dynamic_section,1387 illegal_dynamic_section,
1388 },1388 },
13891389
1390 /// ~~mystery bits~~1390 relaxation: Relaxation,
1391 /// what will MLUGG use them for?1391
1392 /// nobody knows1392 _: u10 = 0,
1393 _: u11 = 0,
1394 },1393 },
1395 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so1394 /// Forms a linked list of all symbol relocations with the same `target`. This list exists so
1396 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.1395 /// that all relocations targeting a particular symbol can be re-applied if that symbol moves.
...@@ -1439,6 +1438,19 @@ const SymbolReloc = struct {...@@ -1439,6 +1438,19 @@ const SymbolReloc = struct {
1439 },1438 },
1440 };1439 };
14411440
1441 const Relaxation = enum(u1) {
1442 none,
1443 };
1444 /// Updates `reloc.type` and `reloc.offset` as needed based on `reloc.bits.relaxation`. It is
1445 /// possible that `reloc` is already relaxed, and may need to be un-relaxed due to a change in
1446 /// the symbol definition.
1447 fn processRelaxation(reloc: *SymbolReloc, elf: *Elf) void {
1448 _ = elf;
1449 switch (reloc.bits.relaxation) {
1450 .none => return,
1451 }
1452 }
1453
1442 /// Instead of using the ELF relocation enums, we have our own internal representation for1454 /// Instead of using the ELF relocation enums, we have our own internal representation for
1443 /// relocation types. This representation is more compact (requiring only 16 bits), and allows1455 /// relocation types. This representation is more compact (requiring only 16 bits), and allows
1444 /// sharing a lot of relocation handling between multiple relocs and target architectures.1456 /// sharing a lot of relocation handling between multiple relocs and target architectures.
...@@ -2332,7 +2344,8 @@ const SymbolReloc = struct {...@@ -2332,7 +2344,8 @@ const SymbolReloc = struct {
2332 reloc.rela_index = .none;2344 reloc.rela_index = .none;
2333 }2345 }
23342346
2335 fn updateDynamicReloc(reloc: *SymbolReloc, elf: *Elf) Error!void {2347 /// Called when the classification of the target symbol changes.
2348 fn updateDynamicReloc(reloc: *SymbolReloc, elf: *Elf, ri: SymbolReloc.Index) Error!void {
2336 assert(elf.ehdrType() != .REL);2349 assert(elf.ehdrType() != .REL);
2337 const reloc_node = reloc.node.unwrap().?; // deleted2350 const reloc_node = reloc.node.unwrap().?; // deleted
23382351
...@@ -2351,6 +2364,30 @@ const SymbolReloc = struct {...@@ -2351,6 +2364,30 @@ const SymbolReloc = struct {
2351 },2364 },
2352 }2365 }
23532366
2367 {
2368 const gpa = elf.base.comp.gpa;
2369
2370 const old_depends_on_got_address = reloc.bits.type.dependsOnGotAddress();
2371 const old_depends_on_tls_size = reloc.bits.type.dependsOnTlsSize(elf);
2372
2373 reloc.processRelaxation(elf);
2374
2375 const new_depends_on_got_address = reloc.bits.type.dependsOnGotAddress();
2376 const new_depends_on_tls_size = reloc.bits.type.dependsOnTlsSize(elf);
2377
2378 if (old_depends_on_got_address and !new_depends_on_got_address) {
2379 assert(elf.got_relocs.swapRemove(ri));
2380 } else if (!old_depends_on_got_address and new_depends_on_got_address) {
2381 try elf.got_relocs.putNoClobber(gpa, ri, {});
2382 }
2383
2384 if (old_depends_on_tls_size and !new_depends_on_tls_size) {
2385 assert(elf.tls_size_symbol_relocs.swapRemove(ri));
2386 } else if (!old_depends_on_tls_size and new_depends_on_tls_size) {
2387 try elf.tls_size_symbol_relocs.putNoClobber(gpa, ri, {});
2388 }
2389 }
2390
2354 assert(reloc.rela_index == .none);2391 assert(reloc.rela_index == .none);
23552392
2356 const symbol_class = elf.classifySymbolValue(reloc.target_symbol);2393 const symbol_class = elf.classifySymbolValue(reloc.target_symbol);
...@@ -4345,7 +4382,7 @@ const Symbol = struct {...@@ -4345,7 +4382,7 @@ const Symbol = struct {
4345 while (ri != .none) {4382 while (ri != .none) {
4346 const reloc = ri.get(elf);4383 const reloc = ri.get(elf);
4347 assert(reloc.target_symbol == sym_id);4384 assert(reloc.target_symbol == sym_id);
4348 try reloc.updateDynamicReloc(elf);4385 try reloc.updateDynamicReloc(elf, ri);
4349 ri = reloc.next;4386 ri = reloc.next;
4350 }4387 }
43514388
...@@ -10000,6 +10037,7 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -10000,6 +10037,7 @@ fn addSymbolRelocAssumeCapacityInner(
10000 .bits = .{10037 .bits = .{
10001 .type = @"type",10038 .type = @"type",
10002 .result = .ok,10039 .result = .ok,
10040 .relaxation = .none,
10003 },10041 },
10004 .next = next,10042 .next = next,
10005 .prev = .none,10043 .prev = .none,
...@@ -10011,7 +10049,7 @@ fn addSymbolRelocAssumeCapacityInner(...@@ -10011,7 +10049,7 @@ fn addSymbolRelocAssumeCapacityInner(
10011 if (@"type".dependsOnGotAddress()) {10049 if (@"type".dependsOnGotAddress()) {
10012 try elf.got_relocs.put(gpa, ri, {});10050 try elf.got_relocs.put(gpa, ri, {});
10013 }10051 }
10014 try ri.get(elf).updateDynamicReloc(elf);10052 try ri.get(elf).updateDynamicReloc(elf, ri);
1001510053
10016 // Actually apply the new relocation!10054 // Actually apply the new relocation!
10017 ri.get(elf).apply(elf);10055 ri.get(elf).apply(elf);