authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-31 17:54:12+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-01-31 17:54:12+01:00
log4404c4d20094bb5021aac4a047cd33b6c24b9a9b
tree44fdee8a39eb543c69ffc2e40d1e60efb66149ac
parentd42a93105142e3e8f1d02efeecc0c0e52457a5d9

link: make Elf atoms fully owned by the linker


12 files changed, 901 insertions(+), 824 deletions(-)

src/Module.zig+3-3
......@@ -5275,7 +5275,7 @@ pub fn clearDecl(
52755275 // and allow it to be variably sized.
52765276 decl.link = switch (mod.comp.bin_file.tag) {
52775277 .coff => .{ .coff = link.File.Coff.Atom.empty },
5278 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
5278 .elf => .{ .elf = {} },
52795279 .macho => .{ .macho = {} },
52805280 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
52815281 .c => .{ .c = {} },
......@@ -5381,7 +5381,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
53815381 }
53825382 }
53835383 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
5384 elf.deleteExport(exp.link.elf);
5384 elf.deleteDeclExport(decl_index, exp.options.name);
53855385 }
53865386 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
53875387 try macho.deleteDeclExport(decl_index, exp.options.name);
......@@ -5695,7 +5695,7 @@ pub fn allocateNewDecl(
56955695 .src_scope = src_scope,
56965696 .link = switch (mod.comp.bin_file.tag) {
56975697 .coff => .{ .coff = link.File.Coff.Atom.empty },
5698 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
5698 .elf => .{ .elf = {} },
56995699 .macho => .{ .macho = {} },
57005700 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
57015701 .c => .{ .c = {} },
src/Sema.zig+1-1
......@@ -5566,7 +5566,7 @@ pub fn analyzeExport(
55665566 .src = src,
55675567 .link = switch (mod.comp.bin_file.tag) {
55685568 .coff => .{ .coff = .{} },
5569 .elf => .{ .elf = .{} },
5569 .elf => .{ .elf = {} },
55705570 .macho => .{ .macho = {} },
55715571 .plan9 => .{ .plan9 = null },
55725572 .c => .{ .c = {} },
src/arch/aarch64/CodeGen.zig+7-6
......@@ -4308,8 +4308,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43084308 const fn_owner_decl = mod.declPtr(func.owner_decl);
43094309
43104310 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4311 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4312 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4311 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4312 const atom = elf_file.getAtom(atom_index);
4313 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
43134314 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
43144315 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
43154316 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
......@@ -6138,8 +6139,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
61386139 mod.markDeclAlive(decl);
61396140
61406141 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6141 try decl.link.elf.ensureInitialized(elf_file);
6142 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6142 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6143 const atom = elf_file.getAtom(atom_index);
6144 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
61436145 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
61446146 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
61456147 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
......@@ -6168,8 +6170,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
61686170 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
61696171 };
61706172 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6171 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6172 return MCValue{ .memory = vaddr };
6173 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
61736174 } else if (self.bin_file.cast(link.File.MachO)) |_| {
61746175 return MCValue{ .linker_load = .{
61756176 .type = .direct,
src/arch/arm/CodeGen.zig+7-8
......@@ -4256,12 +4256,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42564256 if (self.air.value(callee)) |func_value| {
42574257 if (func_value.castTag(.function)) |func_payload| {
42584258 const func = func_payload.data;
4259 const mod = self.bin_file.options.module.?;
4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
42614259
42624260 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4261 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4262 const atom = elf_file.getAtom(atom_index);
4263 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
42654264 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
42664265 } else if (self.bin_file.cast(link.File.MachO)) |_| {
42674266 unreachable; // unsupported architecture for MachO
......@@ -6084,8 +6083,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
60846083 mod.markDeclAlive(decl);
60856084
60866085 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6087 try decl.link.elf.ensureInitialized(elf_file);
6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6086 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6087 const atom = elf_file.getAtom(atom_index);
6088 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
60896089 } else if (self.bin_file.cast(link.File.MachO)) |_| {
60906090 unreachable; // unsupported architecture for MachO
60916091 } else if (self.bin_file.cast(link.File.Coff)) |_| {
......@@ -6106,8 +6106,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
61066106 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
61076107 };
61086108 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6109 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6110 return MCValue{ .memory = vaddr };
6109 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
61116110 } else if (self.bin_file.cast(link.File.MachO)) |_| {
61126111 unreachable;
61136112 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/riscv64/CodeGen.zig+6-8
......@@ -1721,12 +1721,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17211721 if (self.air.value(callee)) |func_value| {
17221722 if (func_value.castTag(.function)) |func_payload| {
17231723 const func = func_payload.data;
1724
1725 const mod = self.bin_file.options.module.?;
1726 const fn_owner_decl = mod.declPtr(func.owner_decl);
1727 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1728 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1729
1724 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1725 const atom = elf_file.getAtom(atom_index);
1726 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
17301727 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
17311728 _ = try self.addInst(.{
17321729 .tag = .jalr,
......@@ -2553,8 +2550,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
25532550 const decl = mod.declPtr(decl_index);
25542551 mod.markDeclAlive(decl);
25552552 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2556 try decl.link.elf.ensureInitialized(elf_file);
2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
2553 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
2554 const atom = elf_file.getAtom(atom_index);
2555 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
25582556 } else if (self.bin_file.cast(link.File.MachO)) |_| {
25592557 unreachable;
25602558 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/sparc64/CodeGen.zig+6-6
......@@ -1216,11 +1216,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
12161216 if (self.bin_file.tag == link.File.Elf.base_tag) {
12171217 if (func_value.castTag(.function)) |func_payload| {
12181218 const func = func_payload.data;
1219 const mod = self.bin_file.options.module.?;
1220 const fn_owner_decl = mod.declPtr(func.owner_decl);
12211219 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
1220 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1221 const atom = elf_file.getAtom(atom_index);
1222 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));
12241223 } else unreachable;
12251224
12261225 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });
......@@ -4205,8 +4204,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42054204
42064205 mod.markDeclAlive(decl);
42074206 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4208 try decl.link.elf.ensureInitialized(elf_file);
4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
4207 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
4208 const atom = elf_file.getAtom(atom_index);
4209 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
42104210 } else {
42114211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
42124212 }
src/arch/x86_64/CodeGen.zig+7-6
......@@ -4000,8 +4000,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
40004000 const fn_owner_decl = mod.declPtr(func.owner_decl);
40014001
40024002 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4003 try fn_owner_decl.link.elf.ensureInitialized(elf_file);
4004 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));
4003 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4004 const atom = elf_file.getAtom(atom_index);
4005 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
40054006 _ = try self.addInst(.{
40064007 .tag = .call,
40074008 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
......@@ -6721,8 +6722,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
67216722 module.markDeclAlive(decl);
67226723
67236724 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6724 try decl.link.elf.ensureInitialized(elf_file);
6725 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };
6725 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6726 const atom = elf_file.getAtom(atom_index);
6727 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
67266728 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
67276729 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
67286730 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
......@@ -6751,8 +6753,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
67516753 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
67526754 };
67536755 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6754 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;
6755 return MCValue{ .memory = vaddr };
6756 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
67566757 } else if (self.bin_file.cast(link.File.MachO)) |_| {
67576758 return MCValue{ .linker_load = .{
67586759 .type = .direct,
src/link.zig+2-2
......@@ -262,7 +262,7 @@ pub const File = struct {
262262 lock: ?Cache.Lock = null,
263263
264264 pub const LinkBlock = union {
265 elf: Elf.TextBlock,
265 elf: void,
266266 coff: Coff.Atom,
267267 macho: void,
268268 plan9: Plan9.DeclBlock,
......@@ -284,7 +284,7 @@ pub const File = struct {
284284 };
285285
286286 pub const Export = union {
287 elf: Elf.Export,
287 elf: void,
288288 coff: Coff.Export,
289289 macho: void,
290290 plan9: Plan9.Export,
src/link/Dwarf.zig+13-13
......@@ -1099,7 +1099,7 @@ pub fn commitDeclState(
10991099 switch (self.bin_file.tag) {
11001100 .elf => {
11011101 const elf_file = self.bin_file.cast(File.Elf).?;
1102 const debug_line_sect = &elf_file.sections.items[elf_file.debug_line_section_index.?];
1102 const debug_line_sect = &elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
11031103 const file_pos = debug_line_sect.sh_offset + src_fn.off;
11041104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
11051105 },
......@@ -1152,7 +1152,7 @@ pub fn commitDeclState(
11521152 const elf_file = self.bin_file.cast(File.Elf).?;
11531153 const shdr_index = elf_file.debug_line_section_index.?;
11541154 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1155 const debug_line_sect = elf_file.sections.items[shdr_index];
1155 const debug_line_sect = elf_file.sections.items(.shdr)[shdr_index];
11561156 const file_pos = debug_line_sect.sh_offset + src_fn.off;
11571157 try pwriteDbgLineNops(
11581158 elf_file.base.file.?,
......@@ -1332,7 +1332,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
13321332 switch (self.bin_file.tag) {
13331333 .elf => {
13341334 const elf_file = self.bin_file.cast(File.Elf).?;
1335 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
1335 const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
13361336 const file_pos = debug_info_sect.sh_offset + atom.off;
13371337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
13381338 },
......@@ -1399,7 +1399,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
13991399 const elf_file = self.bin_file.cast(File.Elf).?;
14001400 const shdr_index = elf_file.debug_info_section_index.?;
14011401 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
1402 const debug_info_sect = elf_file.sections.items[shdr_index];
1402 const debug_info_sect = elf_file.sections.items(.shdr)[shdr_index];
14031403 const file_pos = debug_info_sect.sh_offset + atom.off;
14041404 try pwriteDbgInfoNops(
14051405 elf_file.base.file.?,
......@@ -1475,7 +1475,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
14751475 switch (self.bin_file.tag) {
14761476 .elf => {
14771477 const elf_file = self.bin_file.cast(File.Elf).?;
1478 const shdr = elf_file.sections.items[elf_file.debug_line_section_index.?];
1478 const shdr = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
14791479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
14801480 try elf_file.base.file.?.pwriteAll(&data, file_pos);
14811481 },
......@@ -1690,7 +1690,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
16901690 const elf_file = self.bin_file.cast(File.Elf).?;
16911691 const shdr_index = elf_file.debug_abbrev_section_index.?;
16921692 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);
1693 const debug_abbrev_sect = elf_file.sections.items[shdr_index];
1693 const debug_abbrev_sect = elf_file.sections.items(.shdr)[shdr_index];
16941694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
16951695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
16961696 },
......@@ -1805,7 +1805,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
18051805 switch (self.bin_file.tag) {
18061806 .elf => {
18071807 const elf_file = self.bin_file.cast(File.Elf).?;
1808 const debug_info_sect = elf_file.sections.items[elf_file.debug_info_section_index.?];
1808 const debug_info_sect = elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
18091809 const file_pos = debug_info_sect.sh_offset;
18101810 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
18111811 },
......@@ -2124,7 +2124,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
21242124 const elf_file = self.bin_file.cast(File.Elf).?;
21252125 const shdr_index = elf_file.debug_aranges_section_index.?;
21262126 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);
2127 const debug_aranges_sect = elf_file.sections.items[shdr_index];
2127 const debug_aranges_sect = elf_file.sections.items(.shdr)[shdr_index];
21282128 const file_pos = debug_aranges_sect.sh_offset;
21292129 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
21302130 },
......@@ -2285,9 +2285,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
22852285 .elf => {
22862286 const elf_file = self.bin_file.cast(File.Elf).?;
22872287 const shdr_index = elf_file.debug_line_section_index.?;
2288 const needed_size = elf_file.sections.items[shdr_index].sh_size + delta;
2288 const needed_size = elf_file.sections.items(.shdr)[shdr_index].sh_size + delta;
22892289 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);
2290 const file_pos = elf_file.sections.items[shdr_index].sh_offset + src_fn.off;
2290 const file_pos = elf_file.sections.items(.shdr)[shdr_index].sh_offset + src_fn.off;
22912291
22922292 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
22932293 if (amt != buffer.len) return error.InputOutput;
......@@ -2346,7 +2346,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
23462346 switch (self.bin_file.tag) {
23472347 .elf => {
23482348 const elf_file = self.bin_file.cast(File.Elf).?;
2349 const debug_line_sect = elf_file.sections.items[elf_file.debug_line_section_index.?];
2349 const debug_line_sect = elf_file.sections.items(.shdr)[elf_file.debug_line_section_index.?];
23502350 const file_pos = debug_line_sect.sh_offset;
23512351 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
23522352 },
......@@ -2487,7 +2487,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
24872487 switch (self.bin_file.tag) {
24882488 .elf => {
24892489 const elf_file = self.bin_file.cast(File.Elf).?;
2490 const debug_info_sect = &elf_file.sections.items[elf_file.debug_info_section_index.?];
2490 const debug_info_sect = &elf_file.sections.items(.shdr)[elf_file.debug_info_section_index.?];
24912491 break :blk debug_info_sect.sh_offset;
24922492 },
24932493 .macho => {
......@@ -2638,7 +2638,7 @@ fn addDbgInfoErrorSet(
26382638fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom {
26392639 const decl = mod.declPtr(decl_index);
26402640 return switch (tag) {
2641 .elf => &decl.link.elf.dbg_info_atom,
2641 .elf => unreachable,
26422642 .macho => unreachable,
26432643 .wasm => &decl.link.wasm.dbg_info_atom,
26442644 else => unreachable,
src/link/Elf.zig+812-743
......@@ -1,43 +1,89 @@
11const Elf = @This();
22
33const std = @import("std");
4const build_options = @import("build_options");
45const builtin = @import("builtin");
5const math = std.math;
6const mem = std.mem;
76const assert = std.debug.assert;
8const Allocator = std.mem.Allocator;
9const fs = std.fs;
107const elf = std.elf;
8const fs = std.fs;
119const log = std.log.scoped(.link);
10const math = std.math;
11const mem = std.mem;
1212
13const Atom = @import("Elf/Atom.zig");
14const Module = @import("../Module.zig");
15const Compilation = @import("../Compilation.zig");
16const Dwarf = @import("Dwarf.zig");
1713const codegen = @import("../codegen.zig");
18const lldMain = @import("../main.zig").lldMain;
19const trace = @import("../tracy.zig").trace;
20const Package = @import("../Package.zig");
21const Value = @import("../value.zig").Value;
22const Type = @import("../type.zig").Type;
23const TypedValue = @import("../TypedValue.zig");
24const link = @import("../link.zig");
25const File = link.File;
26const build_options = @import("build_options");
27const target_util = @import("../target.zig");
2814const glibc = @import("../glibc.zig");
15const link = @import("../link.zig");
16const lldMain = @import("../main.zig").lldMain;
2917const musl = @import("../musl.zig");
30const Cache = @import("../Cache.zig");
18const target_util = @import("../target.zig");
19const trace = @import("../tracy.zig").trace;
20
3121const Air = @import("../Air.zig");
22const Allocator = std.mem.Allocator;
23pub const Atom = @import("Elf/Atom.zig");
24const Cache = @import("../Cache.zig");
25const Compilation = @import("../Compilation.zig");
26const Dwarf = @import("Dwarf.zig");
27const File = link.File;
3228const Liveness = @import("../Liveness.zig");
3329const LlvmObject = @import("../codegen/llvm.zig").Object;
34
35pub const TextBlock = Atom;
30const Module = @import("../Module.zig");
31const Package = @import("../Package.zig");
32const StringTable = @import("strtab.zig").StringTable;
33const Type = @import("../type.zig").Type;
34const TypedValue = @import("../TypedValue.zig");
35const Value = @import("../value.zig").Value;
3636
3737const default_entry_addr = 0x8000000;
3838
3939pub const base_tag: File.Tag = .elf;
4040
41const Section = struct {
42 shdr: elf.Elf64_Shdr,
43 phdr_index: u16,
44
45 /// Index of the last allocated atom in this section.
46 last_atom_index: ?Atom.Index = null,
47
48 /// A list of atoms that have surplus capacity. This list can have false
49 /// positives, as functions grow and shrink over time, only sometimes being added
50 /// or removed from the freelist.
51 ///
52 /// An atom has surplus capacity when its overcapacity value is greater than
53 /// padToIdeal(minimum_atom_size). That is, when it has so
54 /// much extra capacity, that we could fit a small new symbol in it, itself with
55 /// ideal_capacity or more.
56 ///
57 /// Ideal capacity is defined by size + (size / ideal_factor)
58 ///
59 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
60 /// overcapacity can be negative. A simple way to have negative overcapacity is to
61 /// allocate a fresh text block, which will have ideal capacity, and then grow it
62 /// by 1 byte. It will then have -1 overcapacity.
63 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
64};
65
66const DeclMetadata = struct {
67 atom: Atom.Index,
68 shdr: u16,
69 /// A list of all exports aliases of this Decl.
70 exports: std.ArrayListUnmanaged(u32) = .{},
71
72 fn getExport(m: DeclMetadata, elf_file: *const Elf, name: []const u8) ?u32 {
73 for (m.exports.items) |exp| {
74 if (mem.eql(u8, name, elf_file.getSymbolName(exp))) return exp;
75 }
76 return null;
77 }
78
79 fn getExportPtr(m: *DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
80 for (m.exports.items) |*exp| {
81 if (mem.eql(u8, name, elf_file.getSymbolName(exp.*))) return exp;
82 }
83 return null;
84 }
85};
86
4187base: File,
4288dwarf: ?Dwarf = null,
4389
......@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,
4894
4995/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
5096/// Same order as in the file.
51sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},
97sections: std.MultiArrayList(Section) = .{},
5298shdr_table_offset: ?u64 = null,
5399
54100/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
55101/// Same order as in the file.
56program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = std.ArrayListUnmanaged(elf.Elf64_Phdr){},
102program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
57103phdr_table_offset: ?u64 = null,
58104/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
59105phdr_load_re_index: ?u16 = null,
......@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,
65111/// The index into the program headers of a PT_LOAD program header with Write flag
66112phdr_load_rw_index: ?u16 = null,
67113
68phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
69
70114entry_addr: ?u64 = null,
71115page_size: u32,
72116
73shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
117shstrtab: StringTable(.strtab) = .{},
74118shstrtab_index: ?u16 = null,
75119
76120symtab_section_index: ?u16 = null,
......@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,
113157
114158error_flags: File.ErrorFlags = File.ErrorFlags{},
115159
116/// Pointer to the last allocated atom
117atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{},
118
119/// A list of text blocks that have surplus capacity. This list can have false
120/// positives, as functions grow and shrink over time, only sometimes being added
121/// or removed from the freelist.
122///
123/// A text block has surplus capacity when its overcapacity value is greater than
124/// padToIdeal(minimum_text_block_size). That is, when it has so
125/// much extra capacity, that we could fit a small new symbol in it, itself with
126/// ideal_capacity or more.
127///
128/// Ideal capacity is defined by size + (size / ideal_factor)
129///
130/// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
131/// overcapacity can be negative. A simple way to have negative overcapacity is to
132/// allocate a fresh text block, which will have ideal capacity, and then grow it
133/// by 1 byte. It will then have -1 overcapacity.
134atom_free_lists: std.AutoHashMapUnmanaged(u16, std.ArrayListUnmanaged(*TextBlock)) = .{},
135
136/// Table of Decls that are currently alive.
137/// We store them here so that we can properly dispose of any allocated
138/// memory within the atom in the incremental linker.
139/// TODO consolidate this.
140decls: std.AutoHashMapUnmanaged(Module.Decl.Index, ?u16) = .{},
160/// Table of tracked Decls.
161decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
141162
142163/// List of atoms that are owned directly by the linker.
143/// Currently these are only atoms that are the result of linking
144/// object files. Atoms which take part in incremental linking are
145/// at present owned by Module.Decl.
146/// TODO consolidate this.
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
164atoms: std.ArrayListUnmanaged(Atom) = .{},
165
166/// Table of atoms indexed by the symbol index.
167atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
149168
150169/// Table of unnamed constants associated with a parent `Decl`.
151170/// We store them here so that we can free the constants whenever the `Decl`
......@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},
173192/// this will be a table indexed by index into the list of Atoms.
174193relocs: RelocTable = .{},
175194
176const Reloc = struct {
177 target: u32,
178 offset: u64,
179 addend: u32,
180 prev_vaddr: u64,
181};
182
183const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc));
184const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(*TextBlock));
195const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
196const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
185197
186198/// When allocating, the ideal_capacity is calculated by
187199/// actual_capacity + (actual_capacity / ideal_factor)
......@@ -190,15 +202,11 @@ const ideal_factor = 3;
190202/// In order for a slice of bytes to be considered eligible to keep metadata pointing at
191203/// it as a possible place to put new symbols, it must have enough room for this many bytes
192204/// (plus extra for reserved capacity).
193const minimum_text_block_size = 64;
194pub const min_text_capacity = padToIdeal(minimum_text_block_size);
205const minimum_atom_size = 64;
206pub const min_text_capacity = padToIdeal(minimum_atom_size);
195207
196208pub const PtrWidth = enum { p32, p64 };
197209
198pub const Export = struct {
199 sym_index: ?u32 = null,
200};
201
202210pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
203211 assert(options.target.ofmt == .elf);
204212
......@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
230238
231239 // There must always be a null section in index 0
232240 try self.sections.append(allocator, .{
233 .sh_name = 0,
234 .sh_type = elf.SHT_NULL,
235 .sh_flags = 0,
236 .sh_addr = 0,
237 .sh_offset = 0,
238 .sh_size = 0,
239 .sh_link = 0,
240 .sh_info = 0,
241 .sh_addralign = 0,
242 .sh_entsize = 0,
241 .shdr = .{
242 .sh_name = 0,
243 .sh_type = elf.SHT_NULL,
244 .sh_flags = 0,
245 .sh_addr = 0,
246 .sh_offset = 0,
247 .sh_size = 0,
248 .sh_link = 0,
249 .sh_info = 0,
250 .sh_addralign = 0,
251 .sh_entsize = 0,
252 },
253 .phdr_index = undefined,
243254 });
244255
245256 try self.populateMissingMetadata();
......@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
286297}
287298
288299pub fn deinit(self: *Elf) void {
300 const gpa = self.base.allocator;
301
289302 if (build_options.have_llvm) {
290 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
291 }
292
293 self.sections.deinit(self.base.allocator);
294 self.program_headers.deinit(self.base.allocator);
295 self.shstrtab.deinit(self.base.allocator);
296 self.local_symbols.deinit(self.base.allocator);
297 self.global_symbols.deinit(self.base.allocator);
298 self.global_symbol_free_list.deinit(self.base.allocator);
299 self.local_symbol_free_list.deinit(self.base.allocator);
300 self.offset_table_free_list.deinit(self.base.allocator);
301 self.offset_table.deinit(self.base.allocator);
302 self.phdr_shdr_table.deinit(self.base.allocator);
303 self.decls.deinit(self.base.allocator);
304
305 self.atoms.deinit(self.base.allocator);
303 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
304 }
305
306 for (self.sections.items(.free_list)) |*free_list| {
307 free_list.deinit(gpa);
308 }
309 self.sections.deinit(gpa);
310
311 self.program_headers.deinit(gpa);
312 self.shstrtab.deinit(gpa);
313 self.local_symbols.deinit(gpa);
314 self.global_symbols.deinit(gpa);
315 self.global_symbol_free_list.deinit(gpa);
316 self.local_symbol_free_list.deinit(gpa);
317 self.offset_table_free_list.deinit(gpa);
318 self.offset_table.deinit(gpa);
319
306320 {
307 var it = self.atom_free_lists.valueIterator();
308 while (it.next()) |free_list| {
309 free_list.deinit(self.base.allocator);
321 var it = self.decls.iterator();
322 while (it.next()) |entry| {
323 entry.value_ptr.exports.deinit(gpa);
310324 }
311 self.atom_free_lists.deinit(self.base.allocator);
325 self.decls.deinit(gpa);
312326 }
313327
314 for (self.managed_atoms.items) |atom| {
315 self.base.allocator.destroy(atom);
316 }
317 self.managed_atoms.deinit(self.base.allocator);
328 self.atoms.deinit(gpa);
329 self.atom_by_index_table.deinit(gpa);
318330
319331 {
320332 var it = self.unnamed_const_atoms.valueIterator();
321333 while (it.next()) |atoms| {
322 atoms.deinit(self.base.allocator);
334 atoms.deinit(gpa);
323335 }
324 self.unnamed_const_atoms.deinit(self.base.allocator);
336 self.unnamed_const_atoms.deinit(gpa);
325337 }
326338
327339 {
328340 var it = self.relocs.valueIterator();
329341 while (it.next()) |relocs| {
330 relocs.deinit(self.base.allocator);
342 relocs.deinit(gpa);
331343 }
332 self.relocs.deinit(self.base.allocator);
344 self.relocs.deinit(gpa);
333345 }
334346
335 self.atom_by_index_table.deinit(self.base.allocator);
336
337 if (self.dwarf) |*dw| {
338 dw.deinit();
339 }
347 // if (self.dwarf) |*dw| {
348 // dw.deinit();
349 // }
340350}
341351
342352pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {
343 const mod = self.base.options.module.?;
344 const decl = mod.declPtr(decl_index);
345
346353 assert(self.llvm_object == null);
347354
348 try decl.link.elf.ensureInitialized(self);
349 const target = decl.link.elf.getSymbolIndex().?;
350
351 const vaddr = self.local_symbols.items[target].st_value;
352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;
353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
354 if (!gop.found_existing) {
355 gop.value_ptr.* = .{};
356 }
357 try gop.value_ptr.append(self.base.allocator, .{
355 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
356 const this_atom = self.getAtom(this_atom_index);
357 const target = this_atom.getSymbolIndex().?;
358 const vaddr = this_atom.getSymbol(self).st_value;
359 const atom_index = self.getAtomIndexForSymbol(reloc_info.parent_atom_index).?;
360 try Atom.addRelocation(self, atom_index, .{
358361 .target = target,
359362 .offset = reloc_info.offset,
360363 .addend = reloc_info.addend,
......@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
375378
376379 if (self.shdr_table_offset) |off| {
377380 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
378 const tight_size = self.sections.items.len * shdr_size;
381 const tight_size = self.sections.slice().len * shdr_size;
379382 const increased_size = padToIdeal(tight_size);
380383 const test_end = off + increased_size;
381384 if (end > off and start < test_end) {
......@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
385388
386389 if (self.phdr_table_offset) |off| {
387390 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);
388 const tight_size = self.sections.items.len * phdr_size;
391 const tight_size = self.sections.slice().len * phdr_size;
389392 const increased_size = padToIdeal(tight_size);
390393 const test_end = off + increased_size;
391394 if (end > off and start < test_end) {
......@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
393396 }
394397 }
395398
396 for (self.sections.items) |section| {
399 for (self.sections.items(.shdr)) |section| {
397400 const increased_size = padToIdeal(section.sh_size);
398401 const test_end = section.sh_offset + increased_size;
399402 if (end > section.sh_offset and start < test_end) {
......@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
420423 if (self.phdr_table_offset) |off| {
421424 if (off > start and off < min_pos) min_pos = off;
422425 }
423 for (self.sections.items) |section| {
426 for (self.sections.items(.shdr)) |section| {
424427 if (section.sh_offset <= start) continue;
425428 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
426429 }
......@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
439442 return start;
440443}
441444
442/// TODO Improve this to use a table.
443fn makeString(self: *Elf, bytes: []const u8) !u32 {
444 try self.shstrtab.ensureUnusedCapacity(self.base.allocator, bytes.len + 1);
445 const result = self.shstrtab.items.len;
446 self.shstrtab.appendSliceAssumeCapacity(bytes);
447 self.shstrtab.appendAssumeCapacity(0);
448 return @intCast(u32, result);
449}
450
451pub fn getString(self: Elf, str_off: u32) []const u8 {
452 assert(str_off < self.shstrtab.items.len);
453 return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0);
454}
455
456fn updateString(self: *Elf, old_str_off: u32, new_name: []const u8) !u32 {
457 const existing_name = self.getString(old_str_off);
458 if (mem.eql(u8, existing_name, new_name)) {
459 return old_str_off;
460 }
461 return self.makeString(new_name);
462}
463
464445pub fn populateMissingMetadata(self: *Elf) !void {
465446 assert(self.llvm_object == null);
466447
448 const gpa = self.base.allocator;
467449 const small_ptr = switch (self.ptr_width) {
468450 .p32 => true,
469451 .p64 => false,
......@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
477459 const off = self.findFreeSpace(file_size, p_align);
478460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
479461 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;
480 try self.program_headers.append(self.base.allocator, .{
462 try self.program_headers.append(gpa, .{
481463 .p_type = elf.PT_LOAD,
482464 .p_offset = off,
483465 .p_filesz = file_size,
......@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
487469 .p_align = p_align,
488470 .p_flags = elf.PF_X | elf.PF_R,
489471 });
490 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{});
491472 self.entry_addr = null;
492473 self.phdr_table_dirty = true;
493474 }
......@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
504485 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
505486 // else in virtual memory.
506487 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
507 try self.program_headers.append(self.base.allocator, .{
488 try self.program_headers.append(gpa, .{
508489 .p_type = elf.PT_LOAD,
509490 .p_offset = off,
510491 .p_filesz = file_size,
......@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
527508 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
528509 // TODO Same as for GOT
529510 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
530 try self.program_headers.append(self.base.allocator, .{
511 try self.program_headers.append(gpa, .{
531512 .p_type = elf.PT_LOAD,
532513 .p_offset = off,
533514 .p_filesz = file_size,
......@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
537518 .p_align = p_align,
538519 .p_flags = elf.PF_R,
539520 });
540 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{});
541521 self.phdr_table_dirty = true;
542522 }
543523
......@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
551531 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
552532 // TODO Same as for GOT
553533 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
554 try self.program_headers.append(self.base.allocator, .{
534 try self.program_headers.append(gpa, .{
555535 .p_type = elf.PT_LOAD,
556536 .p_offset = off,
557537 .p_filesz = file_size,
......@@ -561,278 +541,290 @@ pub fn populateMissingMetadata(self: *Elf) !void {
561541 .p_align = p_align,
562542 .p_flags = elf.PF_R | elf.PF_W,
563543 });
564 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{});
565544 self.phdr_table_dirty = true;
566545 }
567546
568547 if (self.shstrtab_index == null) {
569 self.shstrtab_index = @intCast(u16, self.sections.items.len);
570 assert(self.shstrtab.items.len == 0);
571 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0
572 const off = self.findFreeSpace(self.shstrtab.items.len, 1);
573 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.items.len });
574 try self.sections.append(self.base.allocator, .{
575 .sh_name = try self.makeString(".shstrtab"),
576 .sh_type = elf.SHT_STRTAB,
577 .sh_flags = 0,
578 .sh_addr = 0,
579 .sh_offset = off,
580 .sh_size = self.shstrtab.items.len,
581 .sh_link = 0,
582 .sh_info = 0,
583 .sh_addralign = 1,
584 .sh_entsize = 0,
548 self.shstrtab_index = @intCast(u16, self.sections.slice().len);
549 assert(self.shstrtab.buffer.items.len == 0);
550 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
551 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
552 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
553 try self.sections.append(gpa, .{
554 .shdr = .{
555 .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
556 .sh_type = elf.SHT_STRTAB,
557 .sh_flags = 0,
558 .sh_addr = 0,
559 .sh_offset = off,
560 .sh_size = self.shstrtab.buffer.items.len,
561 .sh_link = 0,
562 .sh_info = 0,
563 .sh_addralign = 1,
564 .sh_entsize = 0,
565 },
566 .phdr_index = undefined,
585567 });
586568 self.shstrtab_dirty = true;
587569 self.shdr_table_dirty = true;
588570 }
589571
590572 if (self.text_section_index == null) {
591 self.text_section_index = @intCast(u16, self.sections.items.len);
573 self.text_section_index = @intCast(u16, self.sections.slice().len);
592574 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
593575
594 try self.sections.append(self.base.allocator, .{
595 .sh_name = try self.makeString(".text"),
596 .sh_type = elf.SHT_PROGBITS,
597 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
598 .sh_addr = phdr.p_vaddr,
599 .sh_offset = phdr.p_offset,
600 .sh_size = phdr.p_filesz,
601 .sh_link = 0,
602 .sh_info = 0,
603 .sh_addralign = 1,
604 .sh_entsize = 0,
576 try self.sections.append(gpa, .{
577 .shdr = .{
578 .sh_name = try self.shstrtab.insert(gpa, ".text"),
579 .sh_type = elf.SHT_PROGBITS,
580 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
581 .sh_addr = phdr.p_vaddr,
582 .sh_offset = phdr.p_offset,
583 .sh_size = phdr.p_filesz,
584 .sh_link = 0,
585 .sh_info = 0,
586 .sh_addralign = 1,
587 .sh_entsize = 0,
588 },
589 .phdr_index = self.phdr_load_re_index.?,
605590 });
606 try self.phdr_shdr_table.putNoClobber(
607 self.base.allocator,
608 self.phdr_load_re_index.?,
609 self.text_section_index.?,
610 );
611591 self.shdr_table_dirty = true;
612592 }
613593
614594 if (self.got_section_index == null) {
615 self.got_section_index = @intCast(u16, self.sections.items.len);
595 self.got_section_index = @intCast(u16, self.sections.slice().len);
616596 const phdr = &self.program_headers.items[self.phdr_got_index.?];
617597
618 try self.sections.append(self.base.allocator, .{
619 .sh_name = try self.makeString(".got"),
620 .sh_type = elf.SHT_PROGBITS,
621 .sh_flags = elf.SHF_ALLOC,
622 .sh_addr = phdr.p_vaddr,
623 .sh_offset = phdr.p_offset,
624 .sh_size = phdr.p_filesz,
625 .sh_link = 0,
626 .sh_info = 0,
627 .sh_addralign = @as(u16, ptr_size),
628 .sh_entsize = 0,
598 try self.sections.append(gpa, .{
599 .shdr = .{
600 .sh_name = try self.shstrtab.insert(gpa, ".got"),
601 .sh_type = elf.SHT_PROGBITS,
602 .sh_flags = elf.SHF_ALLOC,
603 .sh_addr = phdr.p_vaddr,
604 .sh_offset = phdr.p_offset,
605 .sh_size = phdr.p_filesz,
606 .sh_link = 0,
607 .sh_info = 0,
608 .sh_addralign = @as(u16, ptr_size),
609 .sh_entsize = 0,
610 },
611 .phdr_index = self.phdr_got_index.?,
629612 });
630 try self.phdr_shdr_table.putNoClobber(
631 self.base.allocator,
632 self.phdr_got_index.?,
633 self.got_section_index.?,
634 );
635613 self.shdr_table_dirty = true;
636614 }
637615
638616 if (self.rodata_section_index == null) {
639 self.rodata_section_index = @intCast(u16, self.sections.items.len);
617 self.rodata_section_index = @intCast(u16, self.sections.slice().len);
640618 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
641619
642 try self.sections.append(self.base.allocator, .{
643 .sh_name = try self.makeString(".rodata"),
644 .sh_type = elf.SHT_PROGBITS,
645 .sh_flags = elf.SHF_ALLOC,
646 .sh_addr = phdr.p_vaddr,
647 .sh_offset = phdr.p_offset,
648 .sh_size = phdr.p_filesz,
649 .sh_link = 0,
650 .sh_info = 0,
651 .sh_addralign = 1,
652 .sh_entsize = 0,
620 try self.sections.append(gpa, .{
621 .shdr = .{
622 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
623 .sh_type = elf.SHT_PROGBITS,
624 .sh_flags = elf.SHF_ALLOC,
625 .sh_addr = phdr.p_vaddr,
626 .sh_offset = phdr.p_offset,
627 .sh_size = phdr.p_filesz,
628 .sh_link = 0,
629 .sh_info = 0,
630 .sh_addralign = 1,
631 .sh_entsize = 0,
632 },
633 .phdr_index = self.phdr_load_ro_index.?,
653634 });
654 try self.phdr_shdr_table.putNoClobber(
655 self.base.allocator,
656 self.phdr_load_ro_index.?,
657 self.rodata_section_index.?,
658 );
659635 self.shdr_table_dirty = true;
660636 }
661637
662638 if (self.data_section_index == null) {
663 self.data_section_index = @intCast(u16, self.sections.items.len);
639 self.data_section_index = @intCast(u16, self.sections.slice().len);
664640 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];
665641
666 try self.sections.append(self.base.allocator, .{
667 .sh_name = try self.makeString(".data"),
668 .sh_type = elf.SHT_PROGBITS,
669 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
670 .sh_addr = phdr.p_vaddr,
671 .sh_offset = phdr.p_offset,
672 .sh_size = phdr.p_filesz,
673 .sh_link = 0,
674 .sh_info = 0,
675 .sh_addralign = @as(u16, ptr_size),
676 .sh_entsize = 0,
642 try self.sections.append(gpa, .{
643 .shdr = .{
644 .sh_name = try self.shstrtab.insert(gpa, ".data"),
645 .sh_type = elf.SHT_PROGBITS,
646 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
647 .sh_addr = phdr.p_vaddr,
648 .sh_offset = phdr.p_offset,
649 .sh_size = phdr.p_filesz,
650 .sh_link = 0,
651 .sh_info = 0,
652 .sh_addralign = @as(u16, ptr_size),
653 .sh_entsize = 0,
654 },
655 .phdr_index = self.phdr_load_rw_index.?,
677656 });
678 try self.phdr_shdr_table.putNoClobber(
679 self.base.allocator,
680 self.phdr_load_rw_index.?,
681 self.data_section_index.?,
682 );
683657 self.shdr_table_dirty = true;
684658 }
685659
686660 if (self.symtab_section_index == null) {
687 self.symtab_section_index = @intCast(u16, self.sections.items.len);
661 self.symtab_section_index = @intCast(u16, self.sections.slice().len);
688662 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
689663 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
690664 const file_size = self.base.options.symbol_count_hint * each_size;
691665 const off = self.findFreeSpace(file_size, min_align);
692666 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
693667
694 try self.sections.append(self.base.allocator, .{
695 .sh_name = try self.makeString(".symtab"),
696 .sh_type = elf.SHT_SYMTAB,
697 .sh_flags = 0,
698 .sh_addr = 0,
699 .sh_offset = off,
700 .sh_size = file_size,
701 // The section header index of the associated string table.
702 .sh_link = self.shstrtab_index.?,
703 .sh_info = @intCast(u32, self.local_symbols.items.len),
704 .sh_addralign = min_align,
705 .sh_entsize = each_size,
668 try self.sections.append(gpa, .{
669 .shdr = .{
670 .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
671 .sh_type = elf.SHT_SYMTAB,
672 .sh_flags = 0,
673 .sh_addr = 0,
674 .sh_offset = off,
675 .sh_size = file_size,
676 // The section header index of the associated string table.
677 .sh_link = self.shstrtab_index.?,
678 .sh_info = @intCast(u32, self.local_symbols.items.len),
679 .sh_addralign = min_align,
680 .sh_entsize = each_size,
681 },
682 .phdr_index = undefined,
706683 });
707684 self.shdr_table_dirty = true;
708685 try self.writeSymbol(0);
709686 }
710687
711 if (self.dwarf) |*dw| {
712 if (self.debug_str_section_index == null) {
713 self.debug_str_section_index = @intCast(u16, self.sections.items.len);
714 assert(dw.strtab.items.len == 0);
715 try dw.strtab.append(self.base.allocator, 0);
716 try self.sections.append(self.base.allocator, .{
717 .sh_name = try self.makeString(".debug_str"),
718 .sh_type = elf.SHT_PROGBITS,
719 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
720 .sh_addr = 0,
721 .sh_offset = 0,
722 .sh_size = 0,
723 .sh_link = 0,
724 .sh_info = 0,
725 .sh_addralign = 1,
726 .sh_entsize = 1,
727 });
728 self.debug_strtab_dirty = true;
729 self.shdr_table_dirty = true;
730 }
731
732 if (self.debug_info_section_index == null) {
733 self.debug_info_section_index = @intCast(u16, self.sections.items.len);
734
735 const file_size_hint = 200;
736 const p_align = 1;
737 const off = self.findFreeSpace(file_size_hint, p_align);
738 log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
739 off,
740 off + file_size_hint,
741 });
742 try self.sections.append(self.base.allocator, .{
743 .sh_name = try self.makeString(".debug_info"),
744 .sh_type = elf.SHT_PROGBITS,
745 .sh_flags = 0,
746 .sh_addr = 0,
747 .sh_offset = off,
748 .sh_size = file_size_hint,
749 .sh_link = 0,
750 .sh_info = 0,
751 .sh_addralign = p_align,
752 .sh_entsize = 0,
753 });
754 self.shdr_table_dirty = true;
755 self.debug_info_header_dirty = true;
756 }
757
758 if (self.debug_abbrev_section_index == null) {
759 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);
760
761 const file_size_hint = 128;
762 const p_align = 1;
763 const off = self.findFreeSpace(file_size_hint, p_align);
764 log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
765 off,
766 off + file_size_hint,
767 });
768 try self.sections.append(self.base.allocator, .{
769 .sh_name = try self.makeString(".debug_abbrev"),
770 .sh_type = elf.SHT_PROGBITS,
771 .sh_flags = 0,
772 .sh_addr = 0,
773 .sh_offset = off,
774 .sh_size = file_size_hint,
775 .sh_link = 0,
776 .sh_info = 0,
777 .sh_addralign = p_align,
778 .sh_entsize = 0,
779 });
780 self.shdr_table_dirty = true;
781 self.debug_abbrev_section_dirty = true;
782 }
783
784 if (self.debug_aranges_section_index == null) {
785 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);
786
787 const file_size_hint = 160;
788 const p_align = 16;
789 const off = self.findFreeSpace(file_size_hint, p_align);
790 log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
791 off,
792 off + file_size_hint,
793 });
794 try self.sections.append(self.base.allocator, .{
795 .sh_name = try self.makeString(".debug_aranges"),
796 .sh_type = elf.SHT_PROGBITS,
797 .sh_flags = 0,
798 .sh_addr = 0,
799 .sh_offset = off,
800 .sh_size = file_size_hint,
801 .sh_link = 0,
802 .sh_info = 0,
803 .sh_addralign = p_align,
804 .sh_entsize = 0,
805 });
806 self.shdr_table_dirty = true;
807 self.debug_aranges_section_dirty = true;
808 }
809
810 if (self.debug_line_section_index == null) {
811 self.debug_line_section_index = @intCast(u16, self.sections.items.len);
812
813 const file_size_hint = 250;
814 const p_align = 1;
815 const off = self.findFreeSpace(file_size_hint, p_align);
816 log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
817 off,
818 off + file_size_hint,
819 });
820 try self.sections.append(self.base.allocator, .{
821 .sh_name = try self.makeString(".debug_line"),
822 .sh_type = elf.SHT_PROGBITS,
823 .sh_flags = 0,
824 .sh_addr = 0,
825 .sh_offset = off,
826 .sh_size = file_size_hint,
827 .sh_link = 0,
828 .sh_info = 0,
829 .sh_addralign = p_align,
830 .sh_entsize = 0,
831 });
832 self.shdr_table_dirty = true;
833 self.debug_line_header_dirty = true;
834 }
835 }
688 // if (self.dwarf) |*dw| {
689 // if (self.debug_str_section_index == null) {
690 // self.debug_str_section_index = @intCast(u16, self.sections.slice().len);
691 // assert(dw.strtab.items.len == 0);
692 // try dw.strtab.append(gpa, 0);
693 // try self.sections.append(gpa, .{
694 // .shdr = .{
695 // .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
696 // .sh_type = elf.SHT_PROGBITS,
697 // .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
698 // .sh_addr = 0,
699 // .sh_offset = 0,
700 // .sh_size = 0,
701 // .sh_link = 0,
702 // .sh_info = 0,
703 // .sh_addralign = 1,
704 // .sh_entsize = 1,
705 // },
706 // .phdr_index = undefined,
707 // });
708 // self.debug_strtab_dirty = true;
709 // self.shdr_table_dirty = true;
710 // }
711
712 // if (self.debug_info_section_index == null) {
713 // self.debug_info_section_index = @intCast(u16, self.sections.slice().len);
714
715 // const file_size_hint = 200;
716 // const p_align = 1;
717 // const off = self.findFreeSpace(file_size_hint, p_align);
718 // log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
719 // off,
720 // off + file_size_hint,
721 // });
722 // try self.sections.append(gpa, .{
723 // .shdr = .{
724 // .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
725 // .sh_type = elf.SHT_PROGBITS,
726 // .sh_flags = 0,
727 // .sh_addr = 0,
728 // .sh_offset = off,
729 // .sh_size = file_size_hint,
730 // .sh_link = 0,
731 // .sh_info = 0,
732 // .sh_addralign = p_align,
733 // .sh_entsize = 0,
734 // },
735 // .phdr_index = undefined,
736 // });
737 // self.shdr_table_dirty = true;
738 // self.debug_info_header_dirty = true;
739 // }
740
741 // if (self.debug_abbrev_section_index == null) {
742 // self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().len);
743
744 // const file_size_hint = 128;
745 // const p_align = 1;
746 // const off = self.findFreeSpace(file_size_hint, p_align);
747 // log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
748 // off,
749 // off + file_size_hint,
750 // });
751 // try self.sections.append(gpa, .{
752 // .shdr = .{
753 // .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
754 // .sh_type = elf.SHT_PROGBITS,
755 // .sh_flags = 0,
756 // .sh_addr = 0,
757 // .sh_offset = off,
758 // .sh_size = file_size_hint,
759 // .sh_link = 0,
760 // .sh_info = 0,
761 // .sh_addralign = p_align,
762 // .sh_entsize = 0,
763 // },
764 // .phdr_index = undefined,
765 // });
766 // self.shdr_table_dirty = true;
767 // self.debug_abbrev_section_dirty = true;
768 // }
769
770 // if (self.debug_aranges_section_index == null) {
771 // self.debug_aranges_section_index = @intCast(u16, self.sections.slice().len);
772
773 // const file_size_hint = 160;
774 // const p_align = 16;
775 // const off = self.findFreeSpace(file_size_hint, p_align);
776 // log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
777 // off,
778 // off + file_size_hint,
779 // });
780 // try self.sections.append(gpa, .{
781 // .shdr = .{
782 // .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
783 // .sh_type = elf.SHT_PROGBITS,
784 // .sh_flags = 0,
785 // .sh_addr = 0,
786 // .sh_offset = off,
787 // .sh_size = file_size_hint,
788 // .sh_link = 0,
789 // .sh_info = 0,
790 // .sh_addralign = p_align,
791 // .sh_entsize = 0,
792 // },
793 // .phdr_index = undefined,
794 // });
795 // self.shdr_table_dirty = true;
796 // self.debug_aranges_section_dirty = true;
797 // }
798
799 // if (self.debug_line_section_index == null) {
800 // self.debug_line_section_index = @intCast(u16, self.sections.slice().len);
801
802 // const file_size_hint = 250;
803 // const p_align = 1;
804 // const off = self.findFreeSpace(file_size_hint, p_align);
805 // log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
806 // off,
807 // off + file_size_hint,
808 // });
809 // try self.sections.append(gpa, .{
810 // .shdr = .{
811 // .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
812 // .sh_type = elf.SHT_PROGBITS,
813 // .sh_flags = 0,
814 // .sh_addr = 0,
815 // .sh_offset = off,
816 // .sh_size = file_size_hint,
817 // .sh_link = 0,
818 // .sh_info = 0,
819 // .sh_addralign = p_align,
820 // .sh_entsize = 0,
821 // },
822 // .phdr_index = undefined,
823 // });
824 // self.shdr_table_dirty = true;
825 // self.debug_line_header_dirty = true;
826 // }
827 // }
836828
837829 const shsize: u64 = switch (self.ptr_width) {
838830 .p32 => @sizeOf(elf.Elf32_Shdr),
......@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
843835 .p64 => @alignOf(elf.Elf64_Shdr),
844836 };
845837 if (self.shdr_table_offset == null) {
846 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
838 self.shdr_table_offset = self.findFreeSpace(self.sections.slice().len * shsize, shalign);
847839 self.shdr_table_dirty = true;
848840 }
849841
......@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
874866 // offset + it's filesize.
875867 var max_file_offset: u64 = 0;
876868
877 for (self.sections.items) |shdr| {
869 for (self.sections.items(.shdr)) |shdr| {
878870 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {
879871 max_file_offset = shdr.sh_offset + shdr.sh_size;
880872 }
......@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {
884876 }
885877}
886878
887fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u64) !void {
879fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
888880 // TODO Also detect virtual address collisions.
889 const shdr = &self.sections.items[shdr_index];
881 const shdr = &self.sections.items(.shdr)[shdr_index];
882 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
890883 const phdr = &self.program_headers.items[phdr_index];
884 const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
891885
892886 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
893887 // Must move the entire section.
894888 const new_offset = self.findFreeSpace(needed_size, self.page_size);
895 const existing_size = if (self.atoms.get(phdr_index)) |last| blk: {
889 const existing_size = if (maybe_last_atom_index) |last_atom_index| blk: {
890 const last = self.getAtom(last_atom_index);
896891 const sym = last.getSymbol(self);
897892 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
898893 } else if (shdr_index == self.got_section_index.?) blk: {
......@@ -900,8 +895,8 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u
900895 } else 0;
901896 shdr.sh_size = 0;
902897
903 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
904 self.getString(shdr.sh_name),
898 log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
899 self.shstrtab.get(shdr.sh_name),
905900 new_offset,
906901 new_offset + existing_size,
907902 });
......@@ -927,7 +922,7 @@ pub fn growNonAllocSection(
927922 min_alignment: u32,
928923 requires_file_copy: bool,
929924) !void {
930 const shdr = &self.sections.items[shdr_index];
925 const shdr = &self.sections.items(.shdr)[shdr_index];
931926
932927 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
933928 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
......@@ -940,7 +935,7 @@ pub fn growNonAllocSection(
940935 shdr.sh_size = 0;
941936 // Move all the symbols to a new file location.
942937 const new_offset = self.findFreeSpace(needed_size, min_alignment);
943 log.debug("moving '{s}' from 0x{x} to 0x{x}", .{ self.getString(shdr.sh_name), shdr.sh_offset, new_offset });
938 log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{ self.shstrtab.get(shdr.sh_name), shdr.sh_offset, new_offset });
944939
945940 if (requires_file_copy) {
946941 const amt = try self.base.file.?.copyRangeAll(
......@@ -961,25 +956,26 @@ pub fn growNonAllocSection(
961956}
962957
963958pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
959 _ = shdr_index;
964960 self.shdr_table_dirty = true; // TODO look into only writing one section
965961
966962 if (phdr_index) |_| {
967963 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
968964 }
969965
970 if (self.dwarf) |_| {
971 if (self.debug_info_section_index.? == shdr_index) {
972 self.debug_info_header_dirty = true;
973 } else if (self.debug_line_section_index.? == shdr_index) {
974 self.debug_line_header_dirty = true;
975 } else if (self.debug_abbrev_section_index.? == shdr_index) {
976 self.debug_abbrev_section_dirty = true;
977 } else if (self.debug_str_section_index.? == shdr_index) {
978 self.debug_strtab_dirty = true;
979 } else if (self.debug_aranges_section_index.? == shdr_index) {
980 self.debug_aranges_section_dirty = true;
981 }
982 }
966 // if (self.dwarf) |_| {
967 // if (self.debug_info_section_index.? == shdr_index) {
968 // self.debug_info_header_dirty = true;
969 // } else if (self.debug_line_section_index.? == shdr_index) {
970 // self.debug_line_header_dirty = true;
971 // } else if (self.debug_abbrev_section_index.? == shdr_index) {
972 // self.debug_abbrev_section_dirty = true;
973 // } else if (self.debug_str_section_index.? == shdr_index) {
974 // self.debug_strtab_dirty = true;
975 // } else if (self.debug_aranges_section_index.? == shdr_index) {
976 // self.debug_aranges_section_dirty = true;
977 // }
978 // }
983979}
984980
985981pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
......@@ -1011,6 +1007,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10111007 }
10121008 }
10131009
1010 const gpa = self.base.allocator;
10141011 var sub_prog_node = prog_node.start("ELF Flush", 0);
10151012 sub_prog_node.activate();
10161013 defer sub_prog_node.end();
......@@ -1018,23 +1015,25 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10181015 // TODO This linker code currently assumes there is only 1 compilation unit and it
10191016 // corresponds to the Zig source code.
10201017 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
1018 _ = module;
10211019
10221020 const target_endian = self.base.options.target.cpu.arch.endian();
10231021 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10241022
1025 if (self.dwarf) |*dw| {
1026 try dw.flushModule(module);
1027 }
1023 // if (self.dwarf) |*dw| {
1024 // try dw.flushModule(module);
1025 // }
10281026
10291027 {
10301028 var it = self.relocs.iterator();
10311029 while (it.next()) |entry| {
1032 const atom = entry.key_ptr.*;
1030 const atom_index = entry.key_ptr.*;
10331031 const relocs = entry.value_ptr.*;
1032 const atom = self.getAtom(atom_index);
10341033 const source_sym = atom.getSymbol(self);
1035 const source_shdr = self.sections.items[source_sym.st_shndx];
1034 const source_shdr = self.sections.items(.shdr)[source_sym.st_shndx];
10361035
1037 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});
1036 log.debug("relocating '{?s}'", .{self.shstrtab.get(source_sym.st_name)});
10381037
10391038 for (relocs.items) |*reloc| {
10401039 const target_sym = self.local_symbols.items[reloc.target];
......@@ -1045,10 +1044,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10451044 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
10461045 const file_offset = source_shdr.sh_offset + section_offset;
10471046
1048 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
1047 log.debug(" ({x}: [() => 0x{x}] ({?s}))", .{
10491048 reloc.offset,
10501049 target_vaddr,
1051 self.getString(target_sym.st_name),
1050 self.shstrtab.get(target_sym.st_name),
10521051 });
10531052
10541053 switch (self.ptr_width) {
......@@ -1069,43 +1068,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10691068 self.logSymtab();
10701069 }
10711070
1072 if (self.dwarf) |*dw| {
1073 if (self.debug_abbrev_section_dirty) {
1074 try dw.writeDbgAbbrev();
1075 if (!self.shdr_table_dirty) {
1076 // Then it won't get written with the others and we need to do it.
1077 try self.writeSectHeader(self.debug_abbrev_section_index.?);
1078 }
1079 self.debug_abbrev_section_dirty = false;
1080 }
1081
1082 if (self.debug_info_header_dirty) {
1083 // Currently only one compilation unit is supported, so the address range is simply
1084 // identical to the main program header virtual address and memory size.
1085 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1086 const low_pc = text_phdr.p_vaddr;
1087 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1088 try dw.writeDbgInfoHeader(module, low_pc, high_pc);
1089 self.debug_info_header_dirty = false;
1090 }
1091
1092 if (self.debug_aranges_section_dirty) {
1093 // Currently only one compilation unit is supported, so the address range is simply
1094 // identical to the main program header virtual address and memory size.
1095 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1096 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1097 if (!self.shdr_table_dirty) {
1098 // Then it won't get written with the others and we need to do it.
1099 try self.writeSectHeader(self.debug_aranges_section_index.?);
1100 }
1101 self.debug_aranges_section_dirty = false;
1102 }
1103
1104 if (self.debug_line_header_dirty) {
1105 try dw.writeDbgLineHeader();
1106 self.debug_line_header_dirty = false;
1107 }
1108 }
1071 // if (self.dwarf) |*dw| {
1072 // if (self.debug_abbrev_section_dirty) {
1073 // try dw.writeDbgAbbrev();
1074 // if (!self.shdr_table_dirty) {
1075 // // Then it won't get written with the others and we need to do it.
1076 // try self.writeSectHeader(self.debug_abbrev_section_index.?);
1077 // }
1078 // self.debug_abbrev_section_dirty = false;
1079 // }
1080
1081 // if (self.debug_info_header_dirty) {
1082 // // Currently only one compilation unit is supported, so the address range is simply
1083 // // identical to the main program header virtual address and memory size.
1084 // const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1085 // const low_pc = text_phdr.p_vaddr;
1086 // const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1087 // try dw.writeDbgInfoHeader(module, low_pc, high_pc);
1088 // self.debug_info_header_dirty = false;
1089 // }
1090
1091 // if (self.debug_aranges_section_dirty) {
1092 // // Currently only one compilation unit is supported, so the address range is simply
1093 // // identical to the main program header virtual address and memory size.
1094 // const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1095 // try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1096 // if (!self.shdr_table_dirty) {
1097 // // Then it won't get written with the others and we need to do it.
1098 // try self.writeSectHeader(self.debug_aranges_section_index.?);
1099 // }
1100 // self.debug_aranges_section_dirty = false;
1101 // }
1102
1103 // if (self.debug_line_header_dirty) {
1104 // try dw.writeDbgLineHeader();
1105 // self.debug_line_header_dirty = false;
1106 // }
1107 // }
11091108
11101109 if (self.phdr_table_dirty) {
11111110 const phsize: u64 = switch (self.ptr_width) {
......@@ -1126,8 +1125,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11261125
11271126 switch (self.ptr_width) {
11281127 .p32 => {
1129 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1130 defer self.base.allocator.free(buf);
1128 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1129 defer gpa.free(buf);
11311130
11321131 for (buf) |*phdr, i| {
11331132 phdr.* = progHeaderTo32(self.program_headers.items[i]);
......@@ -1138,8 +1137,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11381137 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
11391138 },
11401139 .p64 => {
1141 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1142 defer self.base.allocator.free(buf);
1140 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1141 defer gpa.free(buf);
11431142
11441143 for (buf) |*phdr, i| {
11451144 phdr.* = self.program_headers.items[i];
......@@ -1155,23 +1154,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11551154
11561155 {
11571156 const shdr_index = self.shstrtab_index.?;
1158 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {
1159 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);
1160 const shstrtab_sect = self.sections.items[shdr_index];
1161 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
1157 if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1158 try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
1159 const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
1160 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
11621161 self.shstrtab_dirty = false;
11631162 }
11641163 }
11651164
1166 if (self.dwarf) |dwarf| {
1167 const shdr_index = self.debug_str_section_index.?;
1168 if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items[shdr_index].sh_size) {
1169 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1170 const debug_strtab_sect = self.sections.items[shdr_index];
1171 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);
1172 self.debug_strtab_dirty = false;
1173 }
1174 }
1165 // if (self.dwarf) |dwarf| {
1166 // const shdr_index = self.debug_str_section_index.?;
1167 // if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1168 // try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1169 // const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
1170 // try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);
1171 // self.debug_strtab_dirty = false;
1172 // }
1173 // }
11751174
11761175 if (self.shdr_table_dirty) {
11771176 const shsize: u64 = switch (self.ptr_width) {
......@@ -1183,7 +1182,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11831182 .p64 => @alignOf(elf.Elf64_Shdr),
11841183 };
11851184 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
1186 const needed_size = self.sections.items.len * shsize;
1185 const needed_size = self.sections.slice().len * shsize;
11871186
11881187 if (needed_size > allocated_size) {
11891188 self.shdr_table_offset = null; // free the space
......@@ -1192,12 +1191,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11921191
11931192 switch (self.ptr_width) {
11941193 .p32 => {
1195 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
1196 defer self.base.allocator.free(buf);
1194 const slice = self.sections.slice();
1195 const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
1196 defer gpa.free(buf);
11971197
11981198 for (buf) |*shdr, i| {
1199 shdr.* = sectHeaderTo32(self.sections.items[i]);
1200 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });
1199 shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
1200 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
12011201 if (foreign_endian) {
12021202 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
12031203 }
......@@ -1205,12 +1205,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12051205 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
12061206 },
12071207 .p64 => {
1208 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
1209 defer self.base.allocator.free(buf);
1208 const slice = self.sections.slice();
1209 const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
1210 defer gpa.free(buf);
12101211
12111212 for (buf) |*shdr, i| {
1212 shdr.* = self.sections.items[i];
1213 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });
1213 shdr.* = slice.items(.shdr)[i];
1214 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
12141215 if (foreign_endian) {
12151216 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
12161217 }
......@@ -2021,7 +2022,7 @@ fn writeElfHeader(self: *Elf) !void {
20212022 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
20222023 index += 2;
20232024
2024 const e_shnum = @intCast(u16, self.sections.items.len);
2025 const e_shnum = @intCast(u16, self.sections.slice().len);
20252026 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
20262027 index += 2;
20272028
......@@ -2033,124 +2034,150 @@ fn writeElfHeader(self: *Elf) !void {
20332034 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
20342035}
20352036
2036fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {
2037 const local_sym = text_block.getSymbol(self);
2038 const name_str_index = local_sym.st_name;
2039 const name = self.getString(name_str_index);
2040 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });
2037fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
2038 const atom = self.getAtom(atom_index);
2039 log.debug("freeAtom {d} ({s})", .{ atom_index, atom.getName(self) });
20412040
2042 self.freeRelocationsForTextBlock(text_block);
2041 Atom.freeRelocations(self, atom_index);
20432042
2044 const free_list = self.atom_free_lists.getPtr(phdr_index).?;
2043 const gpa = self.base.allocator;
2044 const shndx = atom.getSymbol(self).st_shndx;
2045 const free_list = &self.sections.items(.free_list)[shndx];
20452046 var already_have_free_list_node = false;
20462047 {
20472048 var i: usize = 0;
20482049 // TODO turn free_list into a hash map
20492050 while (i < free_list.items.len) {
2050 if (free_list.items[i] == text_block) {
2051 if (free_list.items[i] == atom_index) {
20512052 _ = free_list.swapRemove(i);
20522053 continue;
20532054 }
2054 if (free_list.items[i] == text_block.prev) {
2055 if (free_list.items[i] == atom.prev_index) {
20552056 already_have_free_list_node = true;
20562057 }
20572058 i += 1;
20582059 }
20592060 }
20602061
2061 if (self.atoms.getPtr(phdr_index)) |last_block| {
2062 if (last_block.* == text_block) {
2063 if (text_block.prev) |prev| {
2062 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx];
2063 if (maybe_last_atom_index.*) |last_atom_index| {
2064 if (last_atom_index == atom_index) {
2065 if (atom.prev_index) |prev_index| {
20642066 // TODO shrink the section size here
2065 last_block.* = prev;
2067 maybe_last_atom_index.* = prev_index;
20662068 } else {
2067 _ = self.atoms.fetchRemove(phdr_index);
2069 maybe_last_atom_index.* = null;
20682070 }
20692071 }
20702072 }
20712073
2072 if (text_block.prev) |prev| {
2073 prev.next = text_block.next;
2074 if (atom.prev_index) |prev_index| {
2075 const prev = self.getAtomPtr(prev_index);
2076 prev.next_index = atom.next_index;
20742077
2075 if (!already_have_free_list_node and prev.freeListEligible(self)) {
2078 if (!already_have_free_list_node and prev.*.freeListEligible(self)) {
20762079 // The free list is heuristics, it doesn't have to be perfect, so we can
20772080 // ignore the OOM here.
2078 free_list.append(self.base.allocator, prev) catch {};
2081 free_list.append(gpa, prev_index) catch {};
20792082 }
20802083 } else {
2081 text_block.prev = null;
2084 self.getAtomPtr(atom_index).prev_index = null;
20822085 }
20832086
2084 if (text_block.next) |next| {
2085 next.prev = text_block.prev;
2087 if (atom.next_index) |next_index| {
2088 self.getAtomPtr(next_index).prev_index = atom.prev_index;
20862089 } else {
2087 text_block.next = null;
2090 self.getAtomPtr(atom_index).next_index = null;
20882091 }
20892092
20902093 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2091 const local_sym_index = text_block.getSymbolIndex().?;
2092 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};
2094 const local_sym_index = atom.getSymbolIndex().?;
2095
2096 self.local_symbol_free_list.append(gpa, local_sym_index) catch {};
20932097 self.local_symbols.items[local_sym_index].st_info = 0;
2098 self.local_symbols.items[local_sym_index].st_shndx = 0;
20942099 _ = self.atom_by_index_table.remove(local_sym_index);
2095 text_block.local_sym_index = 0;
2100 self.getAtomPtr(atom_index).local_sym_index = 0;
20962101
2097 self.offset_table_free_list.append(self.base.allocator, text_block.offset_table_index) catch {};
2102 self.offset_table_free_list.append(self.base.allocator, atom.offset_table_index) catch {};
20982103
2099 if (self.dwarf) |*dw| {
2100 dw.freeAtom(&text_block.dbg_info_atom);
2101 }
2104 // if (self.dwarf) |*dw| {
2105 // dw.freeAtom(&atom.dbg_info_atom);
2106 // }
21022107}
21032108
2104fn shrinkTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, phdr_index: u16) void {
2109fn shrinkAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64) void {
21052110 _ = self;
2106 _ = text_block;
2111 _ = atom_index;
21072112 _ = new_block_size;
2108 _ = phdr_index;
21092113}
21102114
2111fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2112 const sym = text_block.getSymbol(self);
2115fn growAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2116 const atom = self.getAtom(atom_index);
2117 const sym = atom.getSymbol(self);
21132118 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;
2114 const need_realloc = !align_ok or new_block_size > text_block.capacity(self);
2119 const need_realloc = !align_ok or new_block_size > atom.capacity(self);
21152120 if (!need_realloc) return sym.st_value;
2116 return self.allocateTextBlock(text_block, new_block_size, alignment, phdr_index);
2121 return self.allocateAtom(atom_index, new_block_size, alignment);
2122}
2123
2124pub fn createAtom(self: *Elf) !Atom.Index {
2125 const gpa = self.base.allocator;
2126 const atom_index = @intCast(Atom.Index, self.atoms.items.len);
2127 const atom = try self.atoms.addOne(gpa);
2128 const local_sym_index = try self.allocateLocalSymbol();
2129 const offset_table_index = try self.allocateGotOffset();
2130 try self.atom_by_index_table.putNoClobber(gpa, local_sym_index, atom_index);
2131 atom.* = .{
2132 .local_sym_index = local_sym_index,
2133 .offset_table_index = offset_table_index,
2134 .prev_index = null,
2135 .next_index = null,
2136 .dbg_info_atom = undefined,
2137 };
2138 log.debug("creating ATOM(%{d}) at index {d}", .{ local_sym_index, atom_index });
2139 return atom_index;
21172140}
21182141
2119fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {
2120 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2142fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2143 const atom = self.getAtom(atom_index);
2144 const sym = atom.getSymbol(self);
2145 const phdr_index = self.sections.items(.phdr_index)[sym.st_shndx];
21212146 const phdr = &self.program_headers.items[phdr_index];
2122 const shdr = &self.sections.items[shdr_index];
2123 const new_block_ideal_capacity = padToIdeal(new_block_size);
2147 const shdr = &self.sections.items(.shdr)[sym.st_shndx];
2148 const free_list = &self.sections.items(.free_list)[sym.st_shndx];
2149 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[sym.st_shndx];
2150 const new_atom_ideal_capacity = padToIdeal(new_block_size);
21242151
2125 // We use these to indicate our intention to update metadata, placing the new block,
2152 // We use these to indicate our intention to update metadata, placing the new atom,
21262153 // and possibly removing a free list node.
21272154 // It would be simpler to do it inside the for loop below, but that would cause a
21282155 // problem if an error was returned later in the function. So this action
21292156 // is actually carried out at the end of the function, when errors are no longer possible.
2130 var block_placement: ?*TextBlock = null;
2157 var atom_placement: ?Atom.Index = null;
21312158 var free_list_removal: ?usize = null;
2132 var free_list = self.atom_free_lists.get(phdr_index).?;
21332159
21342160 // First we look for an appropriately sized free list node.
21352161 // The list is unordered. We'll just take the first thing that works.
21362162 const vaddr = blk: {
21372163 var i: usize = 0;
21382164 while (i < free_list.items.len) {
2139 const big_block = free_list.items[i];
2140 // We now have a pointer to a live text block that has too much capacity.
2141 // Is it enough that we could fit this new text block?
2142 const sym = big_block.getSymbol(self);
2143 const capacity = big_block.capacity(self);
2165 const big_atom_index = free_list.items[i];
2166 const big_atom = self.getAtom(big_atom_index);
2167 // We now have a pointer to a live atom that has too much capacity.
2168 // Is it enough that we could fit this new atom?
2169 const big_atom_sym = big_atom.getSymbol(self);
2170 const capacity = big_atom.capacity(self);
21442171 const ideal_capacity = padToIdeal(capacity);
2145 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;
2146 const capacity_end_vaddr = sym.st_value + capacity;
2147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;
2172 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom_sym.st_value, ideal_capacity) catch ideal_capacity;
2173 const capacity_end_vaddr = big_atom_sym.st_value + capacity;
2174 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
21482175 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
21492176 if (new_start_vaddr < ideal_capacity_end_vaddr) {
21502177 // Additional bookkeeping here to notice if this free list node
21512178 // should be deleted because the block that it points to has grown to take up
21522179 // more of the extra capacity.
2153 if (!big_block.freeListEligible(self)) {
2180 if (!big_atom.freeListEligible(self)) {
21542181 _ = free_list.swapRemove(i);
21552182 } else {
21562183 i += 1;
......@@ -2164,60 +2191,69 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
21642191 const keep_free_list_node = remaining_capacity >= min_text_capacity;
21652192
21662193 // Set up the metadata to be updated, after errors are no longer possible.
2167 block_placement = big_block;
2194 atom_placement = big_atom_index;
21682195 if (!keep_free_list_node) {
21692196 free_list_removal = i;
21702197 }
21712198 break :blk new_start_vaddr;
2172 } else if (self.atoms.get(phdr_index)) |last| {
2173 const sym = last.getSymbol(self);
2174 const ideal_capacity = padToIdeal(sym.st_size);
2175 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;
2199 } else if (maybe_last_atom_index.*) |last_index| {
2200 const last = self.getAtom(last_index);
2201 const last_sym = last.getSymbol(self);
2202 const ideal_capacity = padToIdeal(last_sym.st_size);
2203 const ideal_capacity_end_vaddr = last_sym.st_value + ideal_capacity;
21762204 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
21772205 // Set up the metadata to be updated, after errors are no longer possible.
2178 block_placement = last;
2206 atom_placement = last_index;
21792207 break :blk new_start_vaddr;
21802208 } else {
21812209 break :blk phdr.p_vaddr;
21822210 }
21832211 };
21842212
2185 const expand_text_section = block_placement == null or block_placement.?.next == null;
2186 if (expand_text_section) {
2213 const expand_section = if (atom_placement) |placement_index|
2214 self.getAtom(placement_index).next_index == null
2215 else
2216 true;
2217 if (expand_section) {
21872218 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2188 try self.growAllocSection(shdr_index, phdr_index, needed_size);
2189 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);
2190
2191 if (self.dwarf) |_| {
2192 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
2193 // range of the compilation unit. When we expand the text section, this range changes,
2194 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
2195 self.debug_info_header_dirty = true;
2196 // This becomes dirty for the same reason. We could potentially make this more
2197 // fine-grained with the addition of support for more compilation units. It is planned to
2198 // model each package as a different compilation unit.
2199 self.debug_aranges_section_dirty = true;
2200 }
2219 try self.growAllocSection(sym.st_shndx, needed_size);
2220 maybe_last_atom_index.* = atom_index;
2221
2222 // if (self.dwarf) |_| {
2223 // // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
2224 // // range of the compilation unit. When we expand the text section, this range changes,
2225 // // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
2226 // self.debug_info_header_dirty = true;
2227 // // This becomes dirty for the same reason. We could potentially make this more
2228 // // fine-grained with the addition of support for more compilation units. It is planned to
2229 // // model each package as a different compilation unit.
2230 // self.debug_aranges_section_dirty = true;
2231 // }
22012232 }
22022233 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);
22032234
2204 // This function can also reallocate a text block.
2235 // This function can also reallocate an atom.
22052236 // In this case we need to "unplug" it from its previous location before
22062237 // plugging it in to its new location.
2207 if (text_block.prev) |prev| {
2208 prev.next = text_block.next;
2238 if (atom.prev_index) |prev_index| {
2239 const prev = self.getAtomPtr(prev_index);
2240 prev.next_index = atom.next_index;
22092241 }
2210 if (text_block.next) |next| {
2211 next.prev = text_block.prev;
2242 if (atom.next_index) |next_index| {
2243 const next = self.getAtomPtr(next_index);
2244 next.prev_index = atom.prev_index;
22122245 }
22132246
2214 if (block_placement) |big_block| {
2215 text_block.prev = big_block;
2216 text_block.next = big_block.next;
2217 big_block.next = text_block;
2247 if (atom_placement) |big_atom_index| {
2248 const big_atom = self.getAtomPtr(big_atom_index);
2249 const atom_ptr = self.getAtomPtr(atom_index);
2250 atom_ptr.prev_index = big_atom_index;
2251 atom_ptr.next_index = big_atom.next_index;
2252 big_atom.next_index = atom_index;
22182253 } else {
2219 text_block.prev = null;
2220 text_block.next = null;
2254 const atom_ptr = self.getAtomPtr(atom_index);
2255 atom_ptr.prev_index = null;
2256 atom_ptr.next_index = null;
22212257 }
22222258 if (free_list_removal) |i| {
22232259 _ = free_list.swapRemove(i);
......@@ -2272,15 +2308,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {
22722308 return index;
22732309}
22742310
2275fn freeRelocationsForTextBlock(self: *Elf, text_block: *TextBlock) void {
2276 var removed_relocs = self.relocs.fetchRemove(text_block);
2277 if (removed_relocs) |*relocs| relocs.value.deinit(self.base.allocator);
2278}
2279
22802311fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
22812312 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
22822313 for (unnamed_consts.items) |atom| {
2283 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
2314 self.freeAtom(atom);
22842315 }
22852316 unnamed_consts.clearAndFree(self.base.allocator);
22862317}
......@@ -2295,43 +2326,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
22952326
22962327 log.debug("freeDecl {*}", .{decl});
22972328
2298 if (self.decls.fetchRemove(decl_index)) |kv| {
2299 if (kv.value) |index| {
2300 self.freeTextBlock(&decl.link.elf, index);
2301 self.freeUnnamedConsts(decl_index);
2302 }
2329 if (self.decls.fetchRemove(decl_index)) |const_kv| {
2330 var kv = const_kv;
2331 self.freeAtom(kv.value.atom);
2332 self.freeUnnamedConsts(decl_index);
2333 kv.value.exports.deinit(self.base.allocator);
23032334 }
23042335
2305 if (self.dwarf) |*dw| {
2306 dw.freeDecl(decl);
2336 // if (self.dwarf) |*dw| {
2337 // dw.freeDecl(decl);
2338 // }
2339}
2340
2341pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
2342 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2343 if (!gop.found_existing) {
2344 gop.value_ptr.* = .{
2345 .atom = try self.createAtom(),
2346 .shdr = self.getDeclShdrIndex(decl_index),
2347 .exports = .{},
2348 };
23072349 }
2350 return gop.value_ptr.atom;
23082351}
23092352
2310fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 {
2353fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 {
2354 const decl = self.base.options.module.?.declPtr(decl_index);
23112355 const ty = decl.ty;
23122356 const zig_ty = ty.zigTypeTag();
23132357 const val = decl.val;
2314 const phdr_index: u16 = blk: {
2358 const shdr_index: u16 = blk: {
23152359 if (val.isUndefDeep()) {
23162360 // TODO in release-fast and release-small, we should put undef in .bss
2317 break :blk self.phdr_load_rw_index.?;
2361 break :blk self.data_section_index.?;
23182362 }
23192363
23202364 switch (zig_ty) {
23212365 // TODO: what if this is a function pointer?
2322 .Fn => break :blk self.phdr_load_re_index.?,
2366 .Fn => break :blk self.text_section_index.?,
23232367 else => {
23242368 if (val.castTag(.variable)) |_| {
2325 break :blk self.phdr_load_rw_index.?;
2369 break :blk self.data_section_index.?;
23262370 }
2327 break :blk self.phdr_load_ro_index.?;
2371 break :blk self.rodata_section_index.?;
23282372 },
23292373 }
23302374 };
2331 return phdr_index;
2375 return shdr_index;
23322376}
23332377
23342378fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2379 const gpa = self.base.allocator;
23352380 const mod = self.base.options.module.?;
23362381 const decl = mod.declPtr(decl_index);
23372382
......@@ -2341,60 +2386,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
23412386 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
23422387 const required_alignment = decl.getAlignment(self.base.options.target);
23432388
2344 const decl_ptr = self.decls.getPtr(decl_index).?;
2345 if (decl_ptr.* == null) {
2346 decl_ptr.* = try self.getDeclPhdrIndex(decl);
2347 }
2348 const phdr_index = decl_ptr.*.?;
2349 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2389 const decl_metadata = self.decls.get(decl_index).?;
2390 const atom_index = decl_metadata.atom;
2391 const atom = self.getAtom(atom_index);
2392
2393 const shdr_index = decl_metadata.shdr;
2394 if (atom.getSymbol(self).st_size != 0) {
2395 const local_sym = atom.getSymbolPtr(self);
2396 local_sym.st_name = try self.shstrtab.insert(gpa, decl_name);
2397 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2398 local_sym.st_other = 0;
2399 local_sym.st_shndx = shdr_index;
23502400
2351 const local_sym = decl.link.elf.getSymbolPtr(self);
2352 if (local_sym.st_size != 0) {
2353 const capacity = decl.link.elf.capacity(self);
2401 const capacity = atom.capacity(self);
23542402 const need_realloc = code.len > capacity or
23552403 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2404
23562405 if (need_realloc) {
2357 const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
2406 const vaddr = try self.growAtom(atom_index, code.len, required_alignment);
23582407 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });
23592408 if (vaddr != local_sym.st_value) {
23602409 local_sym.st_value = vaddr;
23612410
23622411 log.debug(" (writing new offset table entry)", .{});
2363 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2364 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2412 self.offset_table.items[atom.offset_table_index] = vaddr;
2413 try self.writeOffsetTableEntry(atom.offset_table_index);
23652414 }
23662415 } else if (code.len < local_sym.st_size) {
2367 self.shrinkTextBlock(&decl.link.elf, code.len, phdr_index);
2416 self.shrinkAtom(atom_index, code.len);
23682417 }
23692418 local_sym.st_size = code.len;
2370 local_sym.st_name = try self.updateString(local_sym.st_name, decl_name);
2371 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2372 local_sym.st_other = 0;
2373 local_sym.st_shndx = shdr_index;
2419
23742420 // TODO this write could be avoided if no fields of the symbol were changed.
2375 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2421 try self.writeSymbol(atom.getSymbolIndex().?);
23762422 } else {
2377 const name_str_index = try self.makeString(decl_name);
2378 const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment, phdr_index);
2379 errdefer self.freeTextBlock(&decl.link.elf, phdr_index);
2380 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });
2381
2423 const local_sym = atom.getSymbolPtr(self);
23822424 local_sym.* = .{
2383 .st_name = name_str_index,
2425 .st_name = try self.shstrtab.insert(gpa, decl_name),
23842426 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
23852427 .st_other = 0,
23862428 .st_shndx = shdr_index,
2387 .st_value = vaddr,
2388 .st_size = code.len,
2429 .st_value = 0,
2430 .st_size = 0,
23892431 };
2390 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
2432 const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
2433 errdefer self.freeAtom(atom_index);
2434 log.debug("allocated text block for {s} at 0x{x}", .{ decl_name, vaddr });
23912435
2392 try self.writeSymbol(decl.link.elf.getSymbolIndex().?);
2393 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
2436 self.offset_table.items[atom.offset_table_index] = vaddr;
2437 local_sym.st_value = vaddr;
2438 local_sym.st_size = code.len;
2439
2440 try self.writeSymbol(atom.getSymbolIndex().?);
2441 try self.writeOffsetTableEntry(atom.offset_table_index);
23942442 }
23952443
2444 const local_sym = atom.getSymbolPtr(self);
2445 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
23962446 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2397 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2447 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
23982448 try self.base.file.?.pwriteAll(code, file_offset);
23992449
24002450 return local_sym;
......@@ -2413,28 +2463,23 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24132463
24142464 const decl_index = func.owner_decl;
24152465 const decl = module.declPtr(decl_index);
2416 const atom = &decl.link.elf;
2417 try atom.ensureInitialized(self);
2418 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2419 if (gop.found_existing) {
2420 self.freeUnnamedConsts(decl_index);
2421 self.freeRelocationsForTextBlock(atom);
2422 } else {
2423 gop.value_ptr.* = null;
2424 }
2466
2467 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2468 self.freeUnnamedConsts(decl_index);
2469 Atom.freeRelocations(self, atom_index);
24252470
24262471 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
24272472 defer code_buffer.deinit();
24282473
2429 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2430 defer if (decl_state) |*ds| ds.deinit();
2474 // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2475 // defer if (decl_state) |*ds| ds.deinit();
24312476
2432 const res = if (decl_state) |*ds|
2433 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
2434 .dwarf = ds,
2435 })
2436 else
2437 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
2477 // const res = if (decl_state) |*ds|
2478 // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
2479 // .dwarf = ds,
2480 // })
2481 // else
2482 const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
24382483
24392484 const code = switch (res) {
24402485 .ok => code_buffer.items,
......@@ -2445,15 +2490,16 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24452490 },
24462491 };
24472492 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);
2448 if (decl_state) |*ds| {
2449 try self.dwarf.?.commitDeclState(
2450 module,
2451 decl_index,
2452 local_sym.st_value,
2453 local_sym.st_size,
2454 ds,
2455 );
2456 }
2493 _ = local_sym;
2494 // if (decl_state) |*ds| {
2495 // try self.dwarf.?.commitDeclState(
2496 // module,
2497 // decl_index,
2498 // local_sym.st_value,
2499 // local_sym.st_size,
2500 // ds,
2501 // );
2502 // }
24572503
24582504 // Since we updated the vaddr and the size, each corresponding export
24592505 // symbol also needs to be updated.
......@@ -2483,41 +2529,34 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
24832529 }
24842530 }
24852531
2486 assert(!self.unnamed_const_atoms.contains(decl_index));
2487
2488 const atom = &decl.link.elf;
2489 try atom.ensureInitialized(self);
2490 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2491 if (gop.found_existing) {
2492 self.freeRelocationsForTextBlock(atom);
2493 } else {
2494 gop.value_ptr.* = null;
2495 }
2532 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2533 Atom.freeRelocations(self, atom_index);
2534 const atom = self.getAtom(atom_index);
24962535
24972536 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
24982537 defer code_buffer.deinit();
24992538
2500 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2501 defer if (decl_state) |*ds| ds.deinit();
2539 // var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;
2540 // defer if (decl_state) |*ds| ds.deinit();
25022541
25032542 // TODO implement .debug_info for global variables
25042543 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2505 const res = if (decl_state) |*ds|
2506 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2507 .ty = decl.ty,
2508 .val = decl_val,
2509 }, &code_buffer, .{
2510 .dwarf = ds,
2511 }, .{
2512 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2513 })
2514 else
2515 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2516 .ty = decl.ty,
2517 .val = decl_val,
2518 }, &code_buffer, .none, .{
2519 .parent_atom_index = decl.link.elf.getSymbolIndex().?,
2520 });
2544 // const res = if (decl_state) |*ds|
2545 // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2546 // .ty = decl.ty,
2547 // .val = decl_val,
2548 // }, &code_buffer, .{
2549 // .dwarf = ds,
2550 // }, .{
2551 // .parent_atom_index = atom.getSymbolIndex().?,
2552 // })
2553 // else
2554 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2555 .ty = decl.ty,
2556 .val = decl_val,
2557 }, &code_buffer, .none, .{
2558 .parent_atom_index = atom.getSymbolIndex().?,
2559 });
25212560
25222561 const code = switch (res) {
25232562 .ok => code_buffer.items,
......@@ -2529,15 +2568,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25292568 };
25302569
25312570 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);
2532 if (decl_state) |*ds| {
2533 try self.dwarf.?.commitDeclState(
2534 module,
2535 decl_index,
2536 local_sym.st_value,
2537 local_sym.st_size,
2538 ds,
2539 );
2540 }
2571 _ = local_sym;
2572 // if (decl_state) |*ds| {
2573 // try self.dwarf.?.commitDeclState(
2574 // module,
2575 // decl_index,
2576 // local_sym.st_value,
2577 // local_sym.st_size,
2578 // ds,
2579 // );
2580 // }
25412581
25422582 // Since we updated the vaddr and the size, each corresponding export
25432583 // symbol also needs to be updated.
......@@ -2545,36 +2585,31 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
25452585}
25462586
25472587pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
2548 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2588 const gpa = self.base.allocator;
2589
2590 var code_buffer = std.ArrayList(u8).init(gpa);
25492591 defer code_buffer.deinit();
25502592
25512593 const mod = self.base.options.module.?;
2552 const decl = mod.declPtr(decl_index);
2553
2554 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
2594 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
25552595 if (!gop.found_existing) {
25562596 gop.value_ptr.* = .{};
25572597 }
25582598 const unnamed_consts = gop.value_ptr;
25592599
2560 const atom = try self.base.allocator.create(TextBlock);
2561 errdefer self.base.allocator.destroy(atom);
2562 atom.* = TextBlock.empty;
2563 // TODO for unnamed consts we don't need GOT offset/entry allocated
2564 try atom.ensureInitialized(self);
2565 try self.managed_atoms.append(self.base.allocator, atom);
2566
2600 const decl = mod.declPtr(decl_index);
25672601 const name_str_index = blk: {
25682602 const decl_name = try decl.getFullyQualifiedName(mod);
2569 defer self.base.allocator.free(decl_name);
2570
2603 defer gpa.free(decl_name);
25712604 const index = unnamed_consts.items.len;
2572 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });
2573 defer self.base.allocator.free(name);
2574
2575 break :blk try self.makeString(name);
2605 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
2606 defer gpa.free(name);
2607 break :blk try self.shstrtab.insert(gpa, name);
25762608 };
2577 const name = self.getString(name_str_index);
2609 const name = self.shstrtab.get(name_str_index).?;
2610
2611 const atom_index = try self.createAtom();
2612 const atom = self.getAtomPtr(atom_index);
25782613
25792614 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
25802615 .none = {},
......@@ -2592,28 +2627,24 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
25922627 };
25932628
25942629 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2595 const phdr_index = self.phdr_load_ro_index.?;
2596 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2597 const vaddr = try self.allocateTextBlock(atom, code.len, required_alignment, phdr_index);
2598 errdefer self.freeTextBlock(atom, phdr_index);
2599
2600 log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
2601
2630 const shdr_index = self.rodata_section_index.?;
2631 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
26022632 const local_sym = atom.getSymbolPtr(self);
2603 local_sym.* = .{
2604 .st_name = name_str_index,
2605 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,
2606 .st_other = 0,
2607 .st_shndx = shdr_index,
2608 .st_value = vaddr,
2609 .st_size = code.len,
2610 };
2633 local_sym.st_name = name_str_index;
2634 local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT;
2635 local_sym.st_other = 0;
2636 local_sym.st_shndx = shdr_index;
2637 local_sym.st_size = code.len;
2638 local_sym.st_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2639 errdefer self.freeAtom(atom_index);
2640
2641 log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value });
26112642
26122643 try self.writeSymbol(atom.getSymbolIndex().?);
2613 try unnamed_consts.append(self.base.allocator, atom);
2644 try unnamed_consts.append(gpa, atom_index);
26142645
26152646 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;
2616 const file_offset = self.sections.items[shdr_index].sh_offset + section_offset;
2647 const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
26172648 try self.base.file.?.pwriteAll(code, file_offset);
26182649
26192650 return atom.getSymbolIndex().?;
......@@ -2635,20 +2666,16 @@ pub fn updateDeclExports(
26352666 const tracy = trace(@src());
26362667 defer tracy.end();
26372668
2638 const decl = module.declPtr(decl_index);
2639 const atom = &decl.link.elf;
2640
2641 if (atom.getSymbolIndex() == null) return;
2669 const gpa = self.base.allocator;
26422670
2671 const decl = module.declPtr(decl_index);
2672 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2673 const atom = self.getAtom(atom_index);
26432674 const decl_sym = atom.getSymbol(self);
2644 try self.global_symbols.ensureUnusedCapacity(self.base.allocator, exports.len);
2675 const decl_metadata = self.decls.getPtr(decl_index).?;
2676 const shdr_index = decl_metadata.shdr;
26452677
2646 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
2647 if (!gop.found_existing) {
2648 gop.value_ptr.* = try self.getDeclPhdrIndex(decl);
2649 }
2650 const phdr_index = gop.value_ptr.*.?;
2651 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;
2678 try self.global_symbols.ensureUnusedCapacity(gpa, exports.len);
26522679
26532680 for (exports) |exp| {
26542681 if (exp.options.section) |section_name| {
......@@ -2681,10 +2708,10 @@ pub fn updateDeclExports(
26812708 },
26822709 };
26832710 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);
2684 if (exp.link.elf.sym_index) |i| {
2711 if (decl_metadata.getExport(self, exp.options.name)) |i| {
26852712 const sym = &self.global_symbols.items[i];
26862713 sym.* = .{
2687 .st_name = try self.updateString(sym.st_name, exp.options.name),
2714 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
26882715 .st_info = (stb_bits << 4) | stt_bits,
26892716 .st_other = 0,
26902717 .st_shndx = shdr_index,
......@@ -2692,21 +2719,19 @@ pub fn updateDeclExports(
26922719 .st_size = decl_sym.st_size,
26932720 };
26942721 } else {
2695 const name = try self.makeString(exp.options.name);
26962722 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
26972723 _ = self.global_symbols.addOneAssumeCapacity();
26982724 break :blk self.global_symbols.items.len - 1;
26992725 };
2726 try decl_metadata.exports.append(gpa, @intCast(u32, i));
27002727 self.global_symbols.items[i] = .{
2701 .st_name = name,
2728 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
27022729 .st_info = (stb_bits << 4) | stt_bits,
27032730 .st_other = 0,
27042731 .st_shndx = shdr_index,
27052732 .st_value = decl_sym.st_value,
27062733 .st_size = decl_sym.st_size,
27072734 };
2708
2709 exp.link.elf.sym_index = @intCast(u32, i);
27102735 }
27112736 }
27122737}
......@@ -2722,17 +2747,19 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
27222747 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
27232748
27242749 if (self.llvm_object) |_| return;
2725 if (self.dwarf) |*dw| {
2726 try dw.updateDeclLineNumber(decl);
2727 }
2750 // if (self.dwarf) |*dw| {
2751 // try dw.updateDeclLineNumber(decl);
2752 // }
27282753}
27292754
2730pub fn deleteExport(self: *Elf, exp: Export) void {
2755pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void {
27312756 if (self.llvm_object) |_| return;
2732
2733 const sym_index = exp.sym_index orelse return;
2734 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};
2735 self.global_symbols.items[sym_index].st_info = 0;
2757 const metadata = self.decls.getPtr(decl_index) orelse return;
2758 const sym_index = metadata.getExportPtr(self, name) orelse return;
2759 log.debug("deleting export '{s}'", .{name});
2760 self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {};
2761 self.global_symbols.items[sym_index.*].st_info = 0;
2762 sym_index.* = 0;
27362763}
27372764
27382765fn writeProgHeader(self: *Elf, index: usize) !void {
......@@ -2761,7 +2788,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27612788 switch (self.ptr_width) {
27622789 .p32 => {
27632790 var shdr: [1]elf.Elf32_Shdr = undefined;
2764 shdr[0] = sectHeaderTo32(self.sections.items[index]);
2791 shdr[0] = sectHeaderTo32(self.sections.items(.shdr)[index]);
27652792 if (foreign_endian) {
27662793 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);
27672794 }
......@@ -2769,7 +2796,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27692796 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
27702797 },
27712798 .p64 => {
2772 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
2799 var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]};
27732800 if (foreign_endian) {
27742801 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);
27752802 }
......@@ -2783,11 +2810,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
27832810 const entry_size: u16 = self.archPtrWidthBytes();
27842811 if (self.offset_table_count_dirty) {
27852812 const needed_size = self.offset_table.items.len * entry_size;
2786 try self.growAllocSection(self.got_section_index.?, self.phdr_got_index.?, needed_size);
2813 try self.growAllocSection(self.got_section_index.?, needed_size);
27872814 self.offset_table_count_dirty = false;
27882815 }
27892816 const endian = self.base.options.target.cpu.arch.endian();
2790 const shdr = &self.sections.items[self.got_section_index.?];
2817 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];
27912818 const off = shdr.sh_offset + @as(u64, entry_size) * index;
27922819 switch (entry_size) {
27932820 2 => {
......@@ -2813,7 +2840,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28132840 const tracy = trace(@src());
28142841 defer tracy.end();
28152842
2816 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2843 const syms_sect = &self.sections.items(.shdr)[self.symtab_section_index.?];
28172844 // Make sure we are not pointlessly writing symbol data that will have to get relocated
28182845 // due to running out of space.
28192846 if (self.local_symbols.items.len != syms_sect.sh_info) {
......@@ -2835,7 +2862,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28352862 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,
28362863 };
28372864 const local = self.local_symbols.items[index];
2838 log.debug("writing symbol {d}, '{s}' at 0x{x}", .{ index, self.getString(local.st_name), off });
2865 log.debug("writing symbol {d}, '{?s}' at 0x{x}", .{ index, self.shstrtab.get(local.st_name), off });
28392866 log.debug(" ({})", .{local});
28402867 switch (self.ptr_width) {
28412868 .p32 => {
......@@ -2865,7 +2892,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
28652892}
28662893
28672894fn writeAllGlobalSymbols(self: *Elf) !void {
2868 const syms_sect = &self.sections.items[self.symtab_section_index.?];
2895 const syms_sect = &self.sections.items(.shdr)[self.symtab_section_index.?];
28692896 const sym_size: u64 = switch (self.ptr_width) {
28702897 .p32 => @sizeOf(elf.Elf32_Sym),
28712898 .p64 => @sizeOf(elf.Elf64_Sym),
......@@ -3215,10 +3242,52 @@ const CsuObjects = struct {
32153242fn logSymtab(self: Elf) void {
32163243 log.debug("locals:", .{});
32173244 for (self.local_symbols.items) |sym, id| {
3218 log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx });
3245 log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx });
32193246 }
32203247 log.debug("globals:", .{});
32213248 for (self.global_symbols.items) |sym, id| {
3222 log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx });
3249 log.debug(" {d}: {?s}: @{x} in {d}", .{ id, self.shstrtab.get(sym.st_name), sym.st_value, sym.st_shndx });
32233250 }
32243251}
3252
3253pub fn getProgramHeader(self: *const Elf, shdr_index: u16) elf.Elf64_Phdr {
3254 const index = self.sections.items(.phdr_index)[shdr_index];
3255 return self.program_headers.items[index];
3256}
3257
3258pub fn getProgramHeaderPtr(self: *Elf, shdr_index: u16) *elf.Elf64_Phdr {
3259 const index = self.sections.items(.phdr_index)[shdr_index];
3260 return &self.program_headers.items[index];
3261}
3262
3263/// Returns pointer-to-symbol described at sym_index.
3264pub fn getSymbolPtr(self: *Elf, sym_index: u32) *elf.Elf64_Sym {
3265 return &self.local_symbols.items[sym_index];
3266}
3267
3268/// Returns symbol at sym_index.
3269pub fn getSymbol(self: *const Elf, sym_index: u32) elf.Elf64_Sym {
3270 return self.local_symbols.items[sym_index];
3271}
3272
3273/// Returns name of the symbol at sym_index.
3274pub fn getSymbolName(self: *const Elf, sym_index: u32) []const u8 {
3275 const sym = self.local_symbols.items[sym_index];
3276 return self.shstrtab.get(sym.st_name).?;
3277}
3278
3279pub fn getAtom(self: *const Elf, atom_index: Atom.Index) Atom {
3280 assert(atom_index < self.atoms.items.len);
3281 return self.atoms.items[atom_index];
3282}
3283
3284pub fn getAtomPtr(self: *Elf, atom_index: Atom.Index) *Atom {
3285 assert(atom_index < self.atoms.items.len);
3286 return &self.atoms.items[atom_index];
3287}
3288
3289/// Returns atom if there is an atom referenced by the symbol.
3290/// Returns null on failure.
3291pub fn getAtomIndexForSymbol(self: *Elf, sym_index: u32) ?Atom.Index {
3292 return self.atom_by_index_table.get(sym_index);
3293}
src/link/Elf/Atom.zig+34-27
......@@ -20,44 +20,35 @@ offset_table_index: u32,
2020
2121/// Points to the previous and next neighbors, based on the `text_offset`.
2222/// This can be used to find, for example, the capacity of this `TextBlock`.
23prev: ?*Atom,
24next: ?*Atom,
23prev_index: ?Atom.Index,
24next_index: ?Atom.Index,
2525
2626dbg_info_atom: Dwarf.Atom,
2727
28pub const empty = Atom{
29 .local_sym_index = 0,
30 .offset_table_index = undefined,
31 .prev = null,
32 .next = null,
33 .dbg_info_atom = undefined,
34};
28pub const Index = u32;
3529
36pub fn ensureInitialized(self: *Atom, elf_file: *Elf) !void {
37 if (self.getSymbolIndex() != null) return; // Already initialized
38 self.local_sym_index = try elf_file.allocateLocalSymbol();
39 self.offset_table_index = try elf_file.allocateGotOffset();
40 try elf_file.atom_by_index_table.putNoClobber(elf_file.base.allocator, self.local_sym_index, self);
41}
30pub const Reloc = struct {
31 target: u32,
32 offset: u64,
33 addend: u32,
34 prev_vaddr: u64,
35};
4236
4337pub fn getSymbolIndex(self: Atom) ?u32 {
4438 if (self.local_sym_index == 0) return null;
4539 return self.local_sym_index;
4640}
4741
48pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym {
49 const sym_index = self.getSymbolIndex().?;
50 return elf_file.local_symbols.items[sym_index];
42pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {
43 return elf_file.getSymbol(self.getSymbolIndex().?);
5144}
5245
5346pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {
54 const sym_index = self.getSymbolIndex().?;
55 return &elf_file.local_symbols.items[sym_index];
47 return elf_file.getSymbolPtr(self.getSymbolIndex().?);
5648}
5749
58pub fn getName(self: Atom, elf_file: *Elf) []const u8 {
59 const sym = self.getSymbol();
60 return elf_file.getString(sym.st_name);
50pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {
51 return elf_file.getSymbolName(self.getSymbolIndex().?);
6152}
6253
6354pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
......@@ -72,9 +63,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
7263/// Returns how much room there is to grow in virtual address space.
7364/// File offset relocation happens transparently, so it is not included in
7465/// this calculation.
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {
66pub fn capacity(self: Atom, elf_file: *const Elf) u64 {
7667 const self_sym = self.getSymbol(elf_file);
77 if (self.next) |next| {
68 if (self.next_index) |next_index| {
69 const next = elf_file.getAtom(next_index);
7870 const next_sym = next.getSymbol(elf_file);
7971 return next_sym.st_value - self_sym.st_value;
8072 } else {
......@@ -83,9 +75,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
8375 }
8476}
8577
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
78pub fn freeListEligible(self: Atom, elf_file: *const Elf) bool {
8779 // No need to keep a free list node for the last block.
88 const next = self.next orelse return false;
80 const next_index = self.next_index orelse return false;
81 const next = elf_file.getAtom(next_index);
8982 const self_sym = self.getSymbol(elf_file);
9083 const next_sym = next.getSymbol(elf_file);
9184 const cap = next_sym.st_value - self_sym.st_value;
......@@ -94,3 +87,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
9487 const surplus = cap - ideal_cap;
9588 return surplus >= Elf.min_text_capacity;
9689}
90
91pub fn addRelocation(elf_file: *Elf, atom_index: Index, reloc: Reloc) !void {
92 const gpa = elf_file.base.allocator;
93 const gop = try elf_file.relocs.getOrPut(gpa, atom_index);
94 if (!gop.found_existing) {
95 gop.value_ptr.* = .{};
96 }
97 try gop.value_ptr.append(gpa, reloc);
98}
99
100pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
101 var removed_relocs = elf_file.relocs.fetchRemove(atom_index);
102 if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
103}
src/link/MachO.zig+3-1
......@@ -2604,9 +2604,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
26042604
26052605 log.debug("freeDecl {*}", .{decl});
26062606
2607 if (self.decls.fetchSwapRemove(decl_index)) |kv| {
2607 if (self.decls.fetchSwapRemove(decl_index)) |const_kv| {
2608 var kv = const_kv;
26082609 self.freeAtom(kv.value.atom);
26092610 self.freeUnnamedConsts(decl_index);
2611 kv.value.exports.deinit(self.base.allocator);
26102612 }
26112613
26122614 // if (self.d_sym) |*d_sym| {