diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 994cf14089..9ee1389397 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1043,14 +1043,17 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node self.linker_defined_index = index; } + // Symbol resolution happens here try self.addLinkerDefinedSymbols(); - - // Resolve symbols self.resolveSymbols(); self.markImportsExports(); self.claimUnresolved(); + + // Scan and create missing synthetic entries such as GOT indirection try self.scanRelocs(); + // Allocate atoms parsed from input object files + self.allocateObjects(); self.allocateLinkerDefinedSymbols(); // Beyond this point, everything has been allocated a virtual address and we can resolve @@ -1402,6 +1405,10 @@ fn scanRelocs(self: *Elf) !void { } } +fn allocateObjects(self: *Elf) void { + _ = self; +} + fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 527b2e5c61..d06dfe3b3d 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -17,7 +17,6 @@ comdat_groups: std.ArrayListUnmanaged(Elf.ComdatGroup.Index) = .{}, fdes: std.ArrayListUnmanaged(Fde) = .{}, cies: std.ArrayListUnmanaged(Cie) = .{}, -needs_exec_stack: bool = false, alive: bool = true, num_dynrelocs: u32 = 0, @@ -80,12 +79,12 @@ pub fn parse(self: *Object, elf_file: *Elf) !void { try self.initAtoms(elf_file); try self.initSymtab(elf_file); - for (self.shdrs.items, 0..) |shdr, i| { - const atom = elf_file.atom(self.atoms.items[i]) orelse continue; - if (!atom.alive) continue; - if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) - try self.parseEhFrame(@as(u16, @intCast(i)), elf_file); - } + // for (self.shdrs.items, 0..) |shdr, i| { + // const atom = elf_file.atom(self.atoms.items[i]) orelse continue; + // if (!atom.alive) continue; + // if (shdr.sh_type == elf.SHT_X86_64_UNWIND or mem.eql(u8, atom.name(elf_file), ".eh_frame")) + // try self.parseEhFrame(@as(u16, @intCast(i)), elf_file); + // } } fn initAtoms(self: *Object, elf_file: *Elf) !void { @@ -148,20 +147,6 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void { else => { const name = self.strings.getAssumeExists(shdr.sh_name); const shndx = @as(u16, @intCast(i)); - - // if (mem.eql(u8, ".note.GNU-stack", name)) { - // if (shdr.sh_flags & elf.SHF_EXECINSTR != 0) { - // if (!elf_file.options.z_execstack or !elf_file.options.z_execstack_if_needed) { - // elf_file.base.warn( - // "{}: may cause segmentation fault as this file requested executable stack", - // .{self.fmtPath()}, - // ); - // } - // self.needs_exec_stack = true; - // } - // continue; - // } - if (self.skipShdr(shndx, elf_file)) continue; try self.addAtom(shdr, shndx, name, elf_file); }, @@ -187,6 +172,7 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, atom.name_offset = try elf_file.strtab.insert(elf_file.base.allocator, name); atom.file_index = self.index; atom.input_section_index = shndx; + atom.output_section_index = self.getOutputSectionIndex(elf_file, shdr); atom.alive = true; self.atoms.items[shndx] = atom_index; @@ -201,15 +187,61 @@ fn addAtom(self: *Object, shdr: elf.Elf64_Shdr, shndx: u16, name: [:0]const u8, } } +fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) u16 { + const name = blk: { + const name = self.strings.getAssumeExists(shdr.sh_name); + // if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; + const sh_name_prefixes: []const [:0]const u8 = &.{ + ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", + ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", + ".dtors", ".gnu.warning", + }; + inline for (sh_name_prefixes) |prefix| { + if (std.mem.eql(u8, name, prefix) or std.mem.startsWith(u8, name, prefix ++ ".")) { + break :blk prefix; + } + } + break :blk name; + }; + const @"type" = switch (shdr.sh_type) { + elf.SHT_NULL => unreachable, + elf.SHT_PROGBITS => blk: { + if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array.")) + break :blk elf.SHT_INIT_ARRAY; + if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array.")) + break :blk elf.SHT_FINI_ARRAY; + break :blk shdr.sh_type; + }, + elf.SHT_X86_64_UNWIND => elf.SHT_PROGBITS, + else => shdr.sh_type, + }; + const flags = blk: { + const flags = shdr.sh_flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); + break :blk switch (@"type") { + elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, + else => flags, + }; + }; + _ = flags; + const out_shndx = elf_file.sectionByName(name) orelse { + log.err("{}: output section {s} not found", .{ self.fmtPath(), name }); + @panic("TODO: missing output section!"); + }; + return out_shndx; +} + fn skipShdr(self: *Object, index: u16, elf_file: *Elf) bool { + _ = elf_file; const shdr = self.shdrs.items[index]; const name = self.strings.getAssumeExists(shdr.sh_name); const ignore = blk: { if (mem.startsWith(u8, name, ".note")) break :blk true; if (mem.startsWith(u8, name, ".comment")) break :blk true; if (mem.startsWith(u8, name, ".llvm_addrsig")) break :blk true; - if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and - mem.startsWith(u8, name, ".debug")) break :blk true; + if (mem.startsWith(u8, name, ".eh_frame")) break :blk true; + // if (elf_file.base.options.strip and shdr.sh_flags & elf.SHF_ALLOC == 0 and + // mem.startsWith(u8, name, ".debug")) break :blk true; + if (shdr.sh_flags & elf.SHF_ALLOC == 0 and mem.startsWith(u8, name, ".debug")) break :blk true; break :blk false; }; return ignore;