From 5fa90afb646bfba4ca3b23a354ef171708e002e9 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 5 Oct 2023 21:11:44 +0200 Subject: [PATCH] elf: fix synthetic section handling and actually parse DSOs --- src/link/Elf.zig | 69 ++++++++++++++++++++++------- src/link/Elf/Object.zig | 2 +- src/link/Elf/SharedObject.zig | 3 +- src/link/Elf/synthetic_sections.zig | 10 ++++- 4 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d54ec0a12e..6915886c14 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1678,6 +1678,8 @@ fn parseLibrary( if (Archive.isArchive(in_file)) { try self.parseArchive(in_file, lib.path, must_link, ctx); + } else if (SharedObject.isSharedObject(in_file)) { + try self.parseSharedObject(in_file, lib, ctx); } else return error.UnknownFileType; } @@ -1732,6 +1734,34 @@ fn parseArchive( } } +fn parseSharedObject( + self: *Elf, + in_file: std.fs.File, + lib: SystemLib, + ctx: *ParseErrorCtx, +) ParseError!void { + const tracy = trace(@src()); + defer tracy.end(); + + const gpa = self.base.allocator; + const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32)); + const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); + self.files.set(index, .{ .shared_object = .{ + .path = lib.path, + .data = data, + .index = index, + .needed = lib.needed, + .alive = lib.needed, + } }); + try self.shared_objects.append(gpa, index); + + const shared_object = self.file(index).?.shared_object; + try shared_object.parse(self); + + ctx.detected_cpu_arch = shared_object.header.?.e_machine.toTargetCpuArch().?; + if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch; +} + /// When resolving symbols, we approach the problem similarly to `mold`. /// 1. Resolve symbols across all objects (including those preemptively extracted archives). /// 2. Resolve symbols across all shared objects. @@ -3437,23 +3467,23 @@ fn addLinkerDefinedSymbols(self: *Elf) !void { self.rela_iplt_start_index = try linker_defined.addGlobal("__rela_iplt_start", self); self.rela_iplt_end_index = try linker_defined.addGlobal("__rela_iplt_end", self); - // for (self.objects.items) |index| { - // const object = self.getFile(index).?.object; - // for (object.atoms.items) |atom_index| { - // if (self.getStartStopBasename(atom_index)) |name| { - // const gpa = self.base.allocator; - // try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2); + for (self.objects.items) |index| { + const object = self.file(index).?.object; + for (object.atoms.items) |atom_index| { + if (self.getStartStopBasename(atom_index)) |name| { + const gpa = self.base.allocator; + try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2); - // const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); - // defer gpa.free(start); - // const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); - // defer gpa.free(stop); + const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name}); + defer gpa.free(start); + const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name}); + defer gpa.free(stop); - // self.start_stop_indexes.appendAssumeCapacity(try internal.addSyntheticGlobal(start, self)); - // self.start_stop_indexes.appendAssumeCapacity(try internal.addSyntheticGlobal(stop, self)); - // } - // } - // } + self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(start, self)); + self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(stop, self)); + } + } + } linker_defined.resolveSymbols(self); } @@ -5199,6 +5229,15 @@ pub fn isCIdentifier(name: []const u8) bool { return true; } +fn getStartStopBasename(self: *Elf, atom_index: Atom.Index) ?[]const u8 { + const atom_ptr = self.atom(atom_index) orelse return null; + const name = atom_ptr.name(self); + if (atom_ptr.inputShdr(self).sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) { + if (isCIdentifier(name)) return name; + } + return null; +} + pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom { if (atom_index == 0) return null; assert(atom_index < self.atoms.items.len); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index dede48896e..6b464ff050 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -970,7 +970,7 @@ pub const ElfShdr = struct { sh_addralign: u64, sh_entsize: u64, - fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr { + pub fn fromElf64Shdr(shdr: elf.Elf64_Shdr) error{Overflow}!ElfShdr { return .{ .sh_name = shdr.sh_name, .sh_type = shdr.sh_type, diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig index d4e3c6f505..1bb46c839b 100644 --- a/src/link/Elf/SharedObject.zig +++ b/src/link/Elf/SharedObject.zig @@ -33,6 +33,7 @@ pub fn isSharedObject(file: std.fs.File) bool { } pub fn deinit(self: *SharedObject, allocator: Allocator) void { + allocator.free(self.data); self.versyms.deinit(allocator); self.verstrings.deinit(allocator); self.symbols.deinit(allocator); @@ -139,7 +140,7 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf) !void { defer gpa.free(full_name); break :blk try elf_file.strtab.insert(gpa, full_name); } else try elf_file.strtab.insert(gpa, name); - const gop = try elf_file.getOrCreateGlobal(off); + const gop = try elf_file.getOrPutGlobal(off); self.symbols.addOneAssumeCapacity().* = gop.index; } } diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index de87dd5743..0fe05d1f42 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -284,8 +284,12 @@ pub const GotSection = struct { entry.tag = .got; entry.symbol_index = sym_index; const symbol = elf_file.symbol(sym_index); - if (symbol.flags.import or symbol.isIFunc(elf_file) or (elf_file.base.options.pic and !symbol.isAbs(elf_file))) + symbol.flags.has_got = true; + if (symbol.flags.import or symbol.isIFunc(elf_file) or + (elf_file.base.options.pic and !symbol.isAbs(elf_file))) + { got.flags.needs_rela = true; + } if (symbol.extra(elf_file)) |extra| { var new_extra = extra; new_extra.got = index; @@ -310,6 +314,7 @@ pub const GotSection = struct { entry.tag = .tlsgd; entry.symbol_index = sym_index; const symbol = elf_file.symbol(sym_index); + symbol.flags.has_tlsgd = true; if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true; if (symbol.extra(elf_file)) |extra| { var new_extra = extra; @@ -324,6 +329,7 @@ pub const GotSection = struct { entry.tag = .gottp; entry.symbol_index = sym_index; const symbol = elf_file.symbol(sym_index); + symbol.flags.has_gottp = true; if (symbol.flags.import or elf_file.isDynLib()) got.flags.needs_rela = true; if (symbol.extra(elf_file)) |extra| { var new_extra = extra; @@ -338,6 +344,7 @@ pub const GotSection = struct { entry.tag = .tlsdesc; entry.symbol_index = sym_index; const symbol = elf_file.symbol(sym_index); + symbol.flags.has_tlsdesc = true; got.flags.needs_rela = true; if (symbol.extra(elf_file)) |extra| { var new_extra = extra; @@ -645,6 +652,7 @@ pub const PltSection = struct { pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void { const index = @as(u32, @intCast(plt.symbols.items.len)); const symbol = elf_file.symbol(sym_index); + symbol.flags.has_plt = true; if (symbol.extra(elf_file)) |extra| { var new_extra = extra; new_extra.plt = index;