aboutsummaryrefslogtreecommitdiff
path: root/src/link/Elf/ZigModule.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-10-17 17:36:40 +0200
committerGitHub <noreply@github.com>2023-10-17 17:36:40 +0200
commiteb5276c94eaab238551fdae9a2e77b0133e31cfb (patch)
treea8040cc914bb1db73b2484087cf81d5f20bab28c /src/link/Elf/ZigModule.zig
parent5039a5db8365413794b0522a51137d3e97d8ba5d (diff)
parent742a130ce55ae776372f99b0724c32a462040caf (diff)
downloadzig-eb5276c94eaab238551fdae9a2e77b0133e31cfb.tar.gz
zig-eb5276c94eaab238551fdae9a2e77b0133e31cfb.zip
Merge pull request #17556 from ziglang/elf-link-zig-proper
elf: port 99% of zld ELF linker to Zig proper
Diffstat (limited to 'src/link/Elf/ZigModule.zig')
-rw-r--r--src/link/Elf/ZigModule.zig46
1 files changed, 36 insertions, 10 deletions
diff --git a/src/link/Elf/ZigModule.zig b/src/link/Elf/ZigModule.zig
index c79680dbf5..4532d7b448 100644
--- a/src/link/Elf/ZigModule.zig
+++ b/src/link/Elf/ZigModule.zig
@@ -13,9 +13,11 @@ local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
-atoms: std.AutoArrayHashMapUnmanaged(Atom.Index, void) = .{},
+atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
+num_dynrelocs: u32 = 0,
+
output_symtab_size: Elf.SymtabSize = .{},
pub fn deinit(self: *ZigModule, allocator: Allocator) void {
@@ -56,7 +58,8 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
const symbol_index = try elf_file.addSymbol();
const esym_index = try self.addLocalEsym(gpa);
- try self.atoms.putNoClobber(gpa, atom_index, {});
+ const shndx = @as(u16, @intCast(self.atoms.items.len));
+ try self.atoms.append(gpa, atom_index);
try self.local_symbols.append(gpa, symbol_index);
const atom_ptr = elf_file.atom(atom_index).?;
@@ -67,10 +70,10 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
symbol_ptr.atom_index = atom_index;
const esym = &self.local_esyms.items[esym_index];
- esym.st_shndx = atom_index;
+ esym.st_shndx = shndx;
symbol_ptr.esym_index = esym_index;
- const relocs_index = @as(Atom.Index, @intCast(self.relocs.items.len));
+ const relocs_index = @as(u16, @intCast(self.relocs.items.len));
const relocs = try self.relocs.addOne(gpa);
relocs.* = .{};
atom_ptr.relocs_section_index = relocs_index;
@@ -78,6 +81,22 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
return symbol_index;
}
+/// TODO actually create fake input shdrs and return that instead.
+pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
+ _ = self;
+ const shdr = shdr: {
+ const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
+ const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
+ var shdr = elf_file.shdrs.items[shndx];
+ shdr.sh_addr = 0;
+ shdr.sh_offset = 0;
+ shdr.sh_size = atom.size;
+ shdr.sh_addralign = atom.alignment.toByteUnits(1);
+ break :shdr shdr;
+ };
+ return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
+}
+
pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000;
@@ -86,7 +105,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
- const atom_index = esym.st_shndx;
+ const atom_index = self.atoms.items[esym.st_shndx];
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
}
@@ -95,7 +114,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
const atom_index = switch (esym.st_shndx) {
elf.SHN_ABS, elf.SHN_COMMON => 0,
- else => esym.st_shndx,
+ else => self.atoms.items[esym.st_shndx],
};
const output_section_index = if (elf_file.atom(atom_index)) |atom|
atom.outputShndx().?
@@ -141,10 +160,12 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
}
pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
- for (self.atoms.keys()) |atom_index| {
+ for (self.atoms.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
- if (try atom.scanRelocsRequiresCode(elf_file)) {
+ const shdr = atom.inputShdr(elf_file);
+ if (shdr.sh_type == elf.SHT_NOBITS) continue;
+ if (atom.scanRelocsRequiresCode(elf_file)) {
// TODO ideally we don't have to fetch the code here.
// Perhaps it would make sense to save the code until flushModule where we
// would free all of generated code?
@@ -272,7 +293,10 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8
const code = try gpa.alloc(u8, size);
errdefer gpa.free(code);
const amt = try elf_file.base.file.?.preadAll(code, file_offset);
- if (amt != code.len) return error.InputOutput;
+ if (amt != code.len) {
+ log.err("fetching code for {s} failed", .{atom.name(elf_file)});
+ return error.InputOutput;
+ }
return code;
}
@@ -324,7 +348,7 @@ fn formatAtoms(
_ = unused_fmt_string;
_ = options;
try writer.writeAll(" atoms\n");
- for (ctx.self.atoms.keys()) |atom_index| {
+ for (ctx.self.atoms.items) |atom_index| {
const atom = ctx.elf_file.atom(atom_index) orelse continue;
try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
}
@@ -333,11 +357,13 @@ fn formatAtoms(
const assert = std.debug.assert;
const std = @import("std");
const elf = std.elf;
+const log = std.log.scoped(.link);
const Allocator = std.mem.Allocator;
const Atom = @import("Atom.zig");
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;
const Module = @import("../../Module.zig");
+const Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");
const ZigModule = @This();