| ... | @@ -164,7 +164,26 @@ pub const Node = union(enum) { | ... | @@ -164,7 +164,26 @@ pub const Node = union(enum) { |
| 164 | } | 164 | } |
| 165 | }; | 165 | }; |
| 166 | | 166 | |
| 167 | pub const Section = struct { si: Symbol.Index, rela_si: Symbol.Index }; | 167 | pub const Section = struct { |
| | 168 | si: Symbol.Index, |
| | 169 | rela_si: Symbol.Index, |
| | 170 | rela_free: RelIndex, |
| | 171 | |
| | 172 | pub const RelIndex = enum(u32) { |
| | 173 | none, |
| | 174 | _, |
| | 175 | |
| | 176 | pub fn wrap(i: ?u32) RelIndex { |
| | 177 | return @enumFromInt((i orelse return .none) + 1); |
| | 178 | } |
| | 179 | pub fn unwrap(ri: RelIndex) ?u32 { |
| | 180 | return switch (ri) { |
| | 181 | .none => null, |
| | 182 | else => @intFromEnum(ri) - 1, |
| | 183 | }; |
| | 184 | } |
| | 185 | }; |
| | 186 | }; |
| 168 | | 187 | |
| 169 | pub const StringTable = struct { | 188 | pub const StringTable = struct { |
| 170 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), | 189 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), |
| ... | @@ -462,7 +481,7 @@ pub const Reloc = extern struct { | ... | @@ -462,7 +481,7 @@ pub const Reloc = extern struct { |
| 462 | next: Reloc.Index, | 481 | next: Reloc.Index, |
| 463 | loc: Symbol.Index, | 482 | loc: Symbol.Index, |
| 464 | target: Symbol.Index, | 483 | target: Symbol.Index, |
| 465 | rel_index: u32, | 484 | index: Section.RelIndex, |
| 466 | offset: u64, | 485 | offset: u64, |
| 467 | addend: i64, | 486 | addend: i64, |
| 468 | | 487 | |
| ... | @@ -472,6 +491,16 @@ pub const Reloc = extern struct { | ... | @@ -472,6 +491,16 @@ pub const Reloc = extern struct { |
| 472 | RISCV: std.elf.R_RISCV, | 491 | RISCV: std.elf.R_RISCV, |
| 473 | PPC64: std.elf.R_PPC64, | 492 | PPC64: std.elf.R_PPC64, |
| 474 | | 493 | |
| | 494 | pub fn none(elf: *Elf) Reloc.Type { |
| | 495 | return switch (elf.ehdrField(.machine)) { |
| | 496 | else => unreachable, |
| | 497 | .AARCH64 => .{ .AARCH64 = .NONE }, |
| | 498 | .PPC64 => .{ .PPC64 = .NONE }, |
| | 499 | .RISCV => .{ .RISCV = .NONE }, |
| | 500 | .X86_64 => .{ .X86_64 = .NONE }, |
| | 501 | }; |
| | 502 | } |
| | 503 | |
| 475 | pub fn absAddr(elf: *Elf) Reloc.Type { | 504 | pub fn absAddr(elf: *Elf) Reloc.Type { |
| 476 | return switch (elf.ehdrField(.machine)) { | 505 | return switch (elf.ehdrField(.machine)) { |
| 477 | else => unreachable, | 506 | else => unreachable, |
| ... | @@ -481,12 +510,35 @@ pub const Reloc = extern struct { | ... | @@ -481,12 +510,35 @@ pub const Reloc = extern struct { |
| 481 | .X86_64 => .{ .X86_64 = .@"64" }, | 510 | .X86_64 => .{ .X86_64 = .@"64" }, |
| 482 | }; | 511 | }; |
| 483 | } | 512 | } |
| | 513 | |
| 484 | pub fn sizeAddr(elf: *Elf) Reloc.Type { | 514 | pub fn sizeAddr(elf: *Elf) Reloc.Type { |
| 485 | return switch (elf.ehdrField(.machine)) { | 515 | return switch (elf.ehdrField(.machine)) { |
| 486 | else => unreachable, | 516 | else => unreachable, |
| 487 | .X86_64 => .{ .X86_64 = .SIZE64 }, | 517 | .X86_64 => .{ .X86_64 = .SIZE64 }, |
| 488 | }; | 518 | }; |
| 489 | } | 519 | } |
| | 520 | |
| | 521 | pub fn wrap(int: u32, elf: *Elf) Reloc.Type { |
| | 522 | return switch (elf.ehdrField(.machine)) { |
| | 523 | else => unreachable, |
| | 524 | inline .AARCH64, |
| | 525 | .PPC64, |
| | 526 | .RISCV, |
| | 527 | .X86_64, |
| | 528 | => |machine| @unionInit(Reloc.Type, @tagName(machine), @enumFromInt(int)), |
| | 529 | }; |
| | 530 | } |
| | 531 | |
| | 532 | pub fn unwrap(rt: Reloc.Type, elf: *Elf) u32 { |
| | 533 | return switch (elf.ehdrField(.machine)) { |
| | 534 | else => unreachable, |
| | 535 | inline .AARCH64, |
| | 536 | .PPC64, |
| | 537 | .RISCV, |
| | 538 | .X86_64, |
| | 539 | => |machine| @intFromEnum(@field(rt, @tagName(machine))), |
| | 540 | }; |
| | 541 | } |
| 490 | }; | 542 | }; |
| 491 | | 543 | |
| 492 | pub const Index = enum(u32) { | 544 | pub const Index = enum(u32) { |
| ... | @@ -590,6 +642,33 @@ pub const Reloc = extern struct { | ... | @@ -590,6 +642,33 @@ pub const Reloc = extern struct { |
| 590 | .none => {}, | 642 | .none => {}, |
| 591 | else => |next| next.get(elf).prev = reloc.prev, | 643 | else => |next| next.get(elf).prev = reloc.prev, |
| 592 | } | 644 | } |
| | 645 | switch (elf.ehdrField(.type)) { |
| | 646 | .NONE, .CORE, _ => unreachable, |
| | 647 | .REL => { |
| | 648 | const sh = reloc.loc.shndx(elf).get(elf); |
| | 649 | switch (elf.shdrPtr(sh.rela_si.shndx(elf))) { |
| | 650 | inline else => |shdr, class| { |
| | 651 | const Rela = class.ElfN().Rela; |
| | 652 | const ent_size = elf.targetLoad(&shdr.entsize); |
| | 653 | const start = ent_size * reloc.index.unwrap().?; |
| | 654 | const rela_slice = sh.rela_si.node(elf).slice(&elf.mf); |
| | 655 | const rela: *Rela = @ptrCast(@alignCast( |
| | 656 | rela_slice[@intCast(start)..][0..@intCast(ent_size)], |
| | 657 | )); |
| | 658 | rela.* = .{ |
| | 659 | .offset = @intFromEnum(sh.rela_free), |
| | 660 | .info = .{ |
| | 661 | .type = @intCast(Reloc.Type.none(elf).unwrap(elf)), |
| | 662 | .sym = 0, |
| | 663 | }, |
| | 664 | .addend = 0, |
| | 665 | }; |
| | 666 | }, |
| | 667 | } |
| | 668 | sh.rela_free = reloc.index; |
| | 669 | }, |
| | 670 | .EXEC, .DYN => assert(reloc.index == .none), |
| | 671 | } |
| 593 | reloc.* = undefined; | 672 | reloc.* = undefined; |
| 594 | } | 673 | } |
| 595 | | 674 | |
| ... | @@ -1036,7 +1115,7 @@ fn initHeaders( | ... | @@ -1036,7 +1115,7 @@ fn initHeaders( |
| 1036 | .entsize = 0, | 1115 | .entsize = 0, |
| 1037 | }; | 1116 | }; |
| 1038 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); | 1117 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); |
| 1039 | elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null }); | 1118 | elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null, .rela_free = .none }); |
| 1040 | | 1119 | |
| 1041 | try elf.symtab.ensureTotalCapacity(gpa, 1); | 1120 | try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 1042 | elf.symtab.addOneAssumeCapacity().* = .{ | 1121 | elf.symtab.addOneAssumeCapacity().* = .{ |
| ... | @@ -1880,18 +1959,7 @@ fn loadObject( | ... | @@ -1880,18 +1959,7 @@ fn loadObject( |
| 1880 | rel.offset - loc_sec.shdr.addr, | 1959 | rel.offset - loc_sec.shdr.addr, |
| 1881 | target_si, | 1960 | target_si, |
| 1882 | rel.addend, | 1961 | rel.addend, |
| 1883 | switch (elf.ehdrField(.machine)) { | 1962 | .wrap(rel.info.type, elf), |
| 1884 | else => unreachable, | | |
| 1885 | inline .AARCH64, | | |
| 1886 | .PPC64, | | |
| 1887 | .RISCV, | | |
| 1888 | .X86_64, | | |
| 1889 | => |machine| @unionInit( | | |
| 1890 | Reloc.Type, | | |
| 1891 | @tagName(machine), | | |
| 1892 | @enumFromInt(rel.info.type), | | |
| 1893 | ), | | |
| 1894 | }, | | |
| 1895 | ); | 1963 | ); |
| 1896 | } | 1964 | } |
| 1897 | }, | 1965 | }, |
| ... | @@ -2156,7 +2224,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -2156,7 +2224,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 2156 | }); | 2224 | }); |
| 2157 | const si = elf.addSymbolAssumeCapacity(); | 2225 | const si = elf.addSymbolAssumeCapacity(); |
| 2158 | elf.nodes.appendAssumeCapacity(.{ .section = si }); | 2226 | elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 2159 | elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null }); | 2227 | elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null, .rela_free = .none }); |
| 2160 | si.get(elf).ni = ni; | 2228 | si.get(elf).ni = ni; |
| 2161 | const addr = elf.computeNodeVAddr(ni); | 2229 | const addr = elf.computeNodeVAddr(ni); |
| 2162 | const offset = ni.fileLocation(&elf.mf, false).offset; | 2230 | const offset = ni.fileLocation(&elf.mf, false).offset; |
| ... | @@ -2275,39 +2343,44 @@ pub fn addRelocAssumeCapacity( | ... | @@ -2275,39 +2343,44 @@ pub fn addRelocAssumeCapacity( |
| 2275 | .next = target.target_relocs, | 2343 | .next = target.target_relocs, |
| 2276 | .loc = loc_si, | 2344 | .loc = loc_si, |
| 2277 | .target = target_si, | 2345 | .target = target_si, |
| 2278 | .rel_index = switch (elf.ehdrField(.type)) { | 2346 | .index = index: switch (elf.ehdrField(.type)) { |
| 2279 | .NONE, .CORE, _ => unreachable, | 2347 | .NONE, .CORE, _ => unreachable, |
| 2280 | .REL => rel_index: { | 2348 | .REL => { |
| 2281 | const rela_si = loc_si.shndx(elf).get(elf).rela_si; | 2349 | const sh = loc_si.shndx(elf).get(elf); |
| 2282 | switch (elf.shdrPtr(rela_si.shndx(elf))) { | 2350 | switch (elf.shdrPtr(sh.rela_si.shndx(elf))) { |
| 2283 | inline else => |shdr, class| { | 2351 | inline else => |shdr, class| { |
| 2284 | const Rela = class.ElfN().Rela; | 2352 | const Rela = class.ElfN().Rela; |
| 2285 | const old_size = elf.targetLoad(&shdr.size); | | |
| 2286 | const ent_size = elf.targetLoad(&shdr.entsize); | 2353 | const ent_size = elf.targetLoad(&shdr.entsize); |
| 2287 | const new_size = old_size + ent_size; | 2354 | const rela_slice = sh.rela_si.node(elf).slice(&elf.mf); |
| 2288 | elf.targetStore(&shdr.size, @intCast(new_size)); | 2355 | const index: u32 = if (sh.rela_free.unwrap()) |index| alloc_index: { |
| | 2356 | const rela: *Rela = @ptrCast(@alignCast( |
| | 2357 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], |
| | 2358 | )); |
| | 2359 | sh.rela_free = @enumFromInt(rela.offset); |
| | 2360 | break :alloc_index index; |
| | 2361 | } else alloc_index: { |
| | 2362 | const old_size = elf.targetLoad(&shdr.size); |
| | 2363 | const new_size = old_size + ent_size; |
| | 2364 | elf.targetStore(&shdr.size, @intCast(new_size)); |
| | 2365 | break :alloc_index @intCast(@divExact(old_size, ent_size)); |
| | 2366 | }; |
| 2289 | const rela: *Rela = @ptrCast(@alignCast( | 2367 | const rela: *Rela = @ptrCast(@alignCast( |
| 2290 | rela_si.node(elf).slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)], | 2368 | rela_slice[@intCast(ent_size * index)..][0..@intCast(ent_size)], |
| 2291 | )); | 2369 | )); |
| 2292 | rela.* = .{ | 2370 | rela.* = .{ |
| 2293 | .offset = @intCast(offset), | 2371 | .offset = @intCast(offset), |
| 2294 | .info = .{ | 2372 | .info = .{ |
| 2295 | .type = switch (elf.ehdrField(.machine)) { | 2373 | .type = @intCast(@"type".unwrap(elf)), |
| 2296 | else => |machine| @panic(@tagName(machine)), | | |
| 2297 | inline .X86_64, .AARCH64, .RISCV, .PPC64 => |machine| @intCast( | | |
| 2298 | @intFromEnum(@field(@"type", @tagName(machine))), | | |
| 2299 | ), | | |
| 2300 | }, | | |
| 2301 | .sym = @intCast(@intFromEnum(target_si)), | 2374 | .sym = @intCast(@intFromEnum(target_si)), |
| 2302 | }, | 2375 | }, |
| 2303 | .addend = @intCast(addend), | 2376 | .addend = @intCast(addend), |
| 2304 | }; | 2377 | }; |
| 2305 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela); | 2378 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela); |
| 2306 | break :rel_index @intCast(@divExact(old_size, ent_size)); | 2379 | break :index .wrap(index); |
| 2307 | }, | 2380 | }, |
| 2308 | } | 2381 | } |
| 2309 | }, | 2382 | }, |
| 2310 | .EXEC, .DYN => 0, | 2383 | .EXEC, .DYN => .none, |
| 2311 | }, | 2384 | }, |
| 2312 | .offset = offset, | 2385 | .offset = offset, |
| 2313 | .addend = addend, | 2386 | .addend = addend, |