authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-08 01:06:00-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-11-09 03:31:26-05:00
logb1d46339b5aa647df2b61ca19694c613aef89c21
tree0bc4016042c89972837664646d2bbe87152468a3
parent80c961159b56c117281a87bfe7acf853182fb427

Elf2: implement object relocs


1 files changed, 403 insertions(+), 215 deletions(-)

src/link/Elf2.zig+403-215
...@@ -3,6 +3,7 @@ options: link.File.OpenOptions,...@@ -3,6 +3,7 @@ options: link.File.OpenOptions,
3mf: MappedFile,3mf: MappedFile,
4ni: Node.Known,4ni: Node.Known,
5nodes: std.MultiArrayList(Node),5nodes: std.MultiArrayList(Node),
6shdrs: std.ArrayList(Section),
6phdrs: std.ArrayList(MappedFile.Node.Index),7phdrs: std.ArrayList(MappedFile.Node.Index),
7si: Symbol.Known,8si: Symbol.Known,
8symtab: std.ArrayList(Symbol),9symtab: std.ArrayList(Symbol),
...@@ -163,9 +164,10 @@ pub const Node = union(enum) {...@@ -163,9 +164,10 @@ pub const Node = union(enum) {
163 }164 }
164};165};
165166
167pub const Section = struct { si: Symbol.Index, rela_si: Symbol.Index };
168
166pub const StringTable = struct {169pub const StringTable = struct {
167 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),170 map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage),
168 size: u32,
169171
170 const Context = struct {172 const Context = struct {
171 slice: []const u8,173 slice: []const u8,
...@@ -193,14 +195,10 @@ pub const StringTable = struct {...@@ -193,14 +195,10 @@ pub const StringTable = struct {
193 }195 }
194 };196 };
195197
196 pub fn get(198 pub fn get(st: *StringTable, elf: *Elf, si: Symbol.Index, key: []const u8) !u32 {
197 st: *StringTable,199 const gpa = elf.base.comp.gpa;
198 gpa: std.mem.Allocator,200 const ni = si.node(elf);
199 mf: *MappedFile,201 const slice_const = ni.sliceConst(&elf.mf);
200 ni: MappedFile.Node.Index,
201 key: []const u8,
202 ) !u32 {
203 const slice_const = ni.sliceConst(mf);
204 const gop = try st.map.getOrPutContextAdapted(202 const gop = try st.map.getOrPutContextAdapted(
205 gpa,203 gpa,
206 key,204 key,
...@@ -208,11 +206,18 @@ pub const StringTable = struct {...@@ -208,11 +206,18 @@ pub const StringTable = struct {
208 .{ .slice = slice_const },206 .{ .slice = slice_const },
209 );207 );
210 if (gop.found_existing) return gop.key_ptr.*;208 if (gop.found_existing) return gop.key_ptr.*;
211 const old_size = st.size;209 const old_size, const new_size = size: switch (elf.shdrPtr(si.shndx(elf))) {
212 const new_size: u32 = @intCast(old_size + key.len + 1);210 inline else => |shdr| {
213 st.size = new_size;211 const old_size: u32 = @intCast(elf.targetLoad(&shdr.size));
214 try ni.resize(mf, gpa, new_size);212 const new_size: u32 = @intCast(old_size + key.len + 1);
215 const slice = ni.slice(mf)[old_size..];213 elf.targetStore(&shdr.size, new_size);
214 break :size .{ old_size, new_size };
215 },
216 };
217 _, const node_size = ni.location(&elf.mf).resolve(&elf.mf);
218 if (new_size > node_size)
219 try ni.resize(&elf.mf, gpa, new_size +| new_size / MappedFile.growth_factor);
220 const slice = ni.slice(&elf.mf)[old_size..];
216 @memcpy(slice[0..key.len], key);221 @memcpy(slice[0..key.len], key);
217 slice[key.len] = 0;222 slice[key.len] = 0;
218 gop.key_ptr.* = old_size;223 gop.key_ptr.* = old_size;
...@@ -226,7 +231,7 @@ pub const Symbol = struct {...@@ -226,7 +231,7 @@ pub const Symbol = struct {
226 loc_relocs: Reloc.Index,231 loc_relocs: Reloc.Index,
227 /// Relocations targeting this symbol232 /// Relocations targeting this symbol
228 target_relocs: Reloc.Index,233 target_relocs: Reloc.Index,
229 unused: u32 = 0,234 unused: u32,
230235
231 pub const Index = enum(u32) {236 pub const Index = enum(u32) {
232 null,237 null,
...@@ -252,6 +257,52 @@ pub const Symbol = struct {...@@ -252,6 +257,52 @@ pub const Symbol = struct {
252 return @enumFromInt(@intFromEnum(si) + 1);257 return @enumFromInt(@intFromEnum(si) + 1);
253 }258 }
254259
260 pub const Shndx = enum(Tag) {
261 UNDEF = std.elf.SHN_UNDEF,
262 LIVEPATCH = reserve(std.elf.SHN_LIVEPATCH),
263 ABS = reserve(std.elf.SHN_ABS),
264 COMMON = reserve(std.elf.SHN_COMMON),
265 _,
266
267 pub const Tag = u32;
268
269 pub const LORESERVE: Shndx = .fromSection(std.elf.SHN_LORESERVE);
270 pub const HIRESERVE: Shndx = .fromSection(std.elf.SHN_HIRESERVE);
271 comptime {
272 assert(@intFromEnum(HIRESERVE) == std.math.maxInt(Tag));
273 }
274
275 fn reserve(sec: std.elf.Section) Tag {
276 assert(sec >= std.elf.SHN_LORESERVE and sec <= std.elf.SHN_HIRESERVE);
277 return @as(Tag, std.math.maxInt(Tag) - std.elf.SHN_HIRESERVE) + sec;
278 }
279
280 pub fn fromSection(sec: std.elf.Section) Shndx {
281 return switch (sec) {
282 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @enumFromInt(sec),
283 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @enumFromInt(reserve(sec)),
284 };
285 }
286 pub fn toSection(s: Shndx) ?std.elf.Section {
287 return switch (@intFromEnum(s)) {
288 std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => |sec| @intCast(sec),
289 std.elf.SHN_LORESERVE...reserve(std.elf.SHN_LORESERVE) - 1 => null,
290 reserve(std.elf.SHN_LORESERVE)...reserve(std.elf.SHN_HIRESERVE) => |sec| @intCast(
291 sec - reserve(std.elf.SHN_LORESERVE) + std.elf.SHN_LORESERVE,
292 ),
293 };
294 }
295
296 pub fn get(s: Shndx, elf: *Elf) *Section {
297 return &elf.shdrs.items[@intFromEnum(s)];
298 }
299 };
300 pub fn shndx(si: Symbol.Index, elf: *Elf) Shndx {
301 return .fromSection(switch (elf.symPtr(si)) {
302 inline else => |sym| elf.targetLoad(&sym.shndx),
303 });
304 }
305
255 pub const InitOptions = struct {306 pub const InitOptions = struct {
256 name: []const u8 = "",307 name: []const u8 = "",
257 lib_name: ?[]const u8 = null,308 lib_name: ?[]const u8 = null,
...@@ -260,48 +311,83 @@ pub const Symbol = struct {...@@ -260,48 +311,83 @@ pub const Symbol = struct {
260 type: std.elf.STT,311 type: std.elf.STT,
261 bind: std.elf.STB = .LOCAL,312 bind: std.elf.STB = .LOCAL,
262 visibility: std.elf.STV = .DEFAULT,313 visibility: std.elf.STV = .DEFAULT,
263 shndx: std.elf.Section = std.elf.SHN_UNDEF,314 shndx: Shndx = .UNDEF,
264 };315 };
265 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {316 pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void {
266 const gpa = elf.base.comp.gpa;317 const gpa = elf.base.comp.gpa;
267 const target_endian = elf.targetEndian();318 const target_endian = elf.targetEndian();
268 const sym_size: usize = switch (elf.identClass()) {
269 .NONE, _ => unreachable,
270 inline else => |class| @sizeOf(class.ElfN().Sym),
271 };
272 const name_strtab_entry = try elf.string(.strtab, opts.name);319 const name_strtab_entry = try elf.string(.strtab, opts.name);
273 try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len);320 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
321 inline else => |shdr| {
322 const old_size = elf.targetLoad(&shdr.size);
323 const ent_size = elf.targetLoad(&shdr.entsize);
324 const new_size = ent_size * elf.symtab.items.len;
325 if (new_size > old_size) {
326 elf.targetStore(&shdr.size, @intCast(new_size));
327 const symtab_ni = elf.si.symtab.node(elf);
328 _, const node_size = symtab_ni.location(&elf.mf).resolve(&elf.mf);
329 if (new_size > node_size) try symtab_ni.resize(
330 &elf.mf,
331 gpa,
332 new_size +| new_size / MappedFile.growth_factor,
333 );
334 }
335 },
336 }
274 switch (elf.symPtr(si)) {337 switch (elf.symPtr(si)) {
275 inline else => |sym, class| {338 inline else => |sym, class| {
339 const Sym = class.ElfN().Sym;
276 sym.* = .{340 sym.* = .{
277 .name = name_strtab_entry,341 .name = name_strtab_entry,
278 .value = @intCast(opts.value),342 .value = @intCast(opts.value),
279 .size = @intCast(opts.size),343 .size = @intCast(opts.size),
280 .info = .{ .type = opts.type, .bind = opts.bind },344 .info = .{ .type = opts.type, .bind = opts.bind },
281 .other = .{ .visibility = opts.visibility },345 .other = .{ .visibility = opts.visibility },
282 .shndx = opts.shndx,346 .shndx = opts.shndx.toSection().?,
283 };347 };
284 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym);348 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, sym);
285 },349 },
286 }350 }
351 switch (elf.shdrPtr(elf.si.symtab.shndx(elf))) {
352 inline else => |shdr| elf.targetStore(&shdr.info, @max(
353 elf.targetLoad(&shdr.info),
354 @intFromEnum(si) + 1,
355 )),
356 }
287 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;357 if (opts.bind == .LOCAL or elf.si.dynsym == .null) return;
288 const dsi = elf.dynsym.items.len;358 const dsi = elf.dynsym.items.len;
289 try elf.dynsym.append(gpa, si);359 try elf.dynsym.append(gpa, si);
290 const dynsym_ni = elf.si.dynsym.node(elf);
291 const name_dynstr_entry = try elf.string(.dynstr, opts.name);360 const name_dynstr_entry = try elf.string(.dynstr, opts.name);
292 try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len);361 switch (elf.shdrPtr(elf.si.dynsym.shndx(elf))) {
362 inline else => |shdr| {
363 const old_size = elf.targetLoad(&shdr.size);
364 const ent_size = elf.targetLoad(&shdr.entsize);
365 const new_size = ent_size * elf.dynsym.items.len;
366 if (new_size > old_size) {
367 elf.targetStore(&shdr.size, @intCast(new_size));
368 const dynsym_ni = elf.si.dynsym.node(elf);
369 _, const node_size = dynsym_ni.location(&elf.mf).resolve(&elf.mf);
370 if (new_size > node_size) try dynsym_ni.resize(
371 &elf.mf,
372 gpa,
373 new_size +| new_size / MappedFile.growth_factor,
374 );
375 }
376 },
377 }
293 switch (elf.dynsymSlice()) {378 switch (elf.dynsymSlice()) {
294 inline else => |dynsym, class| {379 inline else => |dynsyms, class| {
295 const dsym = &dynsym[dsi];380 const Sym = class.ElfN().Sym;
296 dsym.* = .{381 const dynsym = &dynsyms[dsi];
382 dynsym.* = .{
297 .name = name_dynstr_entry,383 .name = name_dynstr_entry,
298 .value = @intCast(opts.value),384 .value = @intCast(opts.value),
299 .size = @intCast(opts.size),385 .size = @intCast(opts.size),
300 .info = .{ .type = opts.type, .bind = opts.bind },386 .info = .{ .type = opts.type, .bind = opts.bind },
301 .other = .{ .visibility = opts.visibility },387 .other = .{ .visibility = opts.visibility },
302 .shndx = opts.shndx,388 .shndx = opts.shndx.toSection().?,
303 };389 };
304 if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym);390 if (target_endian != native_endian) std.mem.byteSwapAllFields(Sym, dynsym);
305 },391 },
306 }392 }
307 }393 }
...@@ -321,6 +407,7 @@ pub const Symbol = struct {...@@ -321,6 +407,7 @@ pub const Symbol = struct {
321 }407 }
322408
323 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {409 pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void {
410 if (elf.ehdrField(.type) == .REL) return;
324 switch (si.get(elf).loc_relocs) {411 switch (si.get(elf).loc_relocs) {
325 .none => {},412 .none => {},
326 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {413 else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| {
...@@ -331,6 +418,7 @@ pub const Symbol = struct {...@@ -331,6 +418,7 @@ pub const Symbol = struct {
331 }418 }
332419
333 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {420 pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void {
421 if (elf.ehdrField(.type) == .REL) return;
334 var ri = si.get(elf).target_relocs;422 var ri = si.get(elf).target_relocs;
335 while (ri != .none) {423 while (ri != .none) {
336 const reloc = ri.get(elf);424 const reloc = ri.get(elf);
...@@ -374,7 +462,7 @@ pub const Reloc = extern struct {...@@ -374,7 +462,7 @@ pub const Reloc = extern struct {
374 next: Reloc.Index,462 next: Reloc.Index,
375 loc: Symbol.Index,463 loc: Symbol.Index,
376 target: Symbol.Index,464 target: Symbol.Index,
377 unused: u32,465 rel_index: u32,
378 offset: u64,466 offset: u64,
379 addend: i64,467 addend: i64,
380468
...@@ -411,6 +499,7 @@ pub const Reloc = extern struct {...@@ -411,6 +499,7 @@ pub const Reloc = extern struct {
411 };499 };
412500
413 pub fn apply(reloc: *const Reloc, elf: *Elf) void {501 pub fn apply(reloc: *const Reloc, elf: *Elf) void {
502 assert(elf.ehdrField(.type) != .REL);
414 const loc_ni = reloc.loc.get(elf).ni;503 const loc_ni = reloc.loc.get(elf).ni;
415 switch (loc_ni) {504 switch (loc_ni) {
416 .none => return,505 .none => return,
...@@ -601,6 +690,7 @@ fn create(...@@ -601,6 +690,7 @@ fn create(
601 .tls = .none,690 .tls = .none,
602 },691 },
603 .nodes = .empty,692 .nodes = .empty,
693 .shdrs = .empty,
604 .phdrs = .empty,694 .phdrs = .empty,
605 .si = .{695 .si = .{
606 .dynsym = .null,696 .dynsym = .null,
...@@ -611,16 +701,13 @@ fn create(...@@ -611,16 +701,13 @@ fn create(
611 .symtab = .empty,701 .symtab = .empty,
612 .shstrtab = .{702 .shstrtab = .{
613 .map = .empty,703 .map = .empty,
614 .size = 1,
615 },704 },
616 .strtab = .{705 .strtab = .{
617 .map = .empty,706 .map = .empty,
618 .size = 1,
619 },707 },
620 .dynsym = .empty,708 .dynsym = .empty,
621 .dynstr = .{709 .dynstr = .{
622 .map = .empty,710 .map = .empty,
623 .size = 1,
624 },711 },
625 .needed = .empty,712 .needed = .empty,
626 .inputs = .empty,713 .inputs = .empty,
...@@ -650,6 +737,7 @@ pub fn deinit(elf: *Elf) void {...@@ -650,6 +737,7 @@ pub fn deinit(elf: *Elf) void {
650 const gpa = elf.base.comp.gpa;737 const gpa = elf.base.comp.gpa;
651 elf.mf.deinit(gpa);738 elf.mf.deinit(gpa);
652 elf.nodes.deinit(gpa);739 elf.nodes.deinit(gpa);
740 elf.shdrs.deinit(gpa);
653 elf.phdrs.deinit(gpa);741 elf.phdrs.deinit(gpa);
654 elf.symtab.deinit(gpa);742 elf.symtab.deinit(gpa);
655 elf.shstrtab.map.deinit(gpa);743 elf.shstrtab.map.deinit(gpa);
...@@ -681,11 +769,10 @@ fn initHeaders(...@@ -681,11 +769,10 @@ fn initHeaders(
681 const comp = elf.base.comp;769 const comp = elf.base.comp;
682 const gpa = comp.gpa;770 const gpa = comp.gpa;
683 const have_dynamic_section = switch (@"type") {771 const have_dynamic_section = switch (@"type") {
684 .NONE => unreachable,772 .NONE, .CORE, _ => unreachable,
685 .REL => false,773 .REL => false,
686 .EXEC => comp.config.link_mode == .dynamic,774 .EXEC => comp.config.link_mode == .dynamic,
687 .DYN => true,775 .DYN => true,
688 .CORE, _ => unreachable,
689 };776 };
690 const addr_align: std.mem.Alignment = switch (class) {777 const addr_align: std.mem.Alignment = switch (class) {
691 .NONE, _ => unreachable,778 .NONE, _ => unreachable,
...@@ -693,6 +780,7 @@ fn initHeaders(...@@ -693,6 +780,7 @@ fn initHeaders(
693 .@"64" => .@"8",780 .@"64" => .@"8",
694 };781 };
695782
783 const shnum: u32 = 1;
696 var phnum: u32 = 0;784 var phnum: u32 = 0;
697 const phdr_phndx = phnum;785 const phdr_phndx = phnum;
698 phnum += 1;786 phnum += 1;
...@@ -716,16 +804,16 @@ fn initHeaders(...@@ -716,16 +804,16 @@ fn initHeaders(
716 } else undefined;804 } else undefined;
717805
718 const expected_nodes_len = expected_nodes_len: switch (@"type") {806 const expected_nodes_len = expected_nodes_len: switch (@"type") {
719 .NONE => unreachable,807 .NONE, .CORE, _ => unreachable,
720 .REL => {808 .REL => {
721 defer phnum = 0;809 defer phnum = 0;
722 break :expected_nodes_len 5 + phnum;810 break :expected_nodes_len 5 + phnum;
723 },811 },
724 .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +812 .EXEC, .DYN => break :expected_nodes_len 5 + phnum * 2 +
725 @as(usize, 2) * @intFromBool(have_dynamic_section),813 @as(usize, 2) * @intFromBool(have_dynamic_section),
726 .CORE, _ => unreachable,
727 };814 };
728 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);815 try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len);
816 try elf.shdrs.ensureTotalCapacity(gpa, shnum);
729 try elf.phdrs.resize(gpa, phnum);817 try elf.phdrs.resize(gpa, phnum);
730 elf.nodes.appendAssumeCapacity(.file);818 elf.nodes.appendAssumeCapacity(.file);
731819
...@@ -760,7 +848,7 @@ fn initHeaders(...@@ -760,7 +848,7 @@ fn initHeaders(
760 ehdr.phentsize = @sizeOf(ElfN.Phdr);848 ehdr.phentsize = @sizeOf(ElfN.Phdr);
761 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);849 ehdr.phnum = @min(phnum, std.elf.PN_XNUM);
762 ehdr.shentsize = @sizeOf(ElfN.Shdr);850 ehdr.shentsize = @sizeOf(ElfN.Shdr);
763 ehdr.shnum = 1;851 ehdr.shnum = if (shnum < std.elf.SHN_LORESERVE) shnum else 0;
764 ehdr.shstrndx = std.elf.SHN_UNDEF;852 ehdr.shstrndx = std.elf.SHN_UNDEF;
765 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);853 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr);
766 },854 },
...@@ -768,7 +856,7 @@ fn initHeaders(...@@ -768,7 +856,7 @@ fn initHeaders(
768856
769 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{857 assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{
770 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),858 .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum),
771 .alignment = addr_align,859 .alignment = elf.mf.flags.block_size,
772 .moved = true,860 .moved = true,
773 .resized = true,861 .resized = true,
774 }));862 }));
...@@ -810,7 +898,8 @@ fn initHeaders(...@@ -810,7 +898,8 @@ fn initHeaders(
810 elf.phdrs.items[data_phndx] = elf.ni.data;898 elf.phdrs.items[data_phndx] = elf.ni.data;
811899
812 break :ph_vaddr switch (elf.ehdrField(.type)) {900 break :ph_vaddr switch (elf.ehdrField(.type)) {
813 else => 0,901 .NONE, .CORE, _ => unreachable,
902 .REL, .DYN => 0,
814 .EXEC => switch (elf.ehdrField(.machine)) {903 .EXEC => switch (elf.ehdrField(.machine)) {
815 .@"386" => 0x400000,904 .@"386" => 0x400000,
816 .AARCH64, .X86_64 => 0x200000,905 .AARCH64, .X86_64 => 0x200000,
...@@ -933,20 +1022,21 @@ fn initHeaders(...@@ -933,20 +1022,21 @@ fn initHeaders(
933 }1022 }
934 }1023 }
9351024
936 const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));1025 const sh_undef: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf)));
937 sh_null.* = .{1026 sh_undef.* = .{
938 .name = try elf.string(.shstrtab, ""),1027 .name = try elf.string(.shstrtab, ""),
939 .type = .NULL,1028 .type = .NULL,
940 .flags = .{ .shf = .{} },1029 .flags = .{ .shf = .{} },
941 .addr = 0,1030 .addr = 0,
942 .offset = 0,1031 .offset = 0,
943 .size = 0,1032 .size = if (shnum < std.elf.SHN_LORESERVE) 0 else shnum,
944 .link = 0,1033 .link = 0,
945 .info = if (phnum >= std.elf.PN_XNUM) phnum else 0,1034 .info = if (phnum < std.elf.PN_XNUM) 0 else phnum,
946 .addralign = 0,1035 .addralign = 0,
947 .entsize = 0,1036 .entsize = 0,
948 };1037 };
949 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null);1038 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef);
1039 elf.shdrs.appendAssumeCapacity(.{ .si = .null, .rela_si = .null });
9501040
951 try elf.symtab.ensureTotalCapacity(gpa, 1);1041 try elf.symtab.ensureTotalCapacity(gpa, 1);
952 elf.symtab.addOneAssumeCapacity().* = .{1042 elf.symtab.addOneAssumeCapacity().* = .{
...@@ -960,6 +1050,7 @@ fn initHeaders(...@@ -960,6 +1050,7 @@ fn initHeaders(
960 .size = @sizeOf(ElfN.Sym) * 1,1050 .size = @sizeOf(ElfN.Sym) * 1,
961 .addralign = addr_align,1051 .addralign = addr_align,
962 .entsize = @sizeOf(ElfN.Sym),1052 .entsize = @sizeOf(ElfN.Sym),
1053 .node_align = elf.mf.flags.block_size,
963 }));1054 }));
964 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));1055 const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class));
965 symtab_null.* = .{1056 symtab_null.* = .{
...@@ -973,13 +1064,14 @@ fn initHeaders(...@@ -973,13 +1064,14 @@ fn initHeaders(
973 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);1064 if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null);
9741065
975 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));1066 const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class));
976 ehdr.shstrndx = ehdr.shnum;1067 elf.targetStore(&ehdr.shstrndx, ehdr.shnum);
977 },1068 },
978 }1069 }
979 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{1070 assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{
980 .type = .STRTAB,1071 .type = .STRTAB,
981 .addralign = elf.mf.flags.block_size,1072 .size = 1,
982 .entsize = 1,1073 .entsize = 1,
1074 .node_align = elf.mf.flags.block_size,
983 }));1075 }));
984 try elf.renameSection(.symtab, ".symtab");1076 try elf.renameSection(.symtab, ".symtab");
985 try elf.renameSection(.shstrtab, ".shstrtab");1077 try elf.renameSection(.shstrtab, ".shstrtab");
...@@ -989,96 +1081,100 @@ fn initHeaders(...@@ -989,96 +1081,100 @@ fn initHeaders(
989 .name = ".strtab",1081 .name = ".strtab",
990 .type = .STRTAB,1082 .type = .STRTAB,
991 .size = 1,1083 .size = 1,
992 .addralign = elf.mf.flags.block_size,
993 .entsize = 1,1084 .entsize = 1,
1085 .node_align = elf.mf.flags.block_size,
994 }));1086 }));
995 try elf.linkSections(.symtab, .strtab);1087 try elf.linkSections(.symtab, .strtab);
996 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;1088 elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0;
9971089
998 assert(elf.si.rodata == try elf.addSection(if (@"type" != .REL) elf.ni.rodata else elf.ni.file, .{1090 assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{
999 .name = ".rodata",1091 .name = ".rodata",
1000 .flags = .{ .ALLOC = true },1092 .flags = .{ .ALLOC = true },
1001 .addralign = elf.mf.flags.block_size,1093 .addralign = elf.mf.flags.block_size,
1002 }));1094 }));
1003 assert(elf.si.text == try elf.addSection(if (@"type" != .REL) elf.ni.text else elf.ni.file, .{1095 assert(elf.si.text == try elf.addSection(elf.ni.text, .{
1004 .name = ".text",1096 .name = ".text",
1005 .flags = .{ .ALLOC = true, .EXECINSTR = true },1097 .flags = .{ .ALLOC = true, .EXECINSTR = true },
1006 .addralign = elf.mf.flags.block_size,1098 .addralign = elf.mf.flags.block_size,
1007 }));1099 }));
1008 assert(elf.si.data == try elf.addSection(if (@"type" != .REL) elf.ni.data else elf.ni.file, .{1100 assert(elf.si.data == try elf.addSection(elf.ni.data, .{
1009 .name = ".data",1101 .name = ".data",
1010 .flags = .{ .WRITE = true, .ALLOC = true },1102 .flags = .{ .WRITE = true, .ALLOC = true },
1011 .addralign = elf.mf.flags.block_size,1103 .addralign = elf.mf.flags.block_size,
1012 }));1104 }));
1013 if (maybe_interp) |interp| {1105 if (@"type" != .REL) {
1014 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{1106 if (maybe_interp) |interp| {
1015 .size = interp.len + 1,1107 const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1016 .moved = true,1108 .size = interp.len + 1,
1017 .resized = true,1109 .moved = true,
1018 .bubbles_moved = false,1110 .resized = true,
1019 });1111 .bubbles_moved = false,
1020 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });1112 });
1021 elf.phdrs.items[interp_phndx] = interp_ni;1113 elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx });
10221114 elf.phdrs.items[interp_phndx] = interp_ni;
1023 const sec_interp_si = try elf.addSection(interp_ni, .{1115
1024 .type = .PROGBITS,1116 const sec_interp_si = try elf.addSection(interp_ni, .{
1025 .name = ".interp",1117 .type = .PROGBITS,
1026 .flags = .{ .ALLOC = true },1118 .name = ".interp",
1027 .size = @intCast(interp.len + 1),1119 .flags = .{ .ALLOC = true },
1028 });1120 .size = @intCast(interp.len + 1),
1029 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);1121 });
1030 @memcpy(sec_interp[0..interp.len], interp);1122 const sec_interp = sec_interp_si.node(elf).slice(&elf.mf);
1031 sec_interp[interp.len] = 0;1123 @memcpy(sec_interp[0..interp.len], interp);
1032 }1124 sec_interp[interp.len] = 0;
1033 if (have_dynamic_section) {
1034 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1035 .moved = true,
1036 .bubbles_moved = false,
1037 });
1038 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1039 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
1040
1041 switch (class) {
1042 .NONE, _ => unreachable,
1043 inline else => |ct_class| {
1044 const ElfN = ct_class.ElfN();
1045 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1046 .name = ".dynsym",
1047 .type = .DYNSYM,
1048 .size = @sizeOf(ElfN.Sym) * 1,
1049 .addralign = addr_align,
1050 .entsize = @sizeOf(ElfN.Sym),
1051 });
1052 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1053 dynsym_null.* = .{
1054 .name = try elf.string(.dynstr, ""),
1055 .value = 0,
1056 .size = 0,
1057 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1058 .other = .{ .visibility = .DEFAULT },
1059 .shndx = std.elf.SHN_UNDEF,
1060 };
1061 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null);
1062 },
1063 }1125 }
1064 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{1126 if (have_dynamic_section) {
1065 .name = ".dynstr",1127 const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{
1066 .type = .STRTAB,1128 .moved = true,
1067 .size = 1,1129 .bubbles_moved = false,
1068 .addralign = elf.mf.flags.block_size,1130 });
1069 .entsize = 1,1131 elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx });
1070 });1132 elf.phdrs.items[dynamic_phndx] = dynamic_ni;
1071 elf.si.dynamic = try elf.addSection(dynamic_ni, .{1133
1072 .name = ".dynamic",1134 switch (class) {
1073 .type = .DYNAMIC,1135 .NONE, _ => unreachable,
1074 .flags = .{ .ALLOC = true, .WRITE = true },1136 inline else => |ct_class| {
1075 .addralign = addr_align,1137 const Sym = ct_class.ElfN().Sym;
1076 });1138 elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{
1077 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);1139 .name = ".dynsym",
1078 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);1140 .type = .DYNSYM,
1079 }1141 .size = @sizeOf(Sym) * 1,
1080 if (comp.config.any_non_single_threaded) {1142 .addralign = addr_align,
1081 if (@"type" != .REL) {1143 .entsize = @sizeOf(Sym),
1144 .node_align = elf.mf.flags.block_size,
1145 });
1146 const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0];
1147 dynsym_null.* = .{
1148 .name = try elf.string(.dynstr, ""),
1149 .value = 0,
1150 .size = 0,
1151 .info = .{ .type = .NOTYPE, .bind = .LOCAL },
1152 .other = .{ .visibility = .DEFAULT },
1153 .shndx = std.elf.SHN_UNDEF,
1154 };
1155 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(
1156 Sym,
1157 dynsym_null,
1158 );
1159 },
1160 }
1161 elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{
1162 .name = ".dynstr",
1163 .type = .STRTAB,
1164 .size = 1,
1165 .entsize = 1,
1166 .node_align = elf.mf.flags.block_size,
1167 });
1168 elf.si.dynamic = try elf.addSection(dynamic_ni, .{
1169 .name = ".dynamic",
1170 .type = .DYNAMIC,
1171 .flags = .{ .ALLOC = true, .WRITE = true },
1172 .node_align = addr_align,
1173 });
1174 try elf.linkSections(elf.si.dynamic, elf.si.dynstr);
1175 try elf.linkSections(elf.si.dynsym, elf.si.dynstr);
1176 }
1177 if (comp.config.any_non_single_threaded) {
1082 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{1178 elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{
1083 .alignment = elf.mf.flags.block_size,1179 .alignment = elf.mf.flags.block_size,
1084 .moved = true,1180 .moved = true,
...@@ -1087,13 +1183,15 @@ fn initHeaders(...@@ -1087,13 +1183,15 @@ fn initHeaders(
1087 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });1183 elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx });
1088 elf.phdrs.items[tls_phndx] = elf.ni.tls;1184 elf.phdrs.items[tls_phndx] = elf.ni.tls;
1089 }1185 }
10901186 } else {
1091 elf.si.tdata = try elf.addSection(if (@"type" != .REL) elf.ni.tls else elf.ni.file, .{1187 assert(maybe_interp == null);
1092 .name = ".tdata",1188 assert(!have_dynamic_section);
1093 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1094 .addralign = elf.mf.flags.block_size,
1095 });
1096 }1189 }
1190 if (comp.config.any_non_single_threaded) elf.si.tdata = try elf.addSection(elf.ni.tls, .{
1191 .name = ".tdata",
1192 .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true },
1193 .addralign = elf.mf.flags.block_size,
1194 });
1097 assert(elf.nodes.len == expected_nodes_len);1195 assert(elf.nodes.len == expected_nodes_len);
1098}1196}
10991197
...@@ -1218,6 +1316,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {...@@ -1218,6 +1316,7 @@ pub const PhdrSlice = union(std.elf.CLASS) {
1218 @"64": []std.elf.Elf64.Phdr,1316 @"64": []std.elf.Elf64.Phdr,
1219};1317};
1220pub fn phdrSlice(elf: *Elf) PhdrSlice {1318pub fn phdrSlice(elf: *Elf) PhdrSlice {
1319 assert(elf.ehdrField(.type) != .REL);
1221 const slice = elf.ni.phdr.slice(&elf.mf);1320 const slice = elf.ni.phdr.slice(&elf.mf);
1222 return switch (elf.identClass()) {1321 return switch (elf.identClass()) {
1223 .NONE, _ => unreachable,1322 .NONE, _ => unreachable,
...@@ -1246,6 +1345,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {...@@ -1246,6 +1345,17 @@ pub fn shdrSlice(elf: *Elf) ShdrSlice {
1246 };1345 };
1247}1346}
12481347
1348pub const ShdrPtr = union(std.elf.CLASS) {
1349 NONE: noreturn,
1350 @"32": *std.elf.Elf32.Shdr,
1351 @"64": *std.elf.Elf64.Shdr,
1352};
1353pub fn shdrPtr(elf: *Elf, shndx: Symbol.Index.Shndx) ShdrPtr {
1354 return switch (elf.shdrSlice()) {
1355 inline else => |shdrs, class| @unionInit(ShdrPtr, @tagName(class), &shdrs[@intFromEnum(shndx)]),
1356 };
1357}
1358
1249pub const SymtabSlice = union(std.elf.CLASS) {1359pub const SymtabSlice = union(std.elf.CLASS) {
1250 NONE: noreturn,1360 NONE: noreturn,
1251 @"32": []std.elf.Elf32.Sym,1361 @"32": []std.elf.Elf32.Sym,
...@@ -1258,7 +1368,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {...@@ -1258,7 +1368,11 @@ pub fn symtabSlice(elf: *Elf) SymtabSlice {
1258 inline else => |class| @unionInit(1368 inline else => |class| @unionInit(
1259 SymtabSlice,1369 SymtabSlice,
1260 @tagName(class),1370 @tagName(class),
1261 @ptrCast(@alignCast(slice)),1371 @ptrCast(@alignCast(slice[0..std.mem.alignBackwardAnyAlign(
1372 usize,
1373 slice.len,
1374 @sizeOf(class.ElfN().Sym),
1375 )])),
1262 ),1376 ),
1263 };1377 };
1264}1378}
...@@ -1270,7 +1384,7 @@ pub const SymPtr = union(std.elf.CLASS) {...@@ -1270,7 +1384,7 @@ pub const SymPtr = union(std.elf.CLASS) {
1270};1384};
1271pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {1385pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr {
1272 return switch (elf.symtabSlice()) {1386 return switch (elf.symtabSlice()) {
1273 inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]),1387 inline else => |syms, class| @unionInit(SymPtr, @tagName(class), &syms[@intFromEnum(si)]),
1274 };1388 };
1275}1389}
12761390
...@@ -1560,7 +1674,7 @@ fn loadObject(...@@ -1560,7 +1674,7 @@ fn loadObject(
1560 .si = try elf.initSymbolAssumeCapacity(.{1674 .si = try elf.initSymbolAssumeCapacity(.{
1561 .name = std.fs.path.stem(member orelse path.sub_path),1675 .name = std.fs.path.stem(member orelse path.sub_path),
1562 .type = .FILE,1676 .type = .FILE,
1563 .shndx = std.elf.SHN_ABS,1677 .shndx = .ABS,
1564 }),1678 }),
1565 };1679 };
1566 const target_endian = elf.targetEndian();1680 const target_endian = elf.targetEndian();
...@@ -1626,7 +1740,7 @@ fn loadObject(...@@ -1626,7 +1740,7 @@ fn loadObject(
1626 });1740 });
1627 section.si = try elf.initSymbolAssumeCapacity(.{1741 section.si = try elf.initSymbolAssumeCapacity(.{
1628 .type = .SECTION,1742 .type = .SECTION,
1629 .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx),1743 .shndx = parent_si.shndx(elf),
1630 });1744 });
1631 section.si.get(elf).ni = ni;1745 section.si.get(elf).ni = ni;
1632 elf.input_sections.addOneAssumeCapacity().* = .{1746 elf.input_sections.addOneAssumeCapacity().* = .{
...@@ -1698,9 +1812,7 @@ fn loadObject(...@@ -1698,9 +1812,7 @@ fn loadObject(
1698 .type = input_sym.info.type,1812 .type = input_sym.info.type,
1699 .bind = input_sym.info.bind,1813 .bind = input_sym.info.bind,
1700 .visibility = input_sym.other.visibility,1814 .visibility = input_sym.other.visibility,
1701 .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) {1815 .shndx = parent_si.shndx(elf),
1702 inline else => |parent_sym| &parent_sym.shndx,
1703 }),
1704 });1816 });
1705 si.get(elf).ni = parent_si.get(elf).ni;1817 si.get(elf).ni = parent_si.get(elf).ni;
1706 switch (input_sym.info.bind) {1818 switch (input_sym.info.bind) {
...@@ -1755,7 +1867,7 @@ fn loadObject(...@@ -1755,7 +1867,7 @@ fn loadObject(
1755 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",1867 "relocation section size (0x{x}) is not a multiple of entsize (0x{x})",
1756 .{ rels.shdr.size, rels.shdr.entsize },1868 .{ rels.shdr.size, rels.shdr.entsize },
1757 );1869 );
1758 try elf.relocs.ensureUnusedCapacity(gpa, relnum);1870 try elf.ensureUnusedRelocCapacity(loc_sec.si, relnum);
1759 try fr.seekTo(fl.offset + rels.shdr.offset);1871 try fr.seekTo(fl.offset + rels.shdr.offset);
1760 for (0..relnum) |_| {1872 for (0..relnum) |_| {
1761 const rel = try r.peekStruct(Rel, target_endian);1873 const rel = try r.peekStruct(Rel, target_endian);
...@@ -1832,13 +1944,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void...@@ -1832,13 +1944,13 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void
1832 var soname: ?ElfN.Addr = null;1944 var soname: ?ElfN.Addr = null;
1833 try fr.seekTo(dynamic_ph.offset);1945 try fr.seekTo(dynamic_ph.offset);
1834 for (0..dynnum) |_| {1946 for (0..dynnum) |_| {
1835 const key = try r.takeInt(ElfN.Addr, target_endian);1947 const tag = try r.takeInt(ElfN.Addr, target_endian);
1836 const value = try r.takeInt(ElfN.Addr, target_endian);1948 const val = try r.takeInt(ElfN.Addr, target_endian);
1837 switch (key) {1949 switch (tag) {
1838 else => {},1950 else => {},
1839 std.elf.DT_STRTAB => strtab = value,1951 std.elf.DT_STRTAB => strtab = val,
1840 std.elf.DT_STRSZ => strsz = value,1952 std.elf.DT_STRSZ => strsz = val,
1841 std.elf.DT_SONAME => soname = value,1953 std.elf.DT_SONAME => soname = val,
1842 }1954 }
1843 }1955 }
1844 if (strtab == null or soname == null)1956 if (strtab == null or soname == null)
...@@ -1883,11 +1995,7 @@ fn prelinkInner(elf: *Elf) !void {...@@ -1883,11 +1995,7 @@ fn prelinkInner(elf: *Elf) !void {
1883 std.fs.path.stem(elf.base.emit.sub_path),1995 std.fs.path.stem(elf.base.emit.sub_path),
1884 });1996 });
1885 defer gpa.free(zcu_name);1997 defer gpa.free(zcu_name);
1886 const si = try elf.initSymbolAssumeCapacity(.{1998 const si = try elf.initSymbolAssumeCapacity(.{ .name = zcu_name, .type = .FILE, .shndx = .ABS });
1887 .name = zcu_name,
1888 .type = .FILE,
1889 .shndx = std.elf.SHN_ABS,
1890 });
1891 elf.inputs.addOneAssumeCapacity().* = .{1999 elf.inputs.addOneAssumeCapacity().* = .{
1892 .path = elf.base.emit,2000 .path = elf.base.emit,
1893 .member = null,2001 .member = null,
...@@ -1989,9 +2097,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -1989,9 +2097,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
1989 name: []const u8 = "",2097 name: []const u8 = "",
1990 type: std.elf.SHT = .NULL,2098 type: std.elf.SHT = .NULL,
1991 flags: std.elf.SHF = .{},2099 flags: std.elf.SHF = .{},
1992 size: std.elf.Word = 0,2100 size: std.elf.Xword = 0,
2101 link: std.elf.Word = 0,
2102 info: std.elf.Word = 0,
1993 addralign: std.mem.Alignment = .@"1",2103 addralign: std.mem.Alignment = .@"1",
1994 entsize: std.elf.Word = 0,2104 entsize: std.elf.Word = 0,
2105 node_align: std.mem.Alignment = .@"1",
1995}) !Symbol.Index {2106}) !Symbol.Index {
1996 switch (opts.type) {2107 switch (opts.type) {
1997 .NULL => assert(opts.size == 0),2108 .NULL => assert(opts.size == 0),
...@@ -2000,50 +2111,71 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2000,50 +2111,71 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
2000 }2111 }
2001 const gpa = elf.base.comp.gpa;2112 const gpa = elf.base.comp.gpa;
2002 try elf.nodes.ensureUnusedCapacity(gpa, 1);2113 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2114 try elf.shdrs.ensureUnusedCapacity(gpa, 1);
2003 try elf.symtab.ensureUnusedCapacity(gpa, 1);2115 try elf.symtab.ensureUnusedCapacity(gpa, 1);
20042116
2005 const shstrtab_entry = try elf.string(.shstrtab, opts.name);2117 const shstrtab_entry = try elf.string(.shstrtab, opts.name);
2006 const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) {2118 const shndx: Symbol.Index.Shndx, const new_shdr_size = shndx: switch (elf.ehdrPtr()) {
2007 inline else => |ehdr| {2119 inline else => |ehdr, class| {
2008 const shndx = elf.targetLoad(&ehdr.shnum);2120 const shndx, const shnum = alloc_shndx: switch (elf.targetLoad(&ehdr.shnum)) {
2009 const shnum = shndx + 1;2121 1...std.elf.SHN_LORESERVE - 2 => |shndx| {
2010 elf.targetStore(&ehdr.shnum, shnum);2122 const shnum = shndx + 1;
2011 break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum };2123 elf.targetStore(&ehdr.shnum, shnum);
2124 break :alloc_shndx .{ shndx, shnum };
2125 },
2126 std.elf.SHN_LORESERVE - 1 => |shndx| {
2127 const shnum = shndx + 1;
2128 elf.targetStore(&ehdr.shnum, 0);
2129 elf.targetStore(&@field(elf.shdrPtr(.UNDEF), @tagName(class)).size, shnum);
2130 break :alloc_shndx .{ shndx, shnum };
2131 },
2132 std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => unreachable,
2133 0 => {
2134 const shnum_ptr = &@field(elf.shdrPtr(.UNDEF), @tagName(class)).size;
2135 const shndx: u32 = @intCast(elf.targetLoad(shnum_ptr));
2136 const shnum = shndx + 1;
2137 elf.targetStore(shnum_ptr, shnum);
2138 break :alloc_shndx .{ shndx, shnum };
2139 },
2140 };
2141 assert(shndx < @intFromEnum(Symbol.Index.Shndx.LORESERVE));
2142 break :shndx .{ @enumFromInt(shndx), elf.targetLoad(&ehdr.shentsize) * shnum };
2012 },2143 },
2013 };2144 };
2014 try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size);2145 _, const shdr_node_size = elf.ni.shdr.location(&elf.mf).resolve(&elf.mf);
2015 const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{2146 if (new_shdr_size > shdr_node_size)
2016 .alignment = opts.addralign,2147 try elf.ni.shdr.resize(&elf.mf, gpa, new_shdr_size +| new_shdr_size / MappedFile.growth_factor);
2148 const ni = try elf.mf.addLastChildNode(gpa, switch (elf.ehdrField(.type)) {
2149 .NONE, .CORE, _ => unreachable,
2150 .REL => elf.ni.file,
2151 .EXEC, .DYN => segment_ni,
2152 }, .{
2153 .alignment = opts.addralign.max(opts.node_align),
2017 .size = opts.size,2154 .size = opts.size,
2018 .resized = opts.size > 0,2155 .resized = opts.size > 0,
2019 });2156 });
2020 const si = elf.addSymbolAssumeCapacity();2157 const si = elf.addSymbolAssumeCapacity();
2021 elf.nodes.appendAssumeCapacity(.{ .section = si });2158 elf.nodes.appendAssumeCapacity(.{ .section = si });
2159 elf.shdrs.appendAssumeCapacity(.{ .si = si, .rela_si = .null });
2022 si.get(elf).ni = ni;2160 si.get(elf).ni = ni;
2023 const addr = elf.computeNodeVAddr(ni);2161 const addr = elf.computeNodeVAddr(ni);
2024 const offset = ni.fileLocation(&elf.mf, false).offset;2162 const offset = ni.fileLocation(&elf.mf, false).offset;
2025 try si.init(elf, .{2163 try si.init(elf, .{ .value = addr, .type = .SECTION, .shndx = shndx });
2026 .value = addr,2164 switch (elf.shdrPtr(shndx)) {
2027 .size = opts.size,2165 inline else => |shdr, class| {
2028 .type = .SECTION,2166 shdr.* = .{
2029 .shndx = shndx,
2030 });
2031 switch (elf.shdrSlice()) {
2032 inline else => |shdr| {
2033 const sh = &shdr[shndx];
2034 sh.* = .{
2035 .name = shstrtab_entry,2167 .name = shstrtab_entry,
2036 .type = opts.type,2168 .type = opts.type,
2037 .flags = .{ .shf = opts.flags },2169 .flags = .{ .shf = opts.flags },
2038 .addr = @intCast(addr),2170 .addr = @intCast(addr),
2039 .offset = @intCast(offset),2171 .offset = @intCast(offset),
2040 .size = opts.size,2172 .size = @intCast(opts.size),
2041 .link = 0,2173 .link = opts.link,
2042 .info = 0,2174 .info = opts.info,
2043 .addralign = @intCast(opts.addralign.toByteUnits()),2175 .addralign = @intCast(opts.addralign.toByteUnits()),
2044 .entsize = opts.entsize,2176 .entsize = opts.entsize,
2045 };2177 };
2046 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh);2178 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr);
2047 },2179 },
2048 }2180 }
2049 return si;2181 return si;
...@@ -2051,39 +2183,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {...@@ -2051,39 +2183,27 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct {
20512183
2052fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {2184fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void {
2053 const shstrtab_entry = try elf.string(.shstrtab, name);2185 const shstrtab_entry = try elf.string(.shstrtab, name);
2054 switch (elf.shdrSlice()) {2186 switch (elf.shdrPtr(si.shndx(elf))) {
2055 inline else => |shdr, class| elf.targetStore(2187 inline else => |shdr| elf.targetStore(&shdr.name, shstrtab_entry),
2056 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2057 shstrtab_entry,
2058 ),
2059 }2188 }
2060}2189}
20612190
2062fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {2191fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void {
2063 switch (elf.shdrSlice()) {2192 switch (elf.shdrPtr(si.shndx(elf))) {
2064 inline else => |shdr, class| shdr[2193 inline else => |shdr| elf.targetStore(&shdr.link, @intFromEnum(link_si.shndx(elf))),
2065 elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)
2066 ].link = @field(elf.symPtr(link_si), @tagName(class)).shndx,
2067 }2194 }
2068}2195}
20692196
2070fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {2197fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 {
2071 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) {2198 const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrPtr(si.shndx(elf))) {
2072 inline else => |shndx, class| elf.targetLoad(2199 inline else => |shdr| elf.targetLoad(&shdr.name),
2073 &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name,
2074 ),
2075 }..];2200 }..];
2076 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];2201 return name[0..std.mem.indexOfScalar(u8, name, 0).? :0];
2077}2202}
20782203
2079fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {2204fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 {
2080 if (key.len == 0) return 0;2205 if (key.len == 0) return 0;
2081 return @field(elf, @tagName(section)).get(2206 return @field(elf, @tagName(section)).get(elf, @field(elf.si, @tagName(section)), key);
2082 elf.base.comp.gpa,
2083 &elf.mf,
2084 @field(elf.si, @tagName(section)).node(elf),
2085 key,
2086 );
2087}2207}
20882208
2089pub fn addReloc(2209pub fn addReloc(
...@@ -2094,9 +2214,51 @@ pub fn addReloc(...@@ -2094,9 +2214,51 @@ pub fn addReloc(
2094 addend: i64,2214 addend: i64,
2095 @"type": Reloc.Type,2215 @"type": Reloc.Type,
2096) !void {2216) !void {
2097 try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1);2217 try elf.ensureUnusedRelocCapacity(loc_si, 1);
2098 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");2218 elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type");
2099}2219}
2220pub fn ensureUnusedRelocCapacity(elf: *Elf, loc_si: Symbol.Index, len: usize) !void {
2221 if (len == 0) return;
2222 const gpa = elf.base.comp.gpa;
2223
2224 try elf.relocs.ensureUnusedCapacity(gpa, len);
2225 if (elf.ehdrField(.type) != .REL) return;
2226
2227 const shndx = loc_si.shndx(elf);
2228 const sh = shndx.get(elf);
2229 if (sh.rela_si == .null) {
2230 var stack = std.heap.stackFallback(32, gpa);
2231 const allocator = stack.get();
2232
2233 const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{elf.sectionName(sh.si)});
2234 defer allocator.free(rela_name);
2235
2236 const class = elf.identClass();
2237 sh.rela_si = try elf.addSection(.none, .{
2238 .name = rela_name,
2239 .type = .RELA,
2240 .link = @intFromEnum(elf.si.symtab.shndx(elf)),
2241 .info = @intFromEnum(shndx),
2242 .addralign = switch (class) {
2243 .NONE, _ => unreachable,
2244 .@"32" => .@"4",
2245 .@"64" => .@"8",
2246 },
2247 .entsize = switch (class) {
2248 .NONE, _ => unreachable,
2249 inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela),
2250 },
2251 .node_align = elf.mf.flags.block_size,
2252 });
2253 }
2254 const rela_ni = sh.rela_si.node(elf);
2255 _, const rela_node_size = rela_ni.location(&elf.mf).resolve(&elf.mf);
2256 const rela_size = switch (elf.shdrPtr(sh.rela_si.shndx(elf))) {
2257 inline else => |shdr| elf.targetLoad(&shdr.size) + elf.targetLoad(&shdr.entsize) * len,
2258 };
2259 if (rela_size > rela_node_size)
2260 try rela_ni.resize(&elf.mf, gpa, rela_size +| rela_size / MappedFile.growth_factor);
2261}
2100pub fn addRelocAssumeCapacity(2262pub fn addRelocAssumeCapacity(
2101 elf: *Elf,2263 elf: *Elf,
2102 loc_si: Symbol.Index,2264 loc_si: Symbol.Index,
...@@ -2113,7 +2275,40 @@ pub fn addRelocAssumeCapacity(...@@ -2113,7 +2275,40 @@ pub fn addRelocAssumeCapacity(
2113 .next = target.target_relocs,2275 .next = target.target_relocs,
2114 .loc = loc_si,2276 .loc = loc_si,
2115 .target = target_si,2277 .target = target_si,
2116 .unused = 0,2278 .rel_index = switch (elf.ehdrField(.type)) {
2279 .NONE, .CORE, _ => unreachable,
2280 .REL => rel_index: {
2281 const rela_si = loc_si.shndx(elf).get(elf).rela_si;
2282 switch (elf.shdrPtr(rela_si.shndx(elf))) {
2283 inline else => |shdr, class| {
2284 const Rela = class.ElfN().Rela;
2285 const old_size = elf.targetLoad(&shdr.size);
2286 const ent_size = elf.targetLoad(&shdr.entsize);
2287 const new_size = old_size + ent_size;
2288 elf.targetStore(&shdr.size, @intCast(new_size));
2289 const rela: *Rela = @ptrCast(@alignCast(
2290 rela_si.node(elf).slice(&elf.mf)[@intCast(old_size)..@intCast(new_size)],
2291 ));
2292 rela.* = .{
2293 .offset = @intCast(offset),
2294 .info = .{
2295 .type = switch (elf.ehdrField(.machine)) {
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)),
2302 },
2303 .addend = @intCast(addend),
2304 };
2305 if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(Rela, rela);
2306 break :rel_index @intCast(@divExact(old_size, ent_size));
2307 },
2308 }
2309 },
2310 .EXEC, .DYN => 0,
2311 },
2117 .offset = offset,2312 .offset = offset,
2118 .addend = addend,2313 .addend = addend,
2119 };2314 };
...@@ -2479,7 +2674,8 @@ fn flushUav(...@@ -2479,7 +2674,8 @@ fn flushUav(
2479 switch (sym.ni) {2674 switch (sym.ni) {
2480 .none => {2675 .none => {
2481 try elf.nodes.ensureUnusedCapacity(gpa, 1);2676 try elf.nodes.ensureUnusedCapacity(gpa, 1);
2482 const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{2677 const sec_si = elf.si.data;
2678 const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
2483 .alignment = uav_align.toStdMem(),2679 .alignment = uav_align.toStdMem(),
2484 .moved = true,2680 .moved = true,
2485 });2681 });
...@@ -2487,7 +2683,7 @@ fn flushUav(...@@ -2487,7 +2683,7 @@ fn flushUav(
2487 sym.ni = ni;2683 sym.ni = ni;
2488 switch (elf.symPtr(si)) {2684 switch (elf.symPtr(si)) {
2489 inline else => |sym_ptr, class| sym_ptr.shndx =2685 inline else => |sym_ptr, class| sym_ptr.shndx =
2490 @field(elf.symPtr(.data), @tagName(class)).shndx,2686 @field(elf.symPtr(sec_si), @tagName(class)).shndx,
2491 }2687 }
2492 },2688 },
2493 else => {2689 else => {
...@@ -2611,11 +2807,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2611,11 +2807,10 @@ fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void {
2611 var child_it = ni.children(&elf.mf);2807 var child_it = ni.children(&elf.mf);
2612 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);2808 while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni);
2613 },2809 },
2614 .section => |si| switch (elf.shdrSlice()) {2810 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
2615 inline else => |shdr, class| elf.targetStore(2811 inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(
2616 &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset,2812 ni.fileLocation(&elf.mf, false).offset,
2617 @intCast(ni.fileLocation(&elf.mf, false).offset),2813 )),
2618 ),
2619 },2814 },
2620 }2815 }
2621}2816}
...@@ -2644,14 +2839,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2644,14 +2839,12 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void {
2644 .section => |si| {2839 .section => |si| {
2645 try elf.flushFileOffset(ni);2840 try elf.flushFileOffset(ni);
2646 const addr = elf.computeNodeVAddr(ni);2841 const addr = elf.computeNodeVAddr(ni);
2647 switch (elf.shdrSlice()) {2842 switch (elf.shdrPtr(si.shndx(elf))) {
2648 inline else => |shdr, class| {2843 inline else => |shdr, class| {
2649 const sym = @field(elf.symPtr(si), @tagName(class));2844 const flags = elf.targetLoad(&shdr.flags).shf;
2650 const sh = &shdr[elf.targetLoad(&sym.shndx)];
2651 const flags = elf.targetLoad(&sh.flags).shf;
2652 if (flags.ALLOC) {2845 if (flags.ALLOC) {
2653 elf.targetStore(&sh.addr, @intCast(addr));2846 elf.targetStore(&shdr.addr, @intCast(addr));
2654 sym.value = sh.addr;2847 @field(elf.symPtr(si), @tagName(class)).value = shdr.addr;
2655 }2848 }
2656 },2849 },
2657 }2850 }
...@@ -2732,20 +2925,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {...@@ -2732,20 +2925,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void {
2732 }2925 }
2733 },2926 },
2734 },2927 },
2735 .section => |si| switch (elf.symPtr(si)) {2928 .section => |si| switch (elf.shdrPtr(si.shndx(elf))) {
2736 inline else => |sym, class| {2929 inline else => |shdr| {
2737 const sh = &@field(elf.shdrSlice(), @tagName(class))[elf.targetLoad(&sym.shndx)];2930 switch (elf.targetLoad(&shdr.type)) {
2738 elf.targetStore(&sh.size, @intCast(size));
2739 switch (elf.targetLoad(&sh.type)) {
2740 else => unreachable,2931 else => unreachable,
2741 .NULL => if (size > 0) elf.targetStore(&sh.type, .PROGBITS),2932 .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS),
2742 .PROGBITS => if (size == 0) elf.targetStore(&sh.type, .NULL),2933 .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL),
2743 .SYMTAB, .DYNSYM => elf.targetStore(2934 .SYMTAB, .STRTAB, .RELA, .DYNAMIC, .REL, .DYNSYM => return,
2744 &sh.info,
2745 @intCast(@divExact(size, elf.targetLoad(&sh.entsize))),
2746 ),
2747 .STRTAB, .DYNAMIC => {},
2748 }2935 }
2936 elf.targetStore(&shdr.size, @intCast(size));
2749 },2937 },
2750 },2938 },
2751 .input_section => {},2939 .input_section => {},