authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-13 21:49:10+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-13 21:49:10+02:00
log10a99f8f64bf7cf336c990b90c72d81f5f767b4d
treef727de971e0791846821def8b0a22bca75c15c8b
parent4a44b7993573016fb5ccb3398d366a884307bf3a
parent0d924d2da67a34046ea5e78e0a65fd9ef2601c8a
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17141 from ziglang/elf-linker

elf: enable Zig's ELF linker on non-incremental codepaths (LLVM, clang)

1 files changed, 53 insertions(+), 15 deletions(-)

src/link/Elf.zig+53-15
...@@ -164,13 +164,21 @@ pub const PtrWidth = enum { p32, p64 };...@@ -164,13 +164,21 @@ pub const PtrWidth = enum { p32, p64 };
164pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {164pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
165 assert(options.target.ofmt == .elf);165 assert(options.target.ofmt == .elf);
166166
167 if (options.use_llvm) {
168 return createEmpty(allocator, options);
169 }
170
171 const self = try createEmpty(allocator, options);167 const self = try createEmpty(allocator, options);
172 errdefer self.base.destroy();168 errdefer self.base.destroy();
173169
170 if (options.use_llvm) {
171 const use_lld = build_options.have_llvm and self.base.options.use_lld;
172 if (use_lld) return self;
173
174 if (options.module != null) {
175 self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
176 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
177 });
178 }
179 }
180 errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
181
174 self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{182 self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{
175 .truncate = false,183 .truncate = false,
176 .read = true,184 .read = true,
...@@ -389,8 +397,6 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {...@@ -389,8 +397,6 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
389}397}
390398
391pub fn populateMissingMetadata(self: *Elf) !void {399pub fn populateMissingMetadata(self: *Elf) !void {
392 assert(self.llvm_object == null);
393
394 const gpa = self.base.allocator;400 const gpa = self.base.allocator;
395 const small_ptr = switch (self.ptr_width) {401 const small_ptr = switch (self.ptr_width) {
396 .p32 => true,402 .p32 => true,
...@@ -962,7 +968,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {...@@ -962,7 +968,7 @@ pub fn markDirty(self: *Elf, shdr_index: u16, phdr_index: ?u16) void {
962pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {968pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
963 if (self.base.options.emit == null) {969 if (self.base.options.emit == null) {
964 if (self.llvm_object) |llvm_object| {970 if (self.llvm_object) |llvm_object| {
965 return try llvm_object.flushModule(comp, prog_node);971 try llvm_object.flushModule(comp, prog_node);
966 }972 }
967 return;973 return;
968 }974 }
...@@ -981,7 +987,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -981,7 +987,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
981 defer tracy.end();987 defer tracy.end();
982988
983 if (self.llvm_object) |llvm_object| {989 if (self.llvm_object) |llvm_object| {
984 return try llvm_object.flushModule(comp, prog_node);990 try llvm_object.flushModule(comp, prog_node);
991
992 const use_lld = build_options.have_llvm and self.base.options.use_lld;
993 if (use_lld) return;
985 }994 }
986995
987 const gpa = self.base.allocator;996 const gpa = self.base.allocator;
...@@ -989,9 +998,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -989,9 +998,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
989 sub_prog_node.activate();998 sub_prog_node.activate();
990 defer sub_prog_node.end();999 defer sub_prog_node.end();
9911000
992 // TODO This linker code currently assumes there is only 1 compilation unit and it1001 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
993 // corresponds to the Zig source code.1002 defer arena_allocator.deinit();
994 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;1003 const arena = arena_allocator.allocator();
1004
1005 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
1006 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
9951007
996 const compiler_rt_path: ?[]const u8 = blk: {1008 const compiler_rt_path: ?[]const u8 = blk: {
997 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1009 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
...@@ -1002,8 +1014,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1002,8 +1014,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10021014
1003 // Here we will parse input positional and library files (if referenced).1015 // Here we will parse input positional and library files (if referenced).
1004 // This will roughly match in any linker backend we support.1016 // This will roughly match in any linker backend we support.
1005 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);1017 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
1006 defer positionals.deinit();1018
1019 if (self.base.intermediary_basename) |path| {
1020 const full_path = blk: {
1021 if (fs.path.dirname(full_out_path)) |dirname| {
1022 break :blk try fs.path.join(arena, &.{ dirname, path });
1023 } else {
1024 break :blk path;
1025 }
1026 };
1027 try positionals.append(.{ .path = full_path });
1028 }
1029
1007 try positionals.ensureUnusedCapacity(self.base.options.objects.len);1030 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
1008 positionals.appendSliceAssumeCapacity(self.base.options.objects);1031 positionals.appendSliceAssumeCapacity(self.base.options.objects);
10091032
...@@ -1025,6 +1048,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1025,6 +1048,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
10251048
1026 // Handle any lazy symbols that were emitted by incremental compilation.1049 // Handle any lazy symbols that were emitted by incremental compilation.
1027 if (self.lazy_syms.getPtr(.none)) |metadata| {1050 if (self.lazy_syms.getPtr(.none)) |metadata| {
1051 const module = self.base.options.module.?;
1052
1028 // Most lazy symbols can be updated on first use, but1053 // Most lazy symbols can be updated on first use, but
1029 // anyerror needs to wait for everything to be flushed.1054 // anyerror needs to wait for everything to be flushed.
1030 if (metadata.text_state != .unused) self.updateLazySymbol(1055 if (metadata.text_state != .unused) self.updateLazySymbol(
...@@ -1051,7 +1076,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1051,7 +1076,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1051 const foreign_endian = target_endian != builtin.cpu.arch.endian();1076 const foreign_endian = target_endian != builtin.cpu.arch.endian();
10521077
1053 if (self.dwarf) |*dw| {1078 if (self.dwarf) |*dw| {
1054 try dw.flushModule(module);1079 try dw.flushModule(self.base.options.module.?);
1055 }1080 }
10561081
1057 // If we haven't already, create a linker-generated input file comprising of1082 // If we haven't already, create a linker-generated input file comprising of
...@@ -1099,6 +1124,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1099,6 +1124,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1099 }1124 }
1100 try self.writeObjects();1125 try self.writeObjects();
11011126
1127 // Look for entry address in objects if not set by the incremental compiler.
1128 if (self.entry_addr == null) {
1129 const entry: ?[]const u8 = entry: {
1130 if (self.base.options.entry) |entry| break :entry entry;
1131 if (!self.isDynLib()) break :entry "_start";
1132 break :entry null;
1133 };
1134 self.entry_addr = if (entry) |name| entry_addr: {
1135 const global_index = self.globalByName(name) orelse break :entry_addr null;
1136 break :entry_addr self.symbol(global_index).value;
1137 } else null;
1138 }
1139
1102 // Generate and emit the symbol table.1140 // Generate and emit the symbol table.
1103 try self.updateSymtabSize();1141 try self.updateSymtabSize();
1104 try self.writeSymtab();1142 try self.writeSymtab();
...@@ -1125,7 +1163,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1125,7 +1163,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1125 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];1163 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];
1126 const low_pc = text_phdr.p_vaddr;1164 const low_pc = text_phdr.p_vaddr;
1127 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1165 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1128 try dw.writeDbgInfoHeader(module, low_pc, high_pc);1166 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1129 self.debug_info_header_dirty = false;1167 self.debug_info_header_dirty = false;
1130 }1168 }
11311169