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(...@@ -5275,7 +5275,7 @@ pub fn clearDecl(
5275 // and allow it to be variably sized.5275 // and allow it to be variably sized.
5276 decl.link = switch (mod.comp.bin_file.tag) {5276 decl.link = switch (mod.comp.bin_file.tag) {
5277 .coff => .{ .coff = link.File.Coff.Atom.empty },5277 .coff => .{ .coff = link.File.Coff.Atom.empty },
5278 .elf => .{ .elf = link.File.Elf.TextBlock.empty },5278 .elf => .{ .elf = {} },
5279 .macho => .{ .macho = {} },5279 .macho => .{ .macho = {} },
5280 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },5280 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
5281 .c => .{ .c = {} },5281 .c => .{ .c = {} },
...@@ -5381,7 +5381,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void...@@ -5381,7 +5381,7 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
5381 }5381 }
5382 }5382 }
5383 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {5383 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
5384 elf.deleteExport(exp.link.elf);5384 elf.deleteDeclExport(decl_index, exp.options.name);
5385 }5385 }
5386 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {5386 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
5387 try macho.deleteDeclExport(decl_index, exp.options.name);5387 try macho.deleteDeclExport(decl_index, exp.options.name);
...@@ -5695,7 +5695,7 @@ pub fn allocateNewDecl(...@@ -5695,7 +5695,7 @@ pub fn allocateNewDecl(
5695 .src_scope = src_scope,5695 .src_scope = src_scope,
5696 .link = switch (mod.comp.bin_file.tag) {5696 .link = switch (mod.comp.bin_file.tag) {
5697 .coff => .{ .coff = link.File.Coff.Atom.empty },5697 .coff => .{ .coff = link.File.Coff.Atom.empty },
5698 .elf => .{ .elf = link.File.Elf.TextBlock.empty },5698 .elf => .{ .elf = {} },
5699 .macho => .{ .macho = {} },5699 .macho => .{ .macho = {} },
5700 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },5700 .plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
5701 .c => .{ .c = {} },5701 .c => .{ .c = {} },
src/Sema.zig+1-1
...@@ -5566,7 +5566,7 @@ pub fn analyzeExport(...@@ -5566,7 +5566,7 @@ pub fn analyzeExport(
5566 .src = src,5566 .src = src,
5567 .link = switch (mod.comp.bin_file.tag) {5567 .link = switch (mod.comp.bin_file.tag) {
5568 .coff => .{ .coff = .{} },5568 .coff => .{ .coff = .{} },
5569 .elf => .{ .elf = .{} },5569 .elf => .{ .elf = {} },
5570 .macho => .{ .macho = {} },5570 .macho => .{ .macho = {} },
5571 .plan9 => .{ .plan9 = null },5571 .plan9 => .{ .plan9 = null },
5572 .c => .{ .c = {} },5572 .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...@@ -4308,8 +4308,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4308 const fn_owner_decl = mod.declPtr(func.owner_decl);4308 const fn_owner_decl = mod.declPtr(func.owner_decl);
43094309
4310 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4310 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4311 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4311 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4312 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4312 const atom = elf_file.getAtom(atom_index);
4313 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4313 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });4314 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
4314 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4315 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4315 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);4316 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...@@ -6138,8 +6139,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6138 mod.markDeclAlive(decl);6139 mod.markDeclAlive(decl);
61396140
6140 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6141 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6141 try decl.link.elf.ensureInitialized(elf_file);6142 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6142 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6143 const atom = elf_file.getAtom(atom_index);
6144 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6143 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6145 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6144 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);6146 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
6145 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;6147 const sym_index = macho_file.getAtom(atom).getSymbolIndex().?;
...@@ -6168,8 +6170,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6168,8 +6170,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6168 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6170 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6169 };6171 };
6170 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6172 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6171 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6173 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6172 return MCValue{ .memory = vaddr };
6173 } else if (self.bin_file.cast(link.File.MachO)) |_| {6174 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6174 return MCValue{ .linker_load = .{6175 return MCValue{ .linker_load = .{
6175 .type = .direct,6176 .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...@@ -4256,12 +4256,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4256 if (self.air.value(callee)) |func_value| {4256 if (self.air.value(callee)) |func_value| {
4257 if (func_value.castTag(.function)) |func_payload| {4257 if (func_value.castTag(.function)) |func_payload| {
4258 const func = func_payload.data;4258 const func = func_payload.data;
4259 const mod = self.bin_file.options.module.?;
4260 const fn_owner_decl = mod.declPtr(func.owner_decl);
42614259
4262 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4260 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4263 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4261 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4264 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4262 const atom = elf_file.getAtom(atom_index);
4263 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4265 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });4264 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
4266 } else if (self.bin_file.cast(link.File.MachO)) |_| {4265 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4267 unreachable; // unsupported architecture for MachO4266 unreachable; // unsupported architecture for MachO
...@@ -6084,8 +6083,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6084,8 +6083,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6084 mod.markDeclAlive(decl);6083 mod.markDeclAlive(decl);
60856084
6086 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6085 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6087 try decl.link.elf.ensureInitialized(elf_file);6086 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6088 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6087 const atom = elf_file.getAtom(atom_index);
6088 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6089 } else if (self.bin_file.cast(link.File.MachO)) |_| {6089 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6090 unreachable; // unsupported architecture for MachO6090 unreachable; // unsupported architecture for MachO
6091 } else if (self.bin_file.cast(link.File.Coff)) |_| {6091 } else if (self.bin_file.cast(link.File.Coff)) |_| {
...@@ -6106,8 +6106,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6106,8 +6106,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6106 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6106 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6107 };6107 };
6108 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6108 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6109 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6109 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6110 return MCValue{ .memory = vaddr };
6111 } else if (self.bin_file.cast(link.File.MachO)) |_| {6110 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6112 unreachable;6111 unreachable;
6113 } else if (self.bin_file.cast(link.File.Coff)) |_| {6112 } 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...@@ -1721,12 +1721,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1721 if (self.air.value(callee)) |func_value| {1721 if (self.air.value(callee)) |func_value| {
1722 if (func_value.castTag(.function)) |func_payload| {1722 if (func_value.castTag(.function)) |func_payload| {
1723 const func = func_payload.data;1723 const func = func_payload.data;
17241724 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1725 const mod = self.bin_file.options.module.?;1725 const atom = elf_file.getAtom(atom_index);
1726 const fn_owner_decl = mod.declPtr(func.owner_decl);1726 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
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
1730 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });1727 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
1731 _ = try self.addInst(.{1728 _ = try self.addInst(.{
1732 .tag = .jalr,1729 .tag = .jalr,
...@@ -2553,8 +2550,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -2553,8 +2550,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
2553 const decl = mod.declPtr(decl_index);2550 const decl = mod.declPtr(decl_index);
2554 mod.markDeclAlive(decl);2551 mod.markDeclAlive(decl);
2555 if (self.bin_file.cast(link.File.Elf)) |elf_file| {2552 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
2556 try decl.link.elf.ensureInitialized(elf_file);2553 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
2557 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };2554 const atom = elf_file.getAtom(atom_index);
2555 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
2558 } else if (self.bin_file.cast(link.File.MachO)) |_| {2556 } else if (self.bin_file.cast(link.File.MachO)) |_| {
2559 unreachable;2557 unreachable;
2560 } else if (self.bin_file.cast(link.File.Coff)) |_| {2558 } 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...@@ -1216,11 +1216,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1216 if (self.bin_file.tag == link.File.Elf.base_tag) {1216 if (self.bin_file.tag == link.File.Elf.base_tag) {
1217 if (func_value.castTag(.function)) |func_payload| {1217 if (func_value.castTag(.function)) |func_payload| {
1218 const func = func_payload.data;1218 const func = func_payload.data;
1219 const mod = self.bin_file.options.module.?;
1220 const fn_owner_decl = mod.declPtr(func.owner_decl);
1221 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1219 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1222 try fn_owner_decl.link.elf.ensureInitialized(elf_file);1220 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
1223 break :blk @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));1221 const atom = elf_file.getAtom(atom_index);
1222 break :blk @intCast(u32, atom.getOffsetTableAddress(elf_file));
1224 } else unreachable;1223 } else unreachable;
12251224
1226 try self.genSetReg(Type.initTag(.usize), .o7, .{ .memory = got_addr });1225 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...@@ -4205,8 +4204,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
42054204
4206 mod.markDeclAlive(decl);4205 mod.markDeclAlive(decl);
4207 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4206 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4208 try decl.link.elf.ensureInitialized(elf_file);4207 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
4209 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };4208 const atom = elf_file.getAtom(atom_index);
4209 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
4210 } else {4210 } else {
4211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});4211 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
4212 }4212 }
src/arch/x86_64/CodeGen.zig+7-6
...@@ -4000,8 +4000,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4000,8 +4000,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4000 const fn_owner_decl = mod.declPtr(func.owner_decl);4000 const fn_owner_decl = mod.declPtr(func.owner_decl);
40014001
4002 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4002 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4003 try fn_owner_decl.link.elf.ensureInitialized(elf_file);4003 const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
4004 const got_addr = @intCast(u32, fn_owner_decl.link.elf.getOffsetTableAddress(elf_file));4004 const atom = elf_file.getAtom(atom_index);
4005 const got_addr = @intCast(u32, atom.getOffsetTableAddress(elf_file));
4005 _ = try self.addInst(.{4006 _ = try self.addInst(.{
4006 .tag = .call,4007 .tag = .call,
4007 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),4008 .ops = Mir.Inst.Ops.encode(.{ .flags = 0b01 }),
...@@ -6721,8 +6722,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne...@@ -6721,8 +6722,9 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
6721 module.markDeclAlive(decl);6722 module.markDeclAlive(decl);
67226723
6723 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6724 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6724 try decl.link.elf.ensureInitialized(elf_file);6725 const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
6725 return MCValue{ .memory = decl.link.elf.getOffsetTableAddress(elf_file) };6726 const atom = elf_file.getAtom(atom_index);
6727 return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) };
6726 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {6728 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
6727 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);6729 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
6728 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;6730 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
...@@ -6751,8 +6753,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6751,8 +6753,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6751 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});6753 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
6752 };6754 };
6753 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6755 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6754 const vaddr = elf_file.local_symbols.items[local_sym_index].st_value;6756 return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value };
6755 return MCValue{ .memory = vaddr };
6756 } else if (self.bin_file.cast(link.File.MachO)) |_| {6757 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6757 return MCValue{ .linker_load = .{6758 return MCValue{ .linker_load = .{
6758 .type = .direct,6759 .type = .direct,
src/link.zig+2-2
...@@ -262,7 +262,7 @@ pub const File = struct {...@@ -262,7 +262,7 @@ pub const File = struct {
262 lock: ?Cache.Lock = null,262 lock: ?Cache.Lock = null,
263263
264 pub const LinkBlock = union {264 pub const LinkBlock = union {
265 elf: Elf.TextBlock,265 elf: void,
266 coff: Coff.Atom,266 coff: Coff.Atom,
267 macho: void,267 macho: void,
268 plan9: Plan9.DeclBlock,268 plan9: Plan9.DeclBlock,
...@@ -284,7 +284,7 @@ pub const File = struct {...@@ -284,7 +284,7 @@ pub const File = struct {
284 };284 };
285285
286 pub const Export = union {286 pub const Export = union {
287 elf: Elf.Export,287 elf: void,
288 coff: Coff.Export,288 coff: Coff.Export,
289 macho: void,289 macho: void,
290 plan9: Plan9.Export,290 plan9: Plan9.Export,
src/link/Dwarf.zig+13-13
...@@ -1099,7 +1099,7 @@ pub fn commitDeclState(...@@ -1099,7 +1099,7 @@ pub fn commitDeclState(
1099 switch (self.bin_file.tag) {1099 switch (self.bin_file.tag) {
1100 .elf => {1100 .elf => {
1101 const elf_file = self.bin_file.cast(File.Elf).?;1101 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.?];
1103 const file_pos = debug_line_sect.sh_offset + src_fn.off;1103 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);1104 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, src_fn.len);
1105 },1105 },
...@@ -1152,7 +1152,7 @@ pub fn commitDeclState(...@@ -1152,7 +1152,7 @@ pub fn commitDeclState(
1152 const elf_file = self.bin_file.cast(File.Elf).?;1152 const elf_file = self.bin_file.cast(File.Elf).?;
1153 const shdr_index = elf_file.debug_line_section_index.?;1153 const shdr_index = elf_file.debug_line_section_index.?;
1154 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);1154 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];
1156 const file_pos = debug_line_sect.sh_offset + src_fn.off;1156 const file_pos = debug_line_sect.sh_offset + src_fn.off;
1157 try pwriteDbgLineNops(1157 try pwriteDbgLineNops(
1158 elf_file.base.file.?,1158 elf_file.base.file.?,
...@@ -1332,7 +1332,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {...@@ -1332,7 +1332,7 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, atom: *Atom, len: u32) !void {
1332 switch (self.bin_file.tag) {1332 switch (self.bin_file.tag) {
1333 .elf => {1333 .elf => {
1334 const elf_file = self.bin_file.cast(File.Elf).?;1334 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.?];
1336 const file_pos = debug_info_sect.sh_offset + atom.off;1336 const file_pos = debug_info_sect.sh_offset + atom.off;
1337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);1337 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, &[0]u8{}, atom.len, false);
1338 },1338 },
...@@ -1399,7 +1399,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void...@@ -1399,7 +1399,7 @@ fn writeDeclDebugInfo(self: *Dwarf, atom: *Atom, dbg_info_buf: []const u8) !void
1399 const elf_file = self.bin_file.cast(File.Elf).?;1399 const elf_file = self.bin_file.cast(File.Elf).?;
1400 const shdr_index = elf_file.debug_info_section_index.?;1400 const shdr_index = elf_file.debug_info_section_index.?;
1401 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);1401 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];
1403 const file_pos = debug_info_sect.sh_offset + atom.off;1403 const file_pos = debug_info_sect.sh_offset + atom.off;
1404 try pwriteDbgInfoNops(1404 try pwriteDbgInfoNops(
1405 elf_file.base.file.?,1405 elf_file.base.file.?,
...@@ -1475,7 +1475,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {...@@ -1475,7 +1475,7 @@ pub fn updateDeclLineNumber(self: *Dwarf, decl: *const Module.Decl) !void {
1475 switch (self.bin_file.tag) {1475 switch (self.bin_file.tag) {
1476 .elf => {1476 .elf => {
1477 const elf_file = self.bin_file.cast(File.Elf).?;1477 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.?];
1479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();1479 const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
1480 try elf_file.base.file.?.pwriteAll(&data, file_pos);1480 try elf_file.base.file.?.pwriteAll(&data, file_pos);
1481 },1481 },
...@@ -1690,7 +1690,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {...@@ -1690,7 +1690,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
1690 const elf_file = self.bin_file.cast(File.Elf).?;1690 const elf_file = self.bin_file.cast(File.Elf).?;
1691 const shdr_index = elf_file.debug_abbrev_section_index.?;1691 const shdr_index = elf_file.debug_abbrev_section_index.?;
1692 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, false);1692 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];
1694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;1694 const file_pos = debug_abbrev_sect.sh_offset + abbrev_offset;
1695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);1695 try elf_file.base.file.?.pwriteAll(&abbrev_buf, file_pos);
1696 },1696 },
...@@ -1805,7 +1805,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u...@@ -1805,7 +1805,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, module: *Module, low_pc: u64, high_pc: u
1805 switch (self.bin_file.tag) {1805 switch (self.bin_file.tag) {
1806 .elf => {1806 .elf => {
1807 const elf_file = self.bin_file.cast(File.Elf).?;1807 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.?];
1809 const file_pos = debug_info_sect.sh_offset;1809 const file_pos = debug_info_sect.sh_offset;
1810 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);1810 try pwriteDbgInfoNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt, false);
1811 },1811 },
...@@ -2124,7 +2124,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {...@@ -2124,7 +2124,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
2124 const elf_file = self.bin_file.cast(File.Elf).?;2124 const elf_file = self.bin_file.cast(File.Elf).?;
2125 const shdr_index = elf_file.debug_aranges_section_index.?;2125 const shdr_index = elf_file.debug_aranges_section_index.?;
2126 try elf_file.growNonAllocSection(shdr_index, needed_size, 16, false);2126 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];
2128 const file_pos = debug_aranges_sect.sh_offset;2128 const file_pos = debug_aranges_sect.sh_offset;
2129 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);2129 try elf_file.base.file.?.pwriteAll(di_buf.items, file_pos);
2130 },2130 },
...@@ -2285,9 +2285,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2285,9 +2285,9 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2285 .elf => {2285 .elf => {
2286 const elf_file = self.bin_file.cast(File.Elf).?;2286 const elf_file = self.bin_file.cast(File.Elf).?;
2287 const shdr_index = elf_file.debug_line_section_index.?;2287 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;
2289 try elf_file.growNonAllocSection(shdr_index, needed_size, 1, true);2289 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
2292 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);2292 const amt = try elf_file.base.file.?.preadAll(buffer, file_pos);
2293 if (amt != buffer.len) return error.InputOutput;2293 if (amt != buffer.len) return error.InputOutput;
...@@ -2346,7 +2346,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {...@@ -2346,7 +2346,7 @@ pub fn writeDbgLineHeader(self: *Dwarf) !void {
2346 switch (self.bin_file.tag) {2346 switch (self.bin_file.tag) {
2347 .elf => {2347 .elf => {
2348 const elf_file = self.bin_file.cast(File.Elf).?;2348 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.?];
2350 const file_pos = debug_line_sect.sh_offset;2350 const file_pos = debug_line_sect.sh_offset;
2351 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);2351 try pwriteDbgLineNops(elf_file.base.file.?, file_pos, 0, di_buf.items, jmp_amt);
2352 },2352 },
...@@ -2487,7 +2487,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {...@@ -2487,7 +2487,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void {
2487 switch (self.bin_file.tag) {2487 switch (self.bin_file.tag) {
2488 .elf => {2488 .elf => {
2489 const elf_file = self.bin_file.cast(File.Elf).?;2489 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.?];
2491 break :blk debug_info_sect.sh_offset;2491 break :blk debug_info_sect.sh_offset;
2492 },2492 },
2493 .macho => {2493 .macho => {
...@@ -2638,7 +2638,7 @@ fn addDbgInfoErrorSet(...@@ -2638,7 +2638,7 @@ fn addDbgInfoErrorSet(
2638fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom {2638fn getDbgInfoAtom(tag: File.Tag, mod: *Module, decl_index: Module.Decl.Index) *Atom {
2639 const decl = mod.declPtr(decl_index);2639 const decl = mod.declPtr(decl_index);
2640 return switch (tag) {2640 return switch (tag) {
2641 .elf => &decl.link.elf.dbg_info_atom,2641 .elf => unreachable,
2642 .macho => unreachable,2642 .macho => unreachable,
2643 .wasm => &decl.link.wasm.dbg_info_atom,2643 .wasm => &decl.link.wasm.dbg_info_atom,
2644 else => unreachable,2644 else => unreachable,
src/link/Elf.zig+812-743
...@@ -1,43 +1,89 @@...@@ -1,43 +1,89 @@
1const Elf = @This();1const Elf = @This();
22
3const std = @import("std");3const std = @import("std");
4const build_options = @import("build_options");
4const builtin = @import("builtin");5const builtin = @import("builtin");
5const math = std.math;
6const mem = std.mem;
7const assert = std.debug.assert;6const assert = std.debug.assert;
8const Allocator = std.mem.Allocator;
9const fs = std.fs;
10const elf = std.elf;7const elf = std.elf;
8const fs = std.fs;
11const log = std.log.scoped(.link);9const 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");
17const codegen = @import("../codegen.zig");13const 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");
28const glibc = @import("../glibc.zig");14const glibc = @import("../glibc.zig");
15const link = @import("../link.zig");
16const lldMain = @import("../main.zig").lldMain;
29const musl = @import("../musl.zig");17const musl = @import("../musl.zig");
30const Cache = @import("../Cache.zig");18const target_util = @import("../target.zig");
19const trace = @import("../tracy.zig").trace;
20
31const Air = @import("../Air.zig");21const 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;
32const Liveness = @import("../Liveness.zig");28const Liveness = @import("../Liveness.zig");
33const LlvmObject = @import("../codegen/llvm.zig").Object;29const LlvmObject = @import("../codegen/llvm.zig").Object;
3430const Module = @import("../Module.zig");
35pub const TextBlock = Atom;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
37const default_entry_addr = 0x8000000;37const default_entry_addr = 0x8000000;
3838
39pub const base_tag: File.Tag = .elf;39pub 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
41base: File,87base: File,
42dwarf: ?Dwarf = null,88dwarf: ?Dwarf = null,
4389
...@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,...@@ -48,12 +94,12 @@ llvm_object: ?*LlvmObject = null,
4894
49/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.95/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
50/// Same order as in the file.96/// Same order as in the file.
51sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = std.ArrayListUnmanaged(elf.Elf64_Shdr){},97sections: std.MultiArrayList(Section) = .{},
52shdr_table_offset: ?u64 = null,98shdr_table_offset: ?u64 = null,
5399
54/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.100/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
55/// Same order as in the file.101/// 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) = .{},
57phdr_table_offset: ?u64 = null,103phdr_table_offset: ?u64 = null,
58/// The index into the program headers of a PT_LOAD program header with Read and Execute flags104/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
59phdr_load_re_index: ?u16 = null,105phdr_load_re_index: ?u16 = null,
...@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,...@@ -65,12 +111,10 @@ phdr_load_ro_index: ?u16 = null,
65/// The index into the program headers of a PT_LOAD program header with Write flag111/// The index into the program headers of a PT_LOAD program header with Write flag
66phdr_load_rw_index: ?u16 = null,112phdr_load_rw_index: ?u16 = null,
67113
68phdr_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
69
70entry_addr: ?u64 = null,114entry_addr: ?u64 = null,
71page_size: u32,115page_size: u32,
72116
73shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},117shstrtab: StringTable(.strtab) = .{},
74shstrtab_index: ?u16 = null,118shstrtab_index: ?u16 = null,
75119
76symtab_section_index: ?u16 = null,120symtab_section_index: ?u16 = null,
...@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,...@@ -113,39 +157,14 @@ debug_line_header_dirty: bool = false,
113157
114error_flags: File.ErrorFlags = File.ErrorFlags{},158error_flags: File.ErrorFlags = File.ErrorFlags{},
115159
116/// Pointer to the last allocated atom160/// Table of tracked Decls.
117atoms: std.AutoHashMapUnmanaged(u16, *TextBlock) = .{},161decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
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) = .{},
141162
142/// List of atoms that are owned directly by the linker.163/// List of atoms that are owned directly by the linker.
143/// Currently these are only atoms that are the result of linking164atoms: std.ArrayListUnmanaged(Atom) = .{},
144/// object files. Atoms which take part in incremental linking are165
145/// at present owned by Module.Decl.166/// Table of atoms indexed by the symbol index.
146/// TODO consolidate this.167atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
149168
150/// Table of unnamed constants associated with a parent `Decl`.169/// Table of unnamed constants associated with a parent `Decl`.
151/// We store them here so that we can free the constants whenever the `Decl`170/// We store them here so that we can free the constants whenever the `Decl`
...@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -173,15 +192,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},
173/// this will be a table indexed by index into the list of Atoms.192/// this will be a table indexed by index into the list of Atoms.
174relocs: RelocTable = .{},193relocs: RelocTable = .{},
175194
176const Reloc = struct {195const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
177 target: u32,196const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
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));
185197
186/// When allocating, the ideal_capacity is calculated by198/// When allocating, the ideal_capacity is calculated by
187/// actual_capacity + (actual_capacity / ideal_factor)199/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -190,15 +202,11 @@ const ideal_factor = 3;...@@ -190,15 +202,11 @@ const ideal_factor = 3;
190/// In order for a slice of bytes to be considered eligible to keep metadata pointing at202/// In order for a slice of bytes to be considered eligible to keep metadata pointing at
191/// it as a possible place to put new symbols, it must have enough room for this many bytes203/// it as a possible place to put new symbols, it must have enough room for this many bytes
192/// (plus extra for reserved capacity).204/// (plus extra for reserved capacity).
193const minimum_text_block_size = 64;205const minimum_atom_size = 64;
194pub const min_text_capacity = padToIdeal(minimum_text_block_size);206pub const min_text_capacity = padToIdeal(minimum_atom_size);
195207
196pub const PtrWidth = enum { p32, p64 };208pub const PtrWidth = enum { p32, p64 };
197209
198pub const Export = struct {
199 sym_index: ?u32 = null,
200};
201
202pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {210pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
203 assert(options.target.ofmt == .elf);211 assert(options.target.ofmt == .elf);
204212
...@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -230,16 +238,19 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
230238
231 // There must always be a null section in index 0239 // There must always be a null section in index 0
232 try self.sections.append(allocator, .{240 try self.sections.append(allocator, .{
233 .sh_name = 0,241 .shdr = .{
234 .sh_type = elf.SHT_NULL,242 .sh_name = 0,
235 .sh_flags = 0,243 .sh_type = elf.SHT_NULL,
236 .sh_addr = 0,244 .sh_flags = 0,
237 .sh_offset = 0,245 .sh_addr = 0,
238 .sh_size = 0,246 .sh_offset = 0,
239 .sh_link = 0,247 .sh_size = 0,
240 .sh_info = 0,248 .sh_link = 0,
241 .sh_addralign = 0,249 .sh_info = 0,
242 .sh_entsize = 0,250 .sh_addralign = 0,
251 .sh_entsize = 0,
252 },
253 .phdr_index = undefined,
243 });254 });
244255
245 try self.populateMissingMetadata();256 try self.populateMissingMetadata();
...@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {...@@ -286,75 +297,67 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
286}297}
287298
288pub fn deinit(self: *Elf) void {299pub fn deinit(self: *Elf) void {
300 const gpa = self.base.allocator;
301
289 if (build_options.have_llvm) {302 if (build_options.have_llvm) {
290 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);303 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
291 }304 }
292305
293 self.sections.deinit(self.base.allocator);306 for (self.sections.items(.free_list)) |*free_list| {
294 self.program_headers.deinit(self.base.allocator);307 free_list.deinit(gpa);
295 self.shstrtab.deinit(self.base.allocator);308 }
296 self.local_symbols.deinit(self.base.allocator);309 self.sections.deinit(gpa);
297 self.global_symbols.deinit(self.base.allocator);310
298 self.global_symbol_free_list.deinit(self.base.allocator);311 self.program_headers.deinit(gpa);
299 self.local_symbol_free_list.deinit(self.base.allocator);312 self.shstrtab.deinit(gpa);
300 self.offset_table_free_list.deinit(self.base.allocator);313 self.local_symbols.deinit(gpa);
301 self.offset_table.deinit(self.base.allocator);314 self.global_symbols.deinit(gpa);
302 self.phdr_shdr_table.deinit(self.base.allocator);315 self.global_symbol_free_list.deinit(gpa);
303 self.decls.deinit(self.base.allocator);316 self.local_symbol_free_list.deinit(gpa);
304317 self.offset_table_free_list.deinit(gpa);
305 self.atoms.deinit(self.base.allocator);318 self.offset_table.deinit(gpa);
319
306 {320 {
307 var it = self.atom_free_lists.valueIterator();321 var it = self.decls.iterator();
308 while (it.next()) |free_list| {322 while (it.next()) |entry| {
309 free_list.deinit(self.base.allocator);323 entry.value_ptr.exports.deinit(gpa);
310 }324 }
311 self.atom_free_lists.deinit(self.base.allocator);325 self.decls.deinit(gpa);
312 }326 }
313327
314 for (self.managed_atoms.items) |atom| {328 self.atoms.deinit(gpa);
315 self.base.allocator.destroy(atom);329 self.atom_by_index_table.deinit(gpa);
316 }
317 self.managed_atoms.deinit(self.base.allocator);
318330
319 {331 {
320 var it = self.unnamed_const_atoms.valueIterator();332 var it = self.unnamed_const_atoms.valueIterator();
321 while (it.next()) |atoms| {333 while (it.next()) |atoms| {
322 atoms.deinit(self.base.allocator);334 atoms.deinit(gpa);
323 }335 }
324 self.unnamed_const_atoms.deinit(self.base.allocator);336 self.unnamed_const_atoms.deinit(gpa);
325 }337 }
326338
327 {339 {
328 var it = self.relocs.valueIterator();340 var it = self.relocs.valueIterator();
329 while (it.next()) |relocs| {341 while (it.next()) |relocs| {
330 relocs.deinit(self.base.allocator);342 relocs.deinit(gpa);
331 }343 }
332 self.relocs.deinit(self.base.allocator);344 self.relocs.deinit(gpa);
333 }345 }
334346
335 self.atom_by_index_table.deinit(self.base.allocator);347 // if (self.dwarf) |*dw| {
336348 // dw.deinit();
337 if (self.dwarf) |*dw| {349 // }
338 dw.deinit();
339 }
340}350}
341351
342pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: File.RelocInfo) !u64 {352pub 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
346 assert(self.llvm_object == null);353 assert(self.llvm_object == null);
347354
348 try decl.link.elf.ensureInitialized(self);355 const this_atom_index = try self.getOrCreateAtomForDecl(decl_index);
349 const target = decl.link.elf.getSymbolIndex().?;356 const this_atom = self.getAtom(this_atom_index);
350357 const target = this_atom.getSymbolIndex().?;
351 const vaddr = self.local_symbols.items[target].st_value;358 const vaddr = this_atom.getSymbol(self).st_value;
352 const atom = self.atom_by_index_table.get(reloc_info.parent_atom_index).?;359 const atom_index = self.getAtomIndexForSymbol(reloc_info.parent_atom_index).?;
353 const gop = try self.relocs.getOrPut(self.base.allocator, atom);360 try Atom.addRelocation(self, atom_index, .{
354 if (!gop.found_existing) {
355 gop.value_ptr.* = .{};
356 }
357 try gop.value_ptr.append(self.base.allocator, .{
358 .target = target,361 .target = target,
359 .offset = reloc_info.offset,362 .offset = reloc_info.offset,
360 .addend = reloc_info.addend,363 .addend = reloc_info.addend,
...@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -375,7 +378,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
375378
376 if (self.shdr_table_offset) |off| {379 if (self.shdr_table_offset) |off| {
377 const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);380 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;
379 const increased_size = padToIdeal(tight_size);382 const increased_size = padToIdeal(tight_size);
380 const test_end = off + increased_size;383 const test_end = off + increased_size;
381 if (end > off and start < test_end) {384 if (end > off and start < test_end) {
...@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -385,7 +388,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
385388
386 if (self.phdr_table_offset) |off| {389 if (self.phdr_table_offset) |off| {
387 const phdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Phdr) else @sizeOf(elf.Elf64_Phdr);390 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;
389 const increased_size = padToIdeal(tight_size);392 const increased_size = padToIdeal(tight_size);
390 const test_end = off + increased_size;393 const test_end = off + increased_size;
391 if (end > off and start < test_end) {394 if (end > off and start < test_end) {
...@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {...@@ -393,7 +396,7 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
393 }396 }
394 }397 }
395398
396 for (self.sections.items) |section| {399 for (self.sections.items(.shdr)) |section| {
397 const increased_size = padToIdeal(section.sh_size);400 const increased_size = padToIdeal(section.sh_size);
398 const test_end = section.sh_offset + increased_size;401 const test_end = section.sh_offset + increased_size;
399 if (end > section.sh_offset and start < test_end) {402 if (end > section.sh_offset and start < test_end) {
...@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {...@@ -420,7 +423,7 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
420 if (self.phdr_table_offset) |off| {423 if (self.phdr_table_offset) |off| {
421 if (off > start and off < min_pos) min_pos = off;424 if (off > start and off < min_pos) min_pos = off;
422 }425 }
423 for (self.sections.items) |section| {426 for (self.sections.items(.shdr)) |section| {
424 if (section.sh_offset <= start) continue;427 if (section.sh_offset <= start) continue;
425 if (section.sh_offset < min_pos) min_pos = section.sh_offset;428 if (section.sh_offset < min_pos) min_pos = section.sh_offset;
426 }429 }
...@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {...@@ -439,31 +442,10 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
439 return start;442 return start;
440}443}
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
464pub fn populateMissingMetadata(self: *Elf) !void {445pub fn populateMissingMetadata(self: *Elf) !void {
465 assert(self.llvm_object == null);446 assert(self.llvm_object == null);
466447
448 const gpa = self.base.allocator;
467 const small_ptr = switch (self.ptr_width) {449 const small_ptr = switch (self.ptr_width) {
468 .p32 => true,450 .p32 => true,
469 .p64 => false,451 .p64 => false,
...@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -477,7 +459,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
477 const off = self.findFreeSpace(file_size, p_align);459 const off = self.findFreeSpace(file_size, p_align);
478 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });460 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
479 const entry_addr: u64 = self.entry_addr orelse if (self.base.options.target.cpu.arch == .spu_2) @as(u64, 0) else default_entry_addr;461 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, .{
481 .p_type = elf.PT_LOAD,463 .p_type = elf.PT_LOAD,
482 .p_offset = off,464 .p_offset = off,
483 .p_filesz = file_size,465 .p_filesz = file_size,
...@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -487,7 +469,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
487 .p_align = p_align,469 .p_align = p_align,
488 .p_flags = elf.PF_X | elf.PF_R,470 .p_flags = elf.PF_X | elf.PF_R,
489 });471 });
490 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_re_index.?, .{});
491 self.entry_addr = null;472 self.entry_addr = null;
492 self.phdr_table_dirty = true;473 self.phdr_table_dirty = true;
493 }474 }
...@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -504,7 +485,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
504 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something485 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
505 // else in virtual memory.486 // else in virtual memory.
506 const got_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x4000000 else 0x8000;487 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, .{
508 .p_type = elf.PT_LOAD,489 .p_type = elf.PT_LOAD,
509 .p_offset = off,490 .p_offset = off,
510 .p_filesz = file_size,491 .p_filesz = file_size,
...@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -527,7 +508,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
527 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });508 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
528 // TODO Same as for GOT509 // TODO Same as for GOT
529 const rodata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0xc000000 else 0xa000;510 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, .{
531 .p_type = elf.PT_LOAD,512 .p_type = elf.PT_LOAD,
532 .p_offset = off,513 .p_offset = off,
533 .p_filesz = file_size,514 .p_filesz = file_size,
...@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -537,7 +518,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
537 .p_align = p_align,518 .p_align = p_align,
538 .p_flags = elf.PF_R,519 .p_flags = elf.PF_R,
539 });520 });
540 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_ro_index.?, .{});
541 self.phdr_table_dirty = true;521 self.phdr_table_dirty = true;
542 }522 }
543523
...@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -551,7 +531,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
551 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });531 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
552 // TODO Same as for GOT532 // TODO Same as for GOT
553 const rwdata_addr: u32 = if (self.base.options.target.cpu.arch.ptrBitWidth() >= 32) 0x10000000 else 0xc000;533 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, .{
555 .p_type = elf.PT_LOAD,535 .p_type = elf.PT_LOAD,
556 .p_offset = off,536 .p_offset = off,
557 .p_filesz = file_size,537 .p_filesz = file_size,
...@@ -561,278 +541,290 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -561,278 +541,290 @@ pub fn populateMissingMetadata(self: *Elf) !void {
561 .p_align = p_align,541 .p_align = p_align,
562 .p_flags = elf.PF_R | elf.PF_W,542 .p_flags = elf.PF_R | elf.PF_W,
563 });543 });
564 try self.atom_free_lists.putNoClobber(self.base.allocator, self.phdr_load_rw_index.?, .{});
565 self.phdr_table_dirty = true;544 self.phdr_table_dirty = true;
566 }545 }
567546
568 if (self.shstrtab_index == null) {547 if (self.shstrtab_index == null) {
569 self.shstrtab_index = @intCast(u16, self.sections.items.len);548 self.shstrtab_index = @intCast(u16, self.sections.slice().len);
570 assert(self.shstrtab.items.len == 0);549 assert(self.shstrtab.buffer.items.len == 0);
571 try self.shstrtab.append(self.base.allocator, 0); // need a 0 at position 0550 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
572 const off = self.findFreeSpace(self.shstrtab.items.len, 1);551 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
573 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.items.len });552 log.debug("found shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
574 try self.sections.append(self.base.allocator, .{553 try self.sections.append(gpa, .{
575 .sh_name = try self.makeString(".shstrtab"),554 .shdr = .{
576 .sh_type = elf.SHT_STRTAB,555 .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
577 .sh_flags = 0,556 .sh_type = elf.SHT_STRTAB,
578 .sh_addr = 0,557 .sh_flags = 0,
579 .sh_offset = off,558 .sh_addr = 0,
580 .sh_size = self.shstrtab.items.len,559 .sh_offset = off,
581 .sh_link = 0,560 .sh_size = self.shstrtab.buffer.items.len,
582 .sh_info = 0,561 .sh_link = 0,
583 .sh_addralign = 1,562 .sh_info = 0,
584 .sh_entsize = 0,563 .sh_addralign = 1,
564 .sh_entsize = 0,
565 },
566 .phdr_index = undefined,
585 });567 });
586 self.shstrtab_dirty = true;568 self.shstrtab_dirty = true;
587 self.shdr_table_dirty = true;569 self.shdr_table_dirty = true;
588 }570 }
589571
590 if (self.text_section_index == null) {572 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);
592 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];574 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
593575
594 try self.sections.append(self.base.allocator, .{576 try self.sections.append(gpa, .{
595 .sh_name = try self.makeString(".text"),577 .shdr = .{
596 .sh_type = elf.SHT_PROGBITS,578 .sh_name = try self.shstrtab.insert(gpa, ".text"),
597 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,579 .sh_type = elf.SHT_PROGBITS,
598 .sh_addr = phdr.p_vaddr,580 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
599 .sh_offset = phdr.p_offset,581 .sh_addr = phdr.p_vaddr,
600 .sh_size = phdr.p_filesz,582 .sh_offset = phdr.p_offset,
601 .sh_link = 0,583 .sh_size = phdr.p_filesz,
602 .sh_info = 0,584 .sh_link = 0,
603 .sh_addralign = 1,585 .sh_info = 0,
604 .sh_entsize = 0,586 .sh_addralign = 1,
587 .sh_entsize = 0,
588 },
589 .phdr_index = self.phdr_load_re_index.?,
605 });590 });
606 try self.phdr_shdr_table.putNoClobber(
607 self.base.allocator,
608 self.phdr_load_re_index.?,
609 self.text_section_index.?,
610 );
611 self.shdr_table_dirty = true;591 self.shdr_table_dirty = true;
612 }592 }
613593
614 if (self.got_section_index == null) {594 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);
616 const phdr = &self.program_headers.items[self.phdr_got_index.?];596 const phdr = &self.program_headers.items[self.phdr_got_index.?];
617597
618 try self.sections.append(self.base.allocator, .{598 try self.sections.append(gpa, .{
619 .sh_name = try self.makeString(".got"),599 .shdr = .{
620 .sh_type = elf.SHT_PROGBITS,600 .sh_name = try self.shstrtab.insert(gpa, ".got"),
621 .sh_flags = elf.SHF_ALLOC,601 .sh_type = elf.SHT_PROGBITS,
622 .sh_addr = phdr.p_vaddr,602 .sh_flags = elf.SHF_ALLOC,
623 .sh_offset = phdr.p_offset,603 .sh_addr = phdr.p_vaddr,
624 .sh_size = phdr.p_filesz,604 .sh_offset = phdr.p_offset,
625 .sh_link = 0,605 .sh_size = phdr.p_filesz,
626 .sh_info = 0,606 .sh_link = 0,
627 .sh_addralign = @as(u16, ptr_size),607 .sh_info = 0,
628 .sh_entsize = 0,608 .sh_addralign = @as(u16, ptr_size),
609 .sh_entsize = 0,
610 },
611 .phdr_index = self.phdr_got_index.?,
629 });612 });
630 try self.phdr_shdr_table.putNoClobber(
631 self.base.allocator,
632 self.phdr_got_index.?,
633 self.got_section_index.?,
634 );
635 self.shdr_table_dirty = true;613 self.shdr_table_dirty = true;
636 }614 }
637615
638 if (self.rodata_section_index == null) {616 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);
640 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];618 const phdr = &self.program_headers.items[self.phdr_load_ro_index.?];
641619
642 try self.sections.append(self.base.allocator, .{620 try self.sections.append(gpa, .{
643 .sh_name = try self.makeString(".rodata"),621 .shdr = .{
644 .sh_type = elf.SHT_PROGBITS,622 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
645 .sh_flags = elf.SHF_ALLOC,623 .sh_type = elf.SHT_PROGBITS,
646 .sh_addr = phdr.p_vaddr,624 .sh_flags = elf.SHF_ALLOC,
647 .sh_offset = phdr.p_offset,625 .sh_addr = phdr.p_vaddr,
648 .sh_size = phdr.p_filesz,626 .sh_offset = phdr.p_offset,
649 .sh_link = 0,627 .sh_size = phdr.p_filesz,
650 .sh_info = 0,628 .sh_link = 0,
651 .sh_addralign = 1,629 .sh_info = 0,
652 .sh_entsize = 0,630 .sh_addralign = 1,
631 .sh_entsize = 0,
632 },
633 .phdr_index = self.phdr_load_ro_index.?,
653 });634 });
654 try self.phdr_shdr_table.putNoClobber(
655 self.base.allocator,
656 self.phdr_load_ro_index.?,
657 self.rodata_section_index.?,
658 );
659 self.shdr_table_dirty = true;635 self.shdr_table_dirty = true;
660 }636 }
661637
662 if (self.data_section_index == null) {638 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);
664 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];640 const phdr = &self.program_headers.items[self.phdr_load_rw_index.?];
665641
666 try self.sections.append(self.base.allocator, .{642 try self.sections.append(gpa, .{
667 .sh_name = try self.makeString(".data"),643 .shdr = .{
668 .sh_type = elf.SHT_PROGBITS,644 .sh_name = try self.shstrtab.insert(gpa, ".data"),
669 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,645 .sh_type = elf.SHT_PROGBITS,
670 .sh_addr = phdr.p_vaddr,646 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
671 .sh_offset = phdr.p_offset,647 .sh_addr = phdr.p_vaddr,
672 .sh_size = phdr.p_filesz,648 .sh_offset = phdr.p_offset,
673 .sh_link = 0,649 .sh_size = phdr.p_filesz,
674 .sh_info = 0,650 .sh_link = 0,
675 .sh_addralign = @as(u16, ptr_size),651 .sh_info = 0,
676 .sh_entsize = 0,652 .sh_addralign = @as(u16, ptr_size),
653 .sh_entsize = 0,
654 },
655 .phdr_index = self.phdr_load_rw_index.?,
677 });656 });
678 try self.phdr_shdr_table.putNoClobber(
679 self.base.allocator,
680 self.phdr_load_rw_index.?,
681 self.data_section_index.?,
682 );
683 self.shdr_table_dirty = true;657 self.shdr_table_dirty = true;
684 }658 }
685659
686 if (self.symtab_section_index == null) {660 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);
688 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);662 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
689 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);663 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
690 const file_size = self.base.options.symbol_count_hint * each_size;664 const file_size = self.base.options.symbol_count_hint * each_size;
691 const off = self.findFreeSpace(file_size, min_align);665 const off = self.findFreeSpace(file_size, min_align);
692 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });666 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
693667
694 try self.sections.append(self.base.allocator, .{668 try self.sections.append(gpa, .{
695 .sh_name = try self.makeString(".symtab"),669 .shdr = .{
696 .sh_type = elf.SHT_SYMTAB,670 .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
697 .sh_flags = 0,671 .sh_type = elf.SHT_SYMTAB,
698 .sh_addr = 0,672 .sh_flags = 0,
699 .sh_offset = off,673 .sh_addr = 0,
700 .sh_size = file_size,674 .sh_offset = off,
701 // The section header index of the associated string table.675 .sh_size = file_size,
702 .sh_link = self.shstrtab_index.?,676 // The section header index of the associated string table.
703 .sh_info = @intCast(u32, self.local_symbols.items.len),677 .sh_link = self.shstrtab_index.?,
704 .sh_addralign = min_align,678 .sh_info = @intCast(u32, self.local_symbols.items.len),
705 .sh_entsize = each_size,679 .sh_addralign = min_align,
680 .sh_entsize = each_size,
681 },
682 .phdr_index = undefined,
706 });683 });
707 self.shdr_table_dirty = true;684 self.shdr_table_dirty = true;
708 try self.writeSymbol(0);685 try self.writeSymbol(0);
709 }686 }
710687
711 if (self.dwarf) |*dw| {688 // if (self.dwarf) |*dw| {
712 if (self.debug_str_section_index == null) {689 // if (self.debug_str_section_index == null) {
713 self.debug_str_section_index = @intCast(u16, self.sections.items.len);690 // self.debug_str_section_index = @intCast(u16, self.sections.slice().len);
714 assert(dw.strtab.items.len == 0);691 // assert(dw.strtab.items.len == 0);
715 try dw.strtab.append(self.base.allocator, 0);692 // try dw.strtab.append(gpa, 0);
716 try self.sections.append(self.base.allocator, .{693 // try self.sections.append(gpa, .{
717 .sh_name = try self.makeString(".debug_str"),694 // .shdr = .{
718 .sh_type = elf.SHT_PROGBITS,695 // .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
719 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,696 // .sh_type = elf.SHT_PROGBITS,
720 .sh_addr = 0,697 // .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
721 .sh_offset = 0,698 // .sh_addr = 0,
722 .sh_size = 0,699 // .sh_offset = 0,
723 .sh_link = 0,700 // .sh_size = 0,
724 .sh_info = 0,701 // .sh_link = 0,
725 .sh_addralign = 1,702 // .sh_info = 0,
726 .sh_entsize = 1,703 // .sh_addralign = 1,
727 });704 // .sh_entsize = 1,
728 self.debug_strtab_dirty = true;705 // },
729 self.shdr_table_dirty = true;706 // .phdr_index = undefined,
730 }707 // });
731708 // self.debug_strtab_dirty = true;
732 if (self.debug_info_section_index == null) {709 // self.shdr_table_dirty = true;
733 self.debug_info_section_index = @intCast(u16, self.sections.items.len);710 // }
734711
735 const file_size_hint = 200;712 // if (self.debug_info_section_index == null) {
736 const p_align = 1;713 // self.debug_info_section_index = @intCast(u16, self.sections.slice().len);
737 const off = self.findFreeSpace(file_size_hint, p_align);714
738 log.debug("found .debug_info free space 0x{x} to 0x{x}", .{715 // const file_size_hint = 200;
739 off,716 // const p_align = 1;
740 off + file_size_hint,717 // const off = self.findFreeSpace(file_size_hint, p_align);
741 });718 // log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
742 try self.sections.append(self.base.allocator, .{719 // off,
743 .sh_name = try self.makeString(".debug_info"),720 // off + file_size_hint,
744 .sh_type = elf.SHT_PROGBITS,721 // });
745 .sh_flags = 0,722 // try self.sections.append(gpa, .{
746 .sh_addr = 0,723 // .shdr = .{
747 .sh_offset = off,724 // .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
748 .sh_size = file_size_hint,725 // .sh_type = elf.SHT_PROGBITS,
749 .sh_link = 0,726 // .sh_flags = 0,
750 .sh_info = 0,727 // .sh_addr = 0,
751 .sh_addralign = p_align,728 // .sh_offset = off,
752 .sh_entsize = 0,729 // .sh_size = file_size_hint,
753 });730 // .sh_link = 0,
754 self.shdr_table_dirty = true;731 // .sh_info = 0,
755 self.debug_info_header_dirty = true;732 // .sh_addralign = p_align,
756 }733 // .sh_entsize = 0,
757734 // },
758 if (self.debug_abbrev_section_index == null) {735 // .phdr_index = undefined,
759 self.debug_abbrev_section_index = @intCast(u16, self.sections.items.len);736 // });
760737 // self.shdr_table_dirty = true;
761 const file_size_hint = 128;738 // self.debug_info_header_dirty = true;
762 const p_align = 1;739 // }
763 const off = self.findFreeSpace(file_size_hint, p_align);740
764 log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{741 // if (self.debug_abbrev_section_index == null) {
765 off,742 // self.debug_abbrev_section_index = @intCast(u16, self.sections.slice().len);
766 off + file_size_hint,743
767 });744 // const file_size_hint = 128;
768 try self.sections.append(self.base.allocator, .{745 // const p_align = 1;
769 .sh_name = try self.makeString(".debug_abbrev"),746 // const off = self.findFreeSpace(file_size_hint, p_align);
770 .sh_type = elf.SHT_PROGBITS,747 // log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
771 .sh_flags = 0,748 // off,
772 .sh_addr = 0,749 // off + file_size_hint,
773 .sh_offset = off,750 // });
774 .sh_size = file_size_hint,751 // try self.sections.append(gpa, .{
775 .sh_link = 0,752 // .shdr = .{
776 .sh_info = 0,753 // .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
777 .sh_addralign = p_align,754 // .sh_type = elf.SHT_PROGBITS,
778 .sh_entsize = 0,755 // .sh_flags = 0,
779 });756 // .sh_addr = 0,
780 self.shdr_table_dirty = true;757 // .sh_offset = off,
781 self.debug_abbrev_section_dirty = true;758 // .sh_size = file_size_hint,
782 }759 // .sh_link = 0,
783760 // .sh_info = 0,
784 if (self.debug_aranges_section_index == null) {761 // .sh_addralign = p_align,
785 self.debug_aranges_section_index = @intCast(u16, self.sections.items.len);762 // .sh_entsize = 0,
786763 // },
787 const file_size_hint = 160;764 // .phdr_index = undefined,
788 const p_align = 16;765 // });
789 const off = self.findFreeSpace(file_size_hint, p_align);766 // self.shdr_table_dirty = true;
790 log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{767 // self.debug_abbrev_section_dirty = true;
791 off,768 // }
792 off + file_size_hint,769
793 });770 // if (self.debug_aranges_section_index == null) {
794 try self.sections.append(self.base.allocator, .{771 // self.debug_aranges_section_index = @intCast(u16, self.sections.slice().len);
795 .sh_name = try self.makeString(".debug_aranges"),772
796 .sh_type = elf.SHT_PROGBITS,773 // const file_size_hint = 160;
797 .sh_flags = 0,774 // const p_align = 16;
798 .sh_addr = 0,775 // const off = self.findFreeSpace(file_size_hint, p_align);
799 .sh_offset = off,776 // log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
800 .sh_size = file_size_hint,777 // off,
801 .sh_link = 0,778 // off + file_size_hint,
802 .sh_info = 0,779 // });
803 .sh_addralign = p_align,780 // try self.sections.append(gpa, .{
804 .sh_entsize = 0,781 // .shdr = .{
805 });782 // .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
806 self.shdr_table_dirty = true;783 // .sh_type = elf.SHT_PROGBITS,
807 self.debug_aranges_section_dirty = true;784 // .sh_flags = 0,
808 }785 // .sh_addr = 0,
809786 // .sh_offset = off,
810 if (self.debug_line_section_index == null) {787 // .sh_size = file_size_hint,
811 self.debug_line_section_index = @intCast(u16, self.sections.items.len);788 // .sh_link = 0,
812789 // .sh_info = 0,
813 const file_size_hint = 250;790 // .sh_addralign = p_align,
814 const p_align = 1;791 // .sh_entsize = 0,
815 const off = self.findFreeSpace(file_size_hint, p_align);792 // },
816 log.debug("found .debug_line free space 0x{x} to 0x{x}", .{793 // .phdr_index = undefined,
817 off,794 // });
818 off + file_size_hint,795 // self.shdr_table_dirty = true;
819 });796 // self.debug_aranges_section_dirty = true;
820 try self.sections.append(self.base.allocator, .{797 // }
821 .sh_name = try self.makeString(".debug_line"),798
822 .sh_type = elf.SHT_PROGBITS,799 // if (self.debug_line_section_index == null) {
823 .sh_flags = 0,800 // self.debug_line_section_index = @intCast(u16, self.sections.slice().len);
824 .sh_addr = 0,801
825 .sh_offset = off,802 // const file_size_hint = 250;
826 .sh_size = file_size_hint,803 // const p_align = 1;
827 .sh_link = 0,804 // const off = self.findFreeSpace(file_size_hint, p_align);
828 .sh_info = 0,805 // log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
829 .sh_addralign = p_align,806 // off,
830 .sh_entsize = 0,807 // off + file_size_hint,
831 });808 // });
832 self.shdr_table_dirty = true;809 // try self.sections.append(gpa, .{
833 self.debug_line_header_dirty = true;810 // .shdr = .{
834 }811 // .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
835 }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
837 const shsize: u64 = switch (self.ptr_width) {829 const shsize: u64 = switch (self.ptr_width) {
838 .p32 => @sizeOf(elf.Elf32_Shdr),830 .p32 => @sizeOf(elf.Elf32_Shdr),
...@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -843,7 +835,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
843 .p64 => @alignOf(elf.Elf64_Shdr),835 .p64 => @alignOf(elf.Elf64_Shdr),
844 };836 };
845 if (self.shdr_table_offset == null) {837 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);
847 self.shdr_table_dirty = true;839 self.shdr_table_dirty = true;
848 }840 }
849841
...@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -874,7 +866,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
874 // offset + it's filesize.866 // offset + it's filesize.
875 var max_file_offset: u64 = 0;867 var max_file_offset: u64 = 0;
876868
877 for (self.sections.items) |shdr| {869 for (self.sections.items(.shdr)) |shdr| {
878 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {870 if (shdr.sh_offset + shdr.sh_size > max_file_offset) {
879 max_file_offset = shdr.sh_offset + shdr.sh_size;871 max_file_offset = shdr.sh_offset + shdr.sh_size;
880 }872 }
...@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {...@@ -884,15 +876,18 @@ pub fn populateMissingMetadata(self: *Elf) !void {
884 }876 }
885}877}
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 {
888 // TODO Also detect virtual address collisions.880 // 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];
890 const phdr = &self.program_headers.items[phdr_index];883 const phdr = &self.program_headers.items[phdr_index];
884 const maybe_last_atom_index = self.sections.items(.last_atom_index)[shdr_index];
891885
892 if (needed_size > self.allocatedSize(shdr.sh_offset)) {886 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
893 // Must move the entire section.887 // Must move the entire section.
894 const new_offset = self.findFreeSpace(needed_size, self.page_size);888 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);
896 const sym = last.getSymbol(self);891 const sym = last.getSymbol(self);
897 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;892 break :blk (sym.st_value + sym.st_size) - phdr.p_vaddr;
898 } else if (shdr_index == self.got_section_index.?) blk: {893 } 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...@@ -900,8 +895,8 @@ fn growAllocSection(self: *Elf, shdr_index: u16, phdr_index: u16, needed_size: u
900 } else 0;895 } else 0;
901 shdr.sh_size = 0;896 shdr.sh_size = 0;
902897
903 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{898 log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
904 self.getString(shdr.sh_name),899 self.shstrtab.get(shdr.sh_name),
905 new_offset,900 new_offset,
906 new_offset + existing_size,901 new_offset + existing_size,
907 });902 });
...@@ -927,7 +922,7 @@ pub fn growNonAllocSection(...@@ -927,7 +922,7 @@ pub fn growNonAllocSection(
927 min_alignment: u32,922 min_alignment: u32,
928 requires_file_copy: bool,923 requires_file_copy: bool,
929) !void {924) !void {
930 const shdr = &self.sections.items[shdr_index];925 const shdr = &self.sections.items(.shdr)[shdr_index];
931926
932 if (needed_size > self.allocatedSize(shdr.sh_offset)) {927 if (needed_size > self.allocatedSize(shdr.sh_offset)) {
933 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {928 const existing_size = if (self.symtab_section_index.? == shdr_index) blk: {
...@@ -940,7 +935,7 @@ pub fn growNonAllocSection(...@@ -940,7 +935,7 @@ pub fn growNonAllocSection(
940 shdr.sh_size = 0;935 shdr.sh_size = 0;
941 // Move all the symbols to a new file location.936 // Move all the symbols to a new file location.
942 const new_offset = self.findFreeSpace(needed_size, min_alignment);937 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
945 if (requires_file_copy) {940 if (requires_file_copy) {
946 const amt = try self.base.file.?.copyRangeAll(941 const amt = try self.base.file.?.copyRangeAll(
...@@ -961,25 +956,26 @@ pub fn growNonAllocSection(...@@ -961,25 +956,26 @@ pub fn growNonAllocSection(
961}956}
962957
963pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {958pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
959 _ = shdr_index;
964 self.shdr_table_dirty = true; // TODO look into only writing one section960 self.shdr_table_dirty = true; // TODO look into only writing one section
965961
966 if (phdr_index) |_| {962 if (phdr_index) |_| {
967 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty963 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
968 }964 }
969965
970 if (self.dwarf) |_| {966 // if (self.dwarf) |_| {
971 if (self.debug_info_section_index.? == shdr_index) {967 // if (self.debug_info_section_index.? == shdr_index) {
972 self.debug_info_header_dirty = true;968 // self.debug_info_header_dirty = true;
973 } else if (self.debug_line_section_index.? == shdr_index) {969 // } else if (self.debug_line_section_index.? == shdr_index) {
974 self.debug_line_header_dirty = true;970 // self.debug_line_header_dirty = true;
975 } else if (self.debug_abbrev_section_index.? == shdr_index) {971 // } else if (self.debug_abbrev_section_index.? == shdr_index) {
976 self.debug_abbrev_section_dirty = true;972 // self.debug_abbrev_section_dirty = true;
977 } else if (self.debug_str_section_index.? == shdr_index) {973 // } else if (self.debug_str_section_index.? == shdr_index) {
978 self.debug_strtab_dirty = true;974 // self.debug_strtab_dirty = true;
979 } else if (self.debug_aranges_section_index.? == shdr_index) {975 // } else if (self.debug_aranges_section_index.? == shdr_index) {
980 self.debug_aranges_section_dirty = true;976 // self.debug_aranges_section_dirty = true;
981 }977 // }
982 }978 // }
983}979}
984980
985pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {981pub 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...@@ -1011,6 +1007,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1011 }1007 }
1012 }1008 }
10131009
1010 const gpa = self.base.allocator;
1014 var sub_prog_node = prog_node.start("ELF Flush", 0);1011 var sub_prog_node = prog_node.start("ELF Flush", 0);
1015 sub_prog_node.activate();1012 sub_prog_node.activate();
1016 defer sub_prog_node.end();1013 defer sub_prog_node.end();
...@@ -1018,23 +1015,25 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1018,23 +1015,25 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1018 // TODO This linker code currently assumes there is only 1 compilation unit and it1015 // TODO This linker code currently assumes there is only 1 compilation unit and it
1019 // corresponds to the Zig source code.1016 // corresponds to the Zig source code.
1020 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;1017 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
1018 _ = module;
10211019
1022 const target_endian = self.base.options.target.cpu.arch.endian();1020 const target_endian = self.base.options.target.cpu.arch.endian();
1023 const foreign_endian = target_endian != builtin.cpu.arch.endian();1021 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10241022
1025 if (self.dwarf) |*dw| {1023 // if (self.dwarf) |*dw| {
1026 try dw.flushModule(module);1024 // try dw.flushModule(module);
1027 }1025 // }
10281026
1029 {1027 {
1030 var it = self.relocs.iterator();1028 var it = self.relocs.iterator();
1031 while (it.next()) |entry| {1029 while (it.next()) |entry| {
1032 const atom = entry.key_ptr.*;1030 const atom_index = entry.key_ptr.*;
1033 const relocs = entry.value_ptr.*;1031 const relocs = entry.value_ptr.*;
1032 const atom = self.getAtom(atom_index);
1034 const source_sym = atom.getSymbol(self);1033 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
1039 for (relocs.items) |*reloc| {1038 for (relocs.items) |*reloc| {
1040 const target_sym = self.local_symbols.items[reloc.target];1039 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...@@ -1045,10 +1044,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1045 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;1044 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
1046 const file_offset = source_shdr.sh_offset + section_offset;1045 const file_offset = source_shdr.sh_offset + section_offset;
10471046
1048 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{1047 log.debug(" ({x}: [() => 0x{x}] ({?s}))", .{
1049 reloc.offset,1048 reloc.offset,
1050 target_vaddr,1049 target_vaddr,
1051 self.getString(target_sym.st_name),1050 self.shstrtab.get(target_sym.st_name),
1052 });1051 });
10531052
1054 switch (self.ptr_width) {1053 switch (self.ptr_width) {
...@@ -1069,43 +1068,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1069,43 +1068,43 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1069 self.logSymtab();1068 self.logSymtab();
1070 }1069 }
10711070
1072 if (self.dwarf) |*dw| {1071 // if (self.dwarf) |*dw| {
1073 if (self.debug_abbrev_section_dirty) {1072 // if (self.debug_abbrev_section_dirty) {
1074 try dw.writeDbgAbbrev();1073 // try dw.writeDbgAbbrev();
1075 if (!self.shdr_table_dirty) {1074 // if (!self.shdr_table_dirty) {
1076 // Then it won't get written with the others and we need to do it.1075 // // Then it won't get written with the others and we need to do it.
1077 try self.writeSectHeader(self.debug_abbrev_section_index.?);1076 // try self.writeSectHeader(self.debug_abbrev_section_index.?);
1078 }1077 // }
1079 self.debug_abbrev_section_dirty = false;1078 // self.debug_abbrev_section_dirty = false;
1080 }1079 // }
10811080
1082 if (self.debug_info_header_dirty) {1081 // if (self.debug_info_header_dirty) {
1083 // Currently only one compilation unit is supported, so the address range is simply1082 // // 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.1083 // // identical to the main program header virtual address and memory size.
1085 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];1084 // const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1086 const low_pc = text_phdr.p_vaddr;1085 // const low_pc = text_phdr.p_vaddr;
1087 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1086 // const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1088 try dw.writeDbgInfoHeader(module, low_pc, high_pc);1087 // try dw.writeDbgInfoHeader(module, low_pc, high_pc);
1089 self.debug_info_header_dirty = false;1088 // self.debug_info_header_dirty = false;
1090 }1089 // }
10911090
1092 if (self.debug_aranges_section_dirty) {1091 // if (self.debug_aranges_section_dirty) {
1093 // Currently only one compilation unit is supported, so the address range is simply1092 // // 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.1093 // // identical to the main program header virtual address and memory size.
1095 const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];1094 // const text_phdr = &self.program_headers.items[self.phdr_load_re_index.?];
1096 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);1095 // try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1097 if (!self.shdr_table_dirty) {1096 // if (!self.shdr_table_dirty) {
1098 // Then it won't get written with the others and we need to do it.1097 // // Then it won't get written with the others and we need to do it.
1099 try self.writeSectHeader(self.debug_aranges_section_index.?);1098 // try self.writeSectHeader(self.debug_aranges_section_index.?);
1100 }1099 // }
1101 self.debug_aranges_section_dirty = false;1100 // self.debug_aranges_section_dirty = false;
1102 }1101 // }
11031102
1104 if (self.debug_line_header_dirty) {1103 // if (self.debug_line_header_dirty) {
1105 try dw.writeDbgLineHeader();1104 // try dw.writeDbgLineHeader();
1106 self.debug_line_header_dirty = false;1105 // self.debug_line_header_dirty = false;
1107 }1106 // }
1108 }1107 // }
11091108
1110 if (self.phdr_table_dirty) {1109 if (self.phdr_table_dirty) {
1111 const phsize: u64 = switch (self.ptr_width) {1110 const phsize: u64 = switch (self.ptr_width) {
...@@ -1126,8 +1125,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1126,8 +1125,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11261125
1127 switch (self.ptr_width) {1126 switch (self.ptr_width) {
1128 .p32 => {1127 .p32 => {
1129 const buf = try self.base.allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);1128 const buf = try gpa.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
1130 defer self.base.allocator.free(buf);1129 defer gpa.free(buf);
11311130
1132 for (buf) |*phdr, i| {1131 for (buf) |*phdr, i| {
1133 phdr.* = progHeaderTo32(self.program_headers.items[i]);1132 phdr.* = progHeaderTo32(self.program_headers.items[i]);
...@@ -1138,8 +1137,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1138,8 +1137,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1138 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);1137 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
1139 },1138 },
1140 .p64 => {1139 .p64 => {
1141 const buf = try self.base.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);1140 const buf = try gpa.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
1142 defer self.base.allocator.free(buf);1141 defer gpa.free(buf);
11431142
1144 for (buf) |*phdr, i| {1143 for (buf) |*phdr, i| {
1145 phdr.* = self.program_headers.items[i];1144 phdr.* = self.program_headers.items[i];
...@@ -1155,23 +1154,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1155,23 +1154,23 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11551154
1156 {1155 {
1157 const shdr_index = self.shstrtab_index.?;1156 const shdr_index = self.shstrtab_index.?;
1158 if (self.shstrtab_dirty or self.shstrtab.items.len != self.sections.items[shdr_index].sh_size) {1157 if (self.shstrtab_dirty or self.shstrtab.buffer.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1159 try self.growNonAllocSection(shdr_index, self.shstrtab.items.len, 1, false);1158 try self.growNonAllocSection(shdr_index, self.shstrtab.buffer.items.len, 1, false);
1160 const shstrtab_sect = self.sections.items[shdr_index];1159 const shstrtab_sect = self.sections.items(.shdr)[shdr_index];
1161 try self.base.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);1160 try self.base.file.?.pwriteAll(self.shstrtab.buffer.items, shstrtab_sect.sh_offset);
1162 self.shstrtab_dirty = false;1161 self.shstrtab_dirty = false;
1163 }1162 }
1164 }1163 }
11651164
1166 if (self.dwarf) |dwarf| {1165 // if (self.dwarf) |dwarf| {
1167 const shdr_index = self.debug_str_section_index.?;1166 // 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) {1167 // if (self.debug_strtab_dirty or dwarf.strtab.items.len != self.sections.items(.shdr)[shdr_index].sh_size) {
1169 try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);1168 // try self.growNonAllocSection(shdr_index, dwarf.strtab.items.len, 1, false);
1170 const debug_strtab_sect = self.sections.items[shdr_index];1169 // const debug_strtab_sect = self.sections.items(.shdr)[shdr_index];
1171 try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);1170 // try self.base.file.?.pwriteAll(dwarf.strtab.items, debug_strtab_sect.sh_offset);
1172 self.debug_strtab_dirty = false;1171 // self.debug_strtab_dirty = false;
1173 }1172 // }
1174 }1173 // }
11751174
1176 if (self.shdr_table_dirty) {1175 if (self.shdr_table_dirty) {
1177 const shsize: u64 = switch (self.ptr_width) {1176 const shsize: u64 = switch (self.ptr_width) {
...@@ -1183,7 +1182,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1183,7 +1182,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1183 .p64 => @alignOf(elf.Elf64_Shdr),1182 .p64 => @alignOf(elf.Elf64_Shdr),
1184 };1183 };
1185 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);1184 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
1188 if (needed_size > allocated_size) {1187 if (needed_size > allocated_size) {
1189 self.shdr_table_offset = null; // free the space1188 self.shdr_table_offset = null; // free the space
...@@ -1192,12 +1191,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1192,12 +1191,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11921191
1193 switch (self.ptr_width) {1192 switch (self.ptr_width) {
1194 .p32 => {1193 .p32 => {
1195 const buf = try self.base.allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);1194 const slice = self.sections.slice();
1196 defer self.base.allocator.free(buf);1195 const buf = try gpa.alloc(elf.Elf32_Shdr, slice.len);
1196 defer gpa.free(buf);
11971197
1198 for (buf) |*shdr, i| {1198 for (buf) |*shdr, i| {
1199 shdr.* = sectHeaderTo32(self.sections.items[i]);1199 shdr.* = sectHeaderTo32(slice.items(.shdr)[i]);
1200 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });1200 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
1201 if (foreign_endian) {1201 if (foreign_endian) {
1202 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);1202 mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
1203 }1203 }
...@@ -1205,12 +1205,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1205,12 +1205,13 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1205 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);1205 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
1206 },1206 },
1207 .p64 => {1207 .p64 => {
1208 const buf = try self.base.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);1208 const slice = self.sections.slice();
1209 defer self.base.allocator.free(buf);1209 const buf = try gpa.alloc(elf.Elf64_Shdr, slice.len);
1210 defer gpa.free(buf);
12101211
1211 for (buf) |*shdr, i| {1212 for (buf) |*shdr, i| {
1212 shdr.* = self.sections.items[i];1213 shdr.* = slice.items(.shdr)[i];
1213 log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* });1214 log.debug("writing section {?s}: {}", .{ self.shstrtab.get(shdr.sh_name), shdr.* });
1214 if (foreign_endian) {1215 if (foreign_endian) {
1215 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);1216 mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
1216 }1217 }
...@@ -2021,7 +2022,7 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2021,7 +2022,7 @@ fn writeElfHeader(self: *Elf) !void {
2021 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);2022 mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
2022 index += 2;2023 index += 2;
20232024
2024 const e_shnum = @intCast(u16, self.sections.items.len);2025 const e_shnum = @intCast(u16, self.sections.slice().len);
2025 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);2026 mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
2026 index += 2;2027 index += 2;
20272028
...@@ -2033,124 +2034,150 @@ fn writeElfHeader(self: *Elf) !void {...@@ -2033,124 +2034,150 @@ fn writeElfHeader(self: *Elf) !void {
2033 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2034 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
2034}2035}
20352036
2036fn freeTextBlock(self: *Elf, text_block: *TextBlock, phdr_index: u16) void {2037fn freeAtom(self: *Elf, atom_index: Atom.Index) void {
2037 const local_sym = text_block.getSymbol(self);2038 const atom = self.getAtom(atom_index);
2038 const name_str_index = local_sym.st_name;2039 log.debug("freeAtom {d} ({s})", .{ atom_index, atom.getName(self) });
2039 const name = self.getString(name_str_index);
2040 log.debug("freeTextBlock {*} ({s})", .{ text_block, name });
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];
2045 var already_have_free_list_node = false;2046 var already_have_free_list_node = false;
2046 {2047 {
2047 var i: usize = 0;2048 var i: usize = 0;
2048 // TODO turn free_list into a hash map2049 // TODO turn free_list into a hash map
2049 while (i < free_list.items.len) {2050 while (i < free_list.items.len) {
2050 if (free_list.items[i] == text_block) {2051 if (free_list.items[i] == atom_index) {
2051 _ = free_list.swapRemove(i);2052 _ = free_list.swapRemove(i);
2052 continue;2053 continue;
2053 }2054 }
2054 if (free_list.items[i] == text_block.prev) {2055 if (free_list.items[i] == atom.prev_index) {
2055 already_have_free_list_node = true;2056 already_have_free_list_node = true;
2056 }2057 }
2057 i += 1;2058 i += 1;
2058 }2059 }
2059 }2060 }
20602061
2061 if (self.atoms.getPtr(phdr_index)) |last_block| {2062 const maybe_last_atom_index = &self.sections.items(.last_atom_index)[shndx];
2062 if (last_block.* == text_block) {2063 if (maybe_last_atom_index.*) |last_atom_index| {
2063 if (text_block.prev) |prev| {2064 if (last_atom_index == atom_index) {
2065 if (atom.prev_index) |prev_index| {
2064 // TODO shrink the section size here2066 // TODO shrink the section size here
2065 last_block.* = prev;2067 maybe_last_atom_index.* = prev_index;
2066 } else {2068 } else {
2067 _ = self.atoms.fetchRemove(phdr_index);2069 maybe_last_atom_index.* = null;
2068 }2070 }
2069 }2071 }
2070 }2072 }
20712073
2072 if (text_block.prev) |prev| {2074 if (atom.prev_index) |prev_index| {
2073 prev.next = text_block.next;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)) {
2076 // The free list is heuristics, it doesn't have to be perfect, so we can2079 // The free list is heuristics, it doesn't have to be perfect, so we can
2077 // ignore the OOM here.2080 // ignore the OOM here.
2078 free_list.append(self.base.allocator, prev) catch {};2081 free_list.append(gpa, prev_index) catch {};
2079 }2082 }
2080 } else {2083 } else {
2081 text_block.prev = null;2084 self.getAtomPtr(atom_index).prev_index = null;
2082 }2085 }
20832086
2084 if (text_block.next) |next| {2087 if (atom.next_index) |next_index| {
2085 next.prev = text_block.prev;2088 self.getAtomPtr(next_index).prev_index = atom.prev_index;
2086 } else {2089 } else {
2087 text_block.next = null;2090 self.getAtomPtr(atom_index).next_index = null;
2088 }2091 }
20892092
2090 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.2093 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
2091 const local_sym_index = text_block.getSymbolIndex().?;2094 const local_sym_index = atom.getSymbolIndex().?;
2092 self.local_symbol_free_list.append(self.base.allocator, local_sym_index) catch {};2095
2096 self.local_symbol_free_list.append(gpa, local_sym_index) catch {};
2093 self.local_symbols.items[local_sym_index].st_info = 0;2097 self.local_symbols.items[local_sym_index].st_info = 0;
2098 self.local_symbols.items[local_sym_index].st_shndx = 0;
2094 _ = self.atom_by_index_table.remove(local_sym_index);2099 _ = 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| {2104 // if (self.dwarf) |*dw| {
2100 dw.freeAtom(&text_block.dbg_info_atom);2105 // dw.freeAtom(&atom.dbg_info_atom);
2101 }2106 // }
2102}2107}
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 {
2105 _ = self;2110 _ = self;
2106 _ = text_block;2111 _ = atom_index;
2107 _ = new_block_size;2112 _ = new_block_size;
2108 _ = phdr_index;
2109}2113}
21102114
2111fn growTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2115fn growAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2112 const sym = text_block.getSymbol(self);2116 const atom = self.getAtom(atom_index);
2117 const sym = atom.getSymbol(self);
2113 const align_ok = mem.alignBackwardGeneric(u64, sym.st_value, alignment) == sym.st_value;2118 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);
2115 if (!need_realloc) return sym.st_value;2120 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;
2117}2140}
21182141
2119fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, alignment: u64, phdr_index: u16) !u64 {2142fn allocateAtom(self: *Elf, atom_index: Atom.Index, new_block_size: u64, alignment: u64) !u64 {
2120 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;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];
2121 const phdr = &self.program_headers.items[phdr_index];2146 const phdr = &self.program_headers.items[phdr_index];
2122 const shdr = &self.sections.items[shdr_index];2147 const shdr = &self.sections.items(.shdr)[sym.st_shndx];
2123 const new_block_ideal_capacity = padToIdeal(new_block_size);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,
2126 // and possibly removing a free list node.2153 // and possibly removing a free list node.
2127 // It would be simpler to do it inside the for loop below, but that would cause a2154 // It would be simpler to do it inside the for loop below, but that would cause a
2128 // problem if an error was returned later in the function. So this action2155 // problem if an error was returned later in the function. So this action
2129 // is actually carried out at the end of the function, when errors are no longer possible.2156 // 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;
2131 var free_list_removal: ?usize = null;2158 var free_list_removal: ?usize = null;
2132 var free_list = self.atom_free_lists.get(phdr_index).?;
21332159
2134 // First we look for an appropriately sized free list node.2160 // First we look for an appropriately sized free list node.
2135 // The list is unordered. We'll just take the first thing that works.2161 // The list is unordered. We'll just take the first thing that works.
2136 const vaddr = blk: {2162 const vaddr = blk: {
2137 var i: usize = 0;2163 var i: usize = 0;
2138 while (i < free_list.items.len) {2164 while (i < free_list.items.len) {
2139 const big_block = free_list.items[i];2165 const big_atom_index = free_list.items[i];
2140 // We now have a pointer to a live text block that has too much capacity.2166 const big_atom = self.getAtom(big_atom_index);
2141 // Is it enough that we could fit this new text block?2167 // We now have a pointer to a live atom that has too much capacity.
2142 const sym = big_block.getSymbol(self);2168 // Is it enough that we could fit this new atom?
2143 const capacity = big_block.capacity(self);2169 const big_atom_sym = big_atom.getSymbol(self);
2170 const capacity = big_atom.capacity(self);
2144 const ideal_capacity = padToIdeal(capacity);2171 const ideal_capacity = padToIdeal(capacity);
2145 const ideal_capacity_end_vaddr = std.math.add(u64, sym.st_value, ideal_capacity) catch ideal_capacity;2172 const ideal_capacity_end_vaddr = std.math.add(u64, big_atom_sym.st_value, ideal_capacity) catch ideal_capacity;
2146 const capacity_end_vaddr = sym.st_value + capacity;2173 const capacity_end_vaddr = big_atom_sym.st_value + capacity;
2147 const new_start_vaddr_unaligned = capacity_end_vaddr - new_block_ideal_capacity;2174 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
2148 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);2175 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
2149 if (new_start_vaddr < ideal_capacity_end_vaddr) {2176 if (new_start_vaddr < ideal_capacity_end_vaddr) {
2150 // Additional bookkeeping here to notice if this free list node2177 // Additional bookkeeping here to notice if this free list node
2151 // should be deleted because the block that it points to has grown to take up2178 // should be deleted because the block that it points to has grown to take up
2152 // more of the extra capacity.2179 // more of the extra capacity.
2153 if (!big_block.freeListEligible(self)) {2180 if (!big_atom.freeListEligible(self)) {
2154 _ = free_list.swapRemove(i);2181 _ = free_list.swapRemove(i);
2155 } else {2182 } else {
2156 i += 1;2183 i += 1;
...@@ -2164,60 +2191,69 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al...@@ -2164,60 +2191,69 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al
2164 const keep_free_list_node = remaining_capacity >= min_text_capacity;2191 const keep_free_list_node = remaining_capacity >= min_text_capacity;
21652192
2166 // Set up the metadata to be updated, after errors are no longer possible.2193 // Set up the metadata to be updated, after errors are no longer possible.
2167 block_placement = big_block;2194 atom_placement = big_atom_index;
2168 if (!keep_free_list_node) {2195 if (!keep_free_list_node) {
2169 free_list_removal = i;2196 free_list_removal = i;
2170 }2197 }
2171 break :blk new_start_vaddr;2198 break :blk new_start_vaddr;
2172 } else if (self.atoms.get(phdr_index)) |last| {2199 } else if (maybe_last_atom_index.*) |last_index| {
2173 const sym = last.getSymbol(self);2200 const last = self.getAtom(last_index);
2174 const ideal_capacity = padToIdeal(sym.st_size);2201 const last_sym = last.getSymbol(self);
2175 const ideal_capacity_end_vaddr = sym.st_value + ideal_capacity;2202 const ideal_capacity = padToIdeal(last_sym.st_size);
2203 const ideal_capacity_end_vaddr = last_sym.st_value + ideal_capacity;
2176 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);2204 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
2177 // Set up the metadata to be updated, after errors are no longer possible.2205 // Set up the metadata to be updated, after errors are no longer possible.
2178 block_placement = last;2206 atom_placement = last_index;
2179 break :blk new_start_vaddr;2207 break :blk new_start_vaddr;
2180 } else {2208 } else {
2181 break :blk phdr.p_vaddr;2209 break :blk phdr.p_vaddr;
2182 }2210 }
2183 };2211 };
21842212
2185 const expand_text_section = block_placement == null or block_placement.?.next == null;2213 const expand_section = if (atom_placement) |placement_index|
2186 if (expand_text_section) {2214 self.getAtom(placement_index).next_index == null
2215 else
2216 true;
2217 if (expand_section) {
2187 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;2218 const needed_size = (vaddr + new_block_size) - phdr.p_vaddr;
2188 try self.growAllocSection(shdr_index, phdr_index, needed_size);2219 try self.growAllocSection(sym.st_shndx, needed_size);
2189 _ = try self.atoms.put(self.base.allocator, phdr_index, text_block);2220 maybe_last_atom_index.* = atom_index;
21902221
2191 if (self.dwarf) |_| {2222 // if (self.dwarf) |_| {
2192 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address2223 // // 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,2224 // // 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.2225 // // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
2195 self.debug_info_header_dirty = true;2226 // self.debug_info_header_dirty = true;
2196 // This becomes dirty for the same reason. We could potentially make this more2227 // // 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 to2228 // // fine-grained with the addition of support for more compilation units. It is planned to
2198 // model each package as a different compilation unit.2229 // // model each package as a different compilation unit.
2199 self.debug_aranges_section_dirty = true;2230 // self.debug_aranges_section_dirty = true;
2200 }2231 // }
2201 }2232 }
2202 shdr.sh_addralign = math.max(shdr.sh_addralign, alignment);2233 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.
2205 // In this case we need to "unplug" it from its previous location before2236 // In this case we need to "unplug" it from its previous location before
2206 // plugging it in to its new location.2237 // plugging it in to its new location.
2207 if (text_block.prev) |prev| {2238 if (atom.prev_index) |prev_index| {
2208 prev.next = text_block.next;2239 const prev = self.getAtomPtr(prev_index);
2240 prev.next_index = atom.next_index;
2209 }2241 }
2210 if (text_block.next) |next| {2242 if (atom.next_index) |next_index| {
2211 next.prev = text_block.prev;2243 const next = self.getAtomPtr(next_index);
2244 next.prev_index = atom.prev_index;
2212 }2245 }
22132246
2214 if (block_placement) |big_block| {2247 if (atom_placement) |big_atom_index| {
2215 text_block.prev = big_block;2248 const big_atom = self.getAtomPtr(big_atom_index);
2216 text_block.next = big_block.next;2249 const atom_ptr = self.getAtomPtr(atom_index);
2217 big_block.next = text_block;2250 atom_ptr.prev_index = big_atom_index;
2251 atom_ptr.next_index = big_atom.next_index;
2252 big_atom.next_index = atom_index;
2218 } else {2253 } else {
2219 text_block.prev = null;2254 const atom_ptr = self.getAtomPtr(atom_index);
2220 text_block.next = null;2255 atom_ptr.prev_index = null;
2256 atom_ptr.next_index = null;
2221 }2257 }
2222 if (free_list_removal) |i| {2258 if (free_list_removal) |i| {
2223 _ = free_list.swapRemove(i);2259 _ = free_list.swapRemove(i);
...@@ -2272,15 +2308,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {...@@ -2272,15 +2308,10 @@ pub fn allocateGotOffset(self: *Elf) !u32 {
2272 return index;2308 return index;
2273}2309}
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
2280fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {2311fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
2281 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;2312 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl_index) orelse return;
2282 for (unnamed_consts.items) |atom| {2313 for (unnamed_consts.items) |atom| {
2283 self.freeTextBlock(atom, self.phdr_load_ro_index.?);2314 self.freeAtom(atom);
2284 }2315 }
2285 unnamed_consts.clearAndFree(self.base.allocator);2316 unnamed_consts.clearAndFree(self.base.allocator);
2286}2317}
...@@ -2295,43 +2326,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {...@@ -2295,43 +2326,57 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
22952326
2296 log.debug("freeDecl {*}", .{decl});2327 log.debug("freeDecl {*}", .{decl});
22972328
2298 if (self.decls.fetchRemove(decl_index)) |kv| {2329 if (self.decls.fetchRemove(decl_index)) |const_kv| {
2299 if (kv.value) |index| {2330 var kv = const_kv;
2300 self.freeTextBlock(&decl.link.elf, index);2331 self.freeAtom(kv.value.atom);
2301 self.freeUnnamedConsts(decl_index);2332 self.freeUnnamedConsts(decl_index);
2302 }2333 kv.value.exports.deinit(self.base.allocator);
2303 }2334 }
23042335
2305 if (self.dwarf) |*dw| {2336 // if (self.dwarf) |*dw| {
2306 dw.freeDecl(decl);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 };
2307 }2349 }
2350 return gop.value_ptr.atom;
2308}2351}
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);
2311 const ty = decl.ty;2355 const ty = decl.ty;
2312 const zig_ty = ty.zigTypeTag();2356 const zig_ty = ty.zigTypeTag();
2313 const val = decl.val;2357 const val = decl.val;
2314 const phdr_index: u16 = blk: {2358 const shdr_index: u16 = blk: {
2315 if (val.isUndefDeep()) {2359 if (val.isUndefDeep()) {
2316 // TODO in release-fast and release-small, we should put undef in .bss2360 // 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.?;
2318 }2362 }
23192363
2320 switch (zig_ty) {2364 switch (zig_ty) {
2321 // TODO: what if this is a function pointer?2365 // 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.?,
2323 else => {2367 else => {
2324 if (val.castTag(.variable)) |_| {2368 if (val.castTag(.variable)) |_| {
2325 break :blk self.phdr_load_rw_index.?;2369 break :blk self.data_section_index.?;
2326 }2370 }
2327 break :blk self.phdr_load_ro_index.?;2371 break :blk self.rodata_section_index.?;
2328 },2372 },
2329 }2373 }
2330 };2374 };
2331 return phdr_index;2375 return shdr_index;
2332}2376}
23332377
2334fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {2378fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, stt_bits: u8) !*elf.Elf64_Sym {
2379 const gpa = self.base.allocator;
2335 const mod = self.base.options.module.?;2380 const mod = self.base.options.module.?;
2336 const decl = mod.declPtr(decl_index);2381 const decl = mod.declPtr(decl_index);
23372382
...@@ -2341,60 +2386,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s...@@ -2341,60 +2386,65 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s
2341 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });2386 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
2342 const required_alignment = decl.getAlignment(self.base.options.target);2387 const required_alignment = decl.getAlignment(self.base.options.target);
23432388
2344 const decl_ptr = self.decls.getPtr(decl_index).?;2389 const decl_metadata = self.decls.get(decl_index).?;
2345 if (decl_ptr.* == null) {2390 const atom_index = decl_metadata.atom;
2346 decl_ptr.* = try self.getDeclPhdrIndex(decl);2391 const atom = self.getAtom(atom_index);
2347 }2392
2348 const phdr_index = decl_ptr.*.?;2393 const shdr_index = decl_metadata.shdr;
2349 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;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);2401 const capacity = atom.capacity(self);
2352 if (local_sym.st_size != 0) {
2353 const capacity = decl.link.elf.capacity(self);
2354 const need_realloc = code.len > capacity or2402 const need_realloc = code.len > capacity or
2355 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);2403 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
2404
2356 if (need_realloc) {2405 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);
2358 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });2407 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, local_sym.st_value, vaddr });
2359 if (vaddr != local_sym.st_value) {2408 if (vaddr != local_sym.st_value) {
2360 local_sym.st_value = vaddr;2409 local_sym.st_value = vaddr;
23612410
2362 log.debug(" (writing new offset table entry)", .{});2411 log.debug(" (writing new offset table entry)", .{});
2363 self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;2412 self.offset_table.items[atom.offset_table_index] = vaddr;
2364 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);2413 try self.writeOffsetTableEntry(atom.offset_table_index);
2365 }2414 }
2366 } else if (code.len < local_sym.st_size) {2415 } 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);
2368 }2417 }
2369 local_sym.st_size = code.len;2418 local_sym.st_size = code.len;
2370 local_sym.st_name = try self.updateString(local_sym.st_name, decl_name);2419
2371 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
2372 local_sym.st_other = 0;
2373 local_sym.st_shndx = shdr_index;
2374 // TODO this write could be avoided if no fields of the symbol were changed.2420 // 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().?);
2376 } else {2422 } else {
2377 const name_str_index = try self.makeString(decl_name);2423 const local_sym = atom.getSymbolPtr(self);
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
2382 local_sym.* = .{2424 local_sym.* = .{
2383 .st_name = name_str_index,2425 .st_name = try self.shstrtab.insert(gpa, decl_name),
2384 .st_info = (elf.STB_LOCAL << 4) | stt_bits,2426 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
2385 .st_other = 0,2427 .st_other = 0,
2386 .st_shndx = shdr_index,2428 .st_shndx = shdr_index,
2387 .st_value = vaddr,2429 .st_value = 0,
2388 .st_size = code.len,2430 .st_size = 0,
2389 };2431 };
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().?);2436 self.offset_table.items[atom.offset_table_index] = vaddr;
2393 try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);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);
2394 }2442 }
23952443
2444 const local_sym = atom.getSymbolPtr(self);
2445 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
2396 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2446 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;
2398 try self.base.file.?.pwriteAll(code, file_offset);2448 try self.base.file.?.pwriteAll(code, file_offset);
23992449
2400 return local_sym;2450 return local_sym;
...@@ -2413,28 +2463,23 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2413,28 +2463,23 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
24132463
2414 const decl_index = func.owner_decl;2464 const decl_index = func.owner_decl;
2415 const decl = module.declPtr(decl_index);2465 const decl = module.declPtr(decl_index);
2416 const atom = &decl.link.elf;2466
2417 try atom.ensureInitialized(self);2467 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2418 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);2468 self.freeUnnamedConsts(decl_index);
2419 if (gop.found_existing) {2469 Atom.freeRelocations(self, atom_index);
2420 self.freeUnnamedConsts(decl_index);
2421 self.freeRelocationsForTextBlock(atom);
2422 } else {
2423 gop.value_ptr.* = null;
2424 }
24252470
2426 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2471 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2427 defer code_buffer.deinit();2472 defer code_buffer.deinit();
24282473
2429 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;2474 // 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();2475 // defer if (decl_state) |*ds| ds.deinit();
24312476
2432 const res = if (decl_state) |*ds|2477 // const res = if (decl_state) |*ds|
2433 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{2478 // try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
2434 .dwarf = ds,2479 // .dwarf = ds,
2435 })2480 // })
2436 else2481 // else
2437 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);2482 const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .none);
24382483
2439 const code = switch (res) {2484 const code = switch (res) {
2440 .ok => code_buffer.items,2485 .ok => code_buffer.items,
...@@ -2445,15 +2490,16 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven...@@ -2445,15 +2490,16 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven
2445 },2490 },
2446 };2491 };
2447 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);2492 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_FUNC);
2448 if (decl_state) |*ds| {2493 _ = local_sym;
2449 try self.dwarf.?.commitDeclState(2494 // if (decl_state) |*ds| {
2450 module,2495 // try self.dwarf.?.commitDeclState(
2451 decl_index,2496 // module,
2452 local_sym.st_value,2497 // decl_index,
2453 local_sym.st_size,2498 // local_sym.st_value,
2454 ds,2499 // local_sym.st_size,
2455 );2500 // ds,
2456 }2501 // );
2502 // }
24572503
2458 // Since we updated the vaddr and the size, each corresponding export2504 // Since we updated the vaddr and the size, each corresponding export
2459 // symbol also needs to be updated.2505 // symbol also needs to be updated.
...@@ -2483,41 +2529,34 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2483,41 +2529,34 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2483 }2529 }
2484 }2530 }
24852531
2486 assert(!self.unnamed_const_atoms.contains(decl_index));2532 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
24872533 Atom.freeRelocations(self, atom_index);
2488 const atom = &decl.link.elf;2534 const atom = self.getAtom(atom_index);
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 }
24962535
2497 var code_buffer = std.ArrayList(u8).init(self.base.allocator);2536 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
2498 defer code_buffer.deinit();2537 defer code_buffer.deinit();
24992538
2500 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(module, decl_index) else null;2539 // 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();2540 // defer if (decl_state) |*ds| ds.deinit();
25022541
2503 // TODO implement .debug_info for global variables2542 // TODO implement .debug_info for global variables
2504 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;2543 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2505 const res = if (decl_state) |*ds|2544 // const res = if (decl_state) |*ds|
2506 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2545 // try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2507 .ty = decl.ty,2546 // .ty = decl.ty,
2508 .val = decl_val,2547 // .val = decl_val,
2509 }, &code_buffer, .{2548 // }, &code_buffer, .{
2510 .dwarf = ds,2549 // .dwarf = ds,
2511 }, .{2550 // }, .{
2512 .parent_atom_index = decl.link.elf.getSymbolIndex().?,2551 // .parent_atom_index = atom.getSymbolIndex().?,
2513 })2552 // })
2514 else2553 // else
2515 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{2554 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
2516 .ty = decl.ty,2555 .ty = decl.ty,
2517 .val = decl_val,2556 .val = decl_val,
2518 }, &code_buffer, .none, .{2557 }, &code_buffer, .none, .{
2519 .parent_atom_index = decl.link.elf.getSymbolIndex().?,2558 .parent_atom_index = atom.getSymbolIndex().?,
2520 });2559 });
25212560
2522 const code = switch (res) {2561 const code = switch (res) {
2523 .ok => code_buffer.items,2562 .ok => code_buffer.items,
...@@ -2529,15 +2568,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2529,15 +2568,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2529 };2568 };
25302569
2531 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);2570 const local_sym = try self.updateDeclCode(decl_index, code, elf.STT_OBJECT);
2532 if (decl_state) |*ds| {2571 _ = local_sym;
2533 try self.dwarf.?.commitDeclState(2572 // if (decl_state) |*ds| {
2534 module,2573 // try self.dwarf.?.commitDeclState(
2535 decl_index,2574 // module,
2536 local_sym.st_value,2575 // decl_index,
2537 local_sym.st_size,2576 // local_sym.st_value,
2538 ds,2577 // local_sym.st_size,
2539 );2578 // ds,
2540 }2579 // );
2580 // }
25412581
2542 // Since we updated the vaddr and the size, each corresponding export2582 // Since we updated the vaddr and the size, each corresponding export
2543 // symbol also needs to be updated.2583 // symbol also needs to be updated.
...@@ -2545,36 +2585,31 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v...@@ -2545,36 +2585,31 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
2545}2585}
25462586
2547pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2587pub 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);
2549 defer code_buffer.deinit();2591 defer code_buffer.deinit();
25502592
2551 const mod = self.base.options.module.?;2593 const mod = self.base.options.module.?;
2552 const decl = mod.declPtr(decl_index);2594 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
2553
2554 const gop = try self.unnamed_const_atoms.getOrPut(self.base.allocator, decl_index);
2555 if (!gop.found_existing) {2595 if (!gop.found_existing) {
2556 gop.value_ptr.* = .{};2596 gop.value_ptr.* = .{};
2557 }2597 }
2558 const unnamed_consts = gop.value_ptr;2598 const unnamed_consts = gop.value_ptr;
25592599
2560 const atom = try self.base.allocator.create(TextBlock);2600 const decl = mod.declPtr(decl_index);
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
2567 const name_str_index = blk: {2601 const name_str_index = blk: {
2568 const decl_name = try decl.getFullyQualifiedName(mod);2602 const decl_name = try decl.getFullyQualifiedName(mod);
2569 defer self.base.allocator.free(decl_name);2603 defer gpa.free(decl_name);
2570
2571 const index = unnamed_consts.items.len;2604 const index = unnamed_consts.items.len;
2572 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl_name, index });2605 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
2573 defer self.base.allocator.free(name);2606 defer gpa.free(name);
25742607 break :blk try self.shstrtab.insert(gpa, name);
2575 break :blk try self.makeString(name);
2576 };2608 };
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
2579 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{2614 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
2580 .none = {},2615 .none = {},
...@@ -2592,28 +2627,24 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2592,28 +2627,24 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2592 };2627 };
25932628
2594 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);2629 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
2595 const phdr_index = self.phdr_load_ro_index.?;2630 const shdr_index = self.rodata_section_index.?;
2596 const shdr_index = self.phdr_shdr_table.get(phdr_index).?;2631 const phdr_index = self.sections.items(.phdr_index)[shdr_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
2602 const local_sym = atom.getSymbolPtr(self);2632 const local_sym = atom.getSymbolPtr(self);
2603 local_sym.* = .{2633 local_sym.st_name = name_str_index;
2604 .st_name = name_str_index,2634 local_sym.st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT;
2605 .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,2635 local_sym.st_other = 0;
2606 .st_other = 0,2636 local_sym.st_shndx = shdr_index;
2607 .st_shndx = shdr_index,2637 local_sym.st_size = code.len;
2608 .st_value = vaddr,2638 local_sym.st_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2609 .st_size = code.len,2639 errdefer self.freeAtom(atom_index);
2610 };2640
2641 log.debug("allocated text block for {s} at 0x{x}", .{ name, local_sym.st_value });
26112642
2612 try self.writeSymbol(atom.getSymbolIndex().?);2643 try self.writeSymbol(atom.getSymbolIndex().?);
2613 try unnamed_consts.append(self.base.allocator, atom);2644 try unnamed_consts.append(gpa, atom_index);
26142645
2615 const section_offset = local_sym.st_value - self.program_headers.items[phdr_index].p_vaddr;2646 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;
2617 try self.base.file.?.pwriteAll(code, file_offset);2648 try self.base.file.?.pwriteAll(code, file_offset);
26182649
2619 return atom.getSymbolIndex().?;2650 return atom.getSymbolIndex().?;
...@@ -2635,20 +2666,16 @@ pub fn updateDeclExports(...@@ -2635,20 +2666,16 @@ pub fn updateDeclExports(
2635 const tracy = trace(@src());2666 const tracy = trace(@src());
2636 defer tracy.end();2667 defer tracy.end();
26372668
2638 const decl = module.declPtr(decl_index);2669 const gpa = self.base.allocator;
2639 const atom = &decl.link.elf;
2640
2641 if (atom.getSymbolIndex() == null) return;
26422670
2671 const decl = module.declPtr(decl_index);
2672 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2673 const atom = self.getAtom(atom_index);
2643 const decl_sym = atom.getSymbol(self);2674 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);2678 try self.global_symbols.ensureUnusedCapacity(gpa, exports.len);
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).?;
26522679
2653 for (exports) |exp| {2680 for (exports) |exp| {
2654 if (exp.options.section) |section_name| {2681 if (exp.options.section) |section_name| {
...@@ -2681,10 +2708,10 @@ pub fn updateDeclExports(...@@ -2681,10 +2708,10 @@ pub fn updateDeclExports(
2681 },2708 },
2682 };2709 };
2683 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);2710 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| {
2685 const sym = &self.global_symbols.items[i];2712 const sym = &self.global_symbols.items[i];
2686 sym.* = .{2713 sym.* = .{
2687 .st_name = try self.updateString(sym.st_name, exp.options.name),2714 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
2688 .st_info = (stb_bits << 4) | stt_bits,2715 .st_info = (stb_bits << 4) | stt_bits,
2689 .st_other = 0,2716 .st_other = 0,
2690 .st_shndx = shdr_index,2717 .st_shndx = shdr_index,
...@@ -2692,21 +2719,19 @@ pub fn updateDeclExports(...@@ -2692,21 +2719,19 @@ pub fn updateDeclExports(
2692 .st_size = decl_sym.st_size,2719 .st_size = decl_sym.st_size,
2693 };2720 };
2694 } else {2721 } else {
2695 const name = try self.makeString(exp.options.name);
2696 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {2722 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
2697 _ = self.global_symbols.addOneAssumeCapacity();2723 _ = self.global_symbols.addOneAssumeCapacity();
2698 break :blk self.global_symbols.items.len - 1;2724 break :blk self.global_symbols.items.len - 1;
2699 };2725 };
2726 try decl_metadata.exports.append(gpa, @intCast(u32, i));
2700 self.global_symbols.items[i] = .{2727 self.global_symbols.items[i] = .{
2701 .st_name = name,2728 .st_name = try self.shstrtab.insert(gpa, exp.options.name),
2702 .st_info = (stb_bits << 4) | stt_bits,2729 .st_info = (stb_bits << 4) | stt_bits,
2703 .st_other = 0,2730 .st_other = 0,
2704 .st_shndx = shdr_index,2731 .st_shndx = shdr_index,
2705 .st_value = decl_sym.st_value,2732 .st_value = decl_sym.st_value,
2706 .st_size = decl_sym.st_size,2733 .st_size = decl_sym.st_size,
2707 };2734 };
2708
2709 exp.link.elf.sym_index = @intCast(u32, i);
2710 }2735 }
2711 }2736 }
2712}2737}
...@@ -2722,17 +2747,19 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)...@@ -2722,17 +2747,19 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl: *const Module.Decl)
2722 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });2747 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
27232748
2724 if (self.llvm_object) |_| return;2749 if (self.llvm_object) |_| return;
2725 if (self.dwarf) |*dw| {2750 // if (self.dwarf) |*dw| {
2726 try dw.updateDeclLineNumber(decl);2751 // try dw.updateDeclLineNumber(decl);
2727 }2752 // }
2728}2753}
27292754
2730pub fn deleteExport(self: *Elf, exp: Export) void {2755pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void {
2731 if (self.llvm_object) |_| return;2756 if (self.llvm_object) |_| return;
27322757 const metadata = self.decls.getPtr(decl_index) orelse return;
2733 const sym_index = exp.sym_index orelse return;2758 const sym_index = metadata.getExportPtr(self, name) orelse return;
2734 self.global_symbol_free_list.append(self.base.allocator, sym_index) catch {};2759 log.debug("deleting export '{s}'", .{name});
2735 self.global_symbols.items[sym_index].st_info = 0;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;
2736}2763}
27372764
2738fn writeProgHeader(self: *Elf, index: usize) !void {2765fn writeProgHeader(self: *Elf, index: usize) !void {
...@@ -2761,7 +2788,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2761,7 +2788,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2761 switch (self.ptr_width) {2788 switch (self.ptr_width) {
2762 .p32 => {2789 .p32 => {
2763 var shdr: [1]elf.Elf32_Shdr = undefined;2790 var shdr: [1]elf.Elf32_Shdr = undefined;
2764 shdr[0] = sectHeaderTo32(self.sections.items[index]);2791 shdr[0] = sectHeaderTo32(self.sections.items(.shdr)[index]);
2765 if (foreign_endian) {2792 if (foreign_endian) {
2766 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);2793 mem.byteSwapAllFields(elf.Elf32_Shdr, &shdr[0]);
2767 }2794 }
...@@ -2769,7 +2796,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {...@@ -2769,7 +2796,7 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
2769 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);2796 return self.base.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
2770 },2797 },
2771 .p64 => {2798 .p64 => {
2772 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};2799 var shdr = [1]elf.Elf64_Shdr{self.sections.items(.shdr)[index]};
2773 if (foreign_endian) {2800 if (foreign_endian) {
2774 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);2801 mem.byteSwapAllFields(elf.Elf64_Shdr, &shdr[0]);
2775 }2802 }
...@@ -2783,11 +2810,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {...@@ -2783,11 +2810,11 @@ fn writeOffsetTableEntry(self: *Elf, index: usize) !void {
2783 const entry_size: u16 = self.archPtrWidthBytes();2810 const entry_size: u16 = self.archPtrWidthBytes();
2784 if (self.offset_table_count_dirty) {2811 if (self.offset_table_count_dirty) {
2785 const needed_size = self.offset_table.items.len * entry_size;2812 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);
2787 self.offset_table_count_dirty = false;2814 self.offset_table_count_dirty = false;
2788 }2815 }
2789 const endian = self.base.options.target.cpu.arch.endian();2816 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.?];
2791 const off = shdr.sh_offset + @as(u64, entry_size) * index;2818 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2792 switch (entry_size) {2819 switch (entry_size) {
2793 2 => {2820 2 => {
...@@ -2813,7 +2840,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2813,7 +2840,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2813 const tracy = trace(@src());2840 const tracy = trace(@src());
2814 defer tracy.end();2841 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.?];
2817 // Make sure we are not pointlessly writing symbol data that will have to get relocated2844 // Make sure we are not pointlessly writing symbol data that will have to get relocated
2818 // due to running out of space.2845 // due to running out of space.
2819 if (self.local_symbols.items.len != syms_sect.sh_info) {2846 if (self.local_symbols.items.len != syms_sect.sh_info) {
...@@ -2835,7 +2862,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2835,7 +2862,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2835 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,2862 .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index,
2836 };2863 };
2837 const local = self.local_symbols.items[index];2864 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 });
2839 log.debug(" ({})", .{local});2866 log.debug(" ({})", .{local});
2840 switch (self.ptr_width) {2867 switch (self.ptr_width) {
2841 .p32 => {2868 .p32 => {
...@@ -2865,7 +2892,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {...@@ -2865,7 +2892,7 @@ fn writeSymbol(self: *Elf, index: usize) !void {
2865}2892}
28662893
2867fn writeAllGlobalSymbols(self: *Elf) !void {2894fn 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.?];
2869 const sym_size: u64 = switch (self.ptr_width) {2896 const sym_size: u64 = switch (self.ptr_width) {
2870 .p32 => @sizeOf(elf.Elf32_Sym),2897 .p32 => @sizeOf(elf.Elf32_Sym),
2871 .p64 => @sizeOf(elf.Elf64_Sym),2898 .p64 => @sizeOf(elf.Elf64_Sym),
...@@ -3215,10 +3242,52 @@ const CsuObjects = struct {...@@ -3215,10 +3242,52 @@ const CsuObjects = struct {
3215fn logSymtab(self: Elf) void {3242fn logSymtab(self: Elf) void {
3216 log.debug("locals:", .{});3243 log.debug("locals:", .{});
3217 for (self.local_symbols.items) |sym, id| {3244 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 });
3219 }3246 }
3220 log.debug("globals:", .{});3247 log.debug("globals:", .{});
3221 for (self.global_symbols.items) |sym, id| {3248 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 });
3223 }3250 }
3224}3251}
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,...@@ -20,44 +20,35 @@ offset_table_index: u32,
2020
21/// Points to the previous and next neighbors, based on the `text_offset`.21/// Points to the previous and next neighbors, based on the `text_offset`.
22/// This can be used to find, for example, the capacity of this `TextBlock`.22/// This can be used to find, for example, the capacity of this `TextBlock`.
23prev: ?*Atom,23prev_index: ?Atom.Index,
24next: ?*Atom,24next_index: ?Atom.Index,
2525
26dbg_info_atom: Dwarf.Atom,26dbg_info_atom: Dwarf.Atom,
2727
28pub const empty = Atom{28pub const Index = u32;
29 .local_sym_index = 0,
30 .offset_table_index = undefined,
31 .prev = null,
32 .next = null,
33 .dbg_info_atom = undefined,
34};
3529
36pub fn ensureInitialized(self: *Atom, elf_file: *Elf) !void {30pub const Reloc = struct {
37 if (self.getSymbolIndex() != null) return; // Already initialized31 target: u32,
38 self.local_sym_index = try elf_file.allocateLocalSymbol();32 offset: u64,
39 self.offset_table_index = try elf_file.allocateGotOffset();33 addend: u32,
40 try elf_file.atom_by_index_table.putNoClobber(elf_file.base.allocator, self.local_sym_index, self);34 prev_vaddr: u64,
41}35};
4236
43pub fn getSymbolIndex(self: Atom) ?u32 {37pub fn getSymbolIndex(self: Atom) ?u32 {
44 if (self.local_sym_index == 0) return null;38 if (self.local_sym_index == 0) return null;
45 return self.local_sym_index;39 return self.local_sym_index;
46}40}
4741
48pub fn getSymbol(self: Atom, elf_file: *Elf) elf.Elf64_Sym {42pub fn getSymbol(self: Atom, elf_file: *const Elf) elf.Elf64_Sym {
49 const sym_index = self.getSymbolIndex().?;43 return elf_file.getSymbol(self.getSymbolIndex().?);
50 return elf_file.local_symbols.items[sym_index];
51}44}
5245
53pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {46pub fn getSymbolPtr(self: Atom, elf_file: *Elf) *elf.Elf64_Sym {
54 const sym_index = self.getSymbolIndex().?;47 return elf_file.getSymbolPtr(self.getSymbolIndex().?);
55 return &elf_file.local_symbols.items[sym_index];
56}48}
5749
58pub fn getName(self: Atom, elf_file: *Elf) []const u8 {50pub fn getName(self: Atom, elf_file: *const Elf) []const u8 {
59 const sym = self.getSymbol();51 return elf_file.getSymbolName(self.getSymbolIndex().?);
60 return elf_file.getString(sym.st_name);
61}52}
6253
63pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {54pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
...@@ -72,9 +63,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {...@@ -72,9 +63,10 @@ pub fn getOffsetTableAddress(self: Atom, elf_file: *Elf) u64 {
72/// Returns how much room there is to grow in virtual address space.63/// Returns how much room there is to grow in virtual address space.
73/// File offset relocation happens transparently, so it is not included in64/// File offset relocation happens transparently, so it is not included in
74/// this calculation.65/// this calculation.
75pub fn capacity(self: Atom, elf_file: *Elf) u64 {66pub fn capacity(self: Atom, elf_file: *const Elf) u64 {
76 const self_sym = self.getSymbol(elf_file);67 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);
78 const next_sym = next.getSymbol(elf_file);70 const next_sym = next.getSymbol(elf_file);
79 return next_sym.st_value - self_sym.st_value;71 return next_sym.st_value - self_sym.st_value;
80 } else {72 } else {
...@@ -83,9 +75,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {...@@ -83,9 +75,10 @@ pub fn capacity(self: Atom, elf_file: *Elf) u64 {
83 }75 }
84}76}
8577
86pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {78pub fn freeListEligible(self: Atom, elf_file: *const Elf) bool {
87 // No need to keep a free list node for the last block.79 // 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);
89 const self_sym = self.getSymbol(elf_file);82 const self_sym = self.getSymbol(elf_file);
90 const next_sym = next.getSymbol(elf_file);83 const next_sym = next.getSymbol(elf_file);
91 const cap = next_sym.st_value - self_sym.st_value;84 const cap = next_sym.st_value - self_sym.st_value;
...@@ -94,3 +87,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {...@@ -94,3 +87,17 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
94 const surplus = cap - ideal_cap;87 const surplus = cap - ideal_cap;
95 return surplus >= Elf.min_text_capacity;88 return surplus >= Elf.min_text_capacity;
96}89}
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 {...@@ -2604,9 +2604,11 @@ pub fn freeDecl(self: *MachO, decl_index: Module.Decl.Index) void {
26042604
2605 log.debug("freeDecl {*}", .{decl});2605 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;
2608 self.freeAtom(kv.value.atom);2609 self.freeAtom(kv.value.atom);
2609 self.freeUnnamedConsts(decl_index);2610 self.freeUnnamedConsts(decl_index);
2611 kv.value.exports.deinit(self.base.allocator);
2610 }2612 }
26112613
2612 // if (self.d_sym) |*d_sym| {2614 // if (self.d_sym) |*d_sym| {