Commit c7ed7c4690
Changed files (6)
src/link/Elf/Atom.zig
@@ -60,6 +60,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
};
}
+pub fn relocsShndx(self: Atom) ?u32 {
+ if (self.relocs_section_index == 0) return null;
+ return self.relocs_section_index;
+}
+
pub fn outputShndx(self: Atom) ?u16 {
if (self.output_section_index == 0) return null;
return self.output_section_index;
@@ -280,9 +285,10 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
}
pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
+ const shndx = self.relocsShndx() orelse return &[0]elf.Elf64_Rela{};
return switch (self.file(elf_file).?) {
- .zig_object => |x| x.relocs.items[self.relocs_section_index].items,
- .object => |x| x.getRelocs(self.relocs_section_index),
+ .zig_object => |x| x.relocs.items[shndx].items,
+ .object => |x| x.getRelocs(shndx),
else => unreachable,
};
}
src/link/Elf/file.zig
@@ -136,8 +136,7 @@ pub const File = union(enum) {
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
const esym = local.elfSym(elf_file);
switch (esym.st_type()) {
- elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
- elf.STT_NOTYPE => continue,
+ elf.STT_SECTION, elf.STT_NOTYPE => continue,
else => {},
}
local.flags.output_symtab = true;
src/link/Elf/Object.zig
@@ -211,6 +211,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
const name = blk: {
const name = self.getString(shdr.sh_name);
+ if (elf_file.isRelocatable()) break :blk 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",
@@ -237,7 +238,10 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
else => shdr.sh_type,
};
const flags = blk: {
- const flags = shdr.sh_flags & ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
+ var flags = shdr.sh_flags;
+ if (!elf_file.isRelocatable()) {
+ 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,
@@ -655,8 +659,13 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
}
pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
- _ = self;
- _ = elf_file;
+ for (self.atoms.items) |atom_index| {
+ const atom = elf_file.atom(atom_index) orelse continue;
+ if (!atom.flags.alive) continue;
+ const shndx = atom.relocsShndx() orelse continue;
+ const shdr = self.shdrs.items[shndx];
+ _ = try self.initOutputSection(elf_file, shdr);
+ }
}
pub fn updateRelaSectionsSizes(self: Object, elf_file: *Elf) void {
src/link/Elf/Symbol.zig
@@ -219,8 +219,6 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
const st_shndx = blk: {
if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
- // TODO I think this is wrong and obsolete
- if (elf_file.isRelocatable() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
break :blk elf.SHN_ABS;
break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
src/link/Elf/ZigObject.zig
@@ -287,22 +287,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
return symbol_index;
}
-pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void {
- assert(elf_file.isRelocatable());
- const gpa = elf_file.base.allocator;
- const symbol_index = try elf_file.addSymbol();
- try self.local_symbols.append(gpa, symbol_index);
- const symbol_ptr = elf_file.symbol(symbol_index);
- symbol_ptr.file_index = self.index;
- symbol_ptr.output_section_index = shndx;
-
- const esym_index = try self.addLocalEsym(gpa);
- const esym = &self.local_esyms.items(.elf_sym)[esym_index];
- esym.st_info = elf.STT_SECTION;
- esym.st_shndx = shndx;
- symbol_ptr.esym_index = esym_index;
-}
-
/// TODO actually create fake input shdrs and return that instead.
pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
_ = self;
src/link/Elf.zig
@@ -597,7 +597,6 @@ pub fn initMetadata(self: *Elf) !void {
const shdr = &self.shdrs.items[self.zig_text_section_index.?];
fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
if (self.isRelocatable()) {
- try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
self.zig_text_rela_section_index = try self.addRelaShdr(
".rela.text.zig",
self.zig_text_section_index.?,
@@ -609,6 +608,7 @@ pub fn initMetadata(self: *Elf) !void {
self.phdr_zig_load_re_index.?,
);
}
+ try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{});
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
}
@@ -644,7 +644,6 @@ pub fn initMetadata(self: *Elf) !void {
const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
if (self.isRelocatable()) {
- try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
".rela.data.rel.ro.zig",
self.zig_data_rel_ro_section_index.?,
@@ -656,6 +655,7 @@ pub fn initMetadata(self: *Elf) !void {
self.phdr_zig_load_ro_index.?,
);
}
+ try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
}
@@ -670,7 +670,6 @@ pub fn initMetadata(self: *Elf) !void {
const shdr = &self.shdrs.items[self.zig_data_section_index.?];
fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
if (self.isRelocatable()) {
- try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
self.zig_data_rela_section_index = try self.addRelaShdr(
".rela.data.zig",
self.zig_data_section_index.?,
@@ -682,6 +681,7 @@ pub fn initMetadata(self: *Elf) !void {
self.phdr_zig_load_rw_index.?,
);
}
+ try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{});
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
}
@@ -700,9 +700,9 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_size = phdr.p_memsz;
try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
} else {
- try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
shdr.sh_size = 1024;
}
+ try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
}
@@ -724,6 +724,7 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_offset = off;
shdr.sh_size = size;
zig_object.debug_strtab_dirty = true;
+ try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{});
}
if (self.debug_info_section_index == null) {
@@ -739,6 +740,7 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_offset = off;
shdr.sh_size = size;
zig_object.debug_info_header_dirty = true;
+ try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{});
}
if (self.debug_abbrev_section_index == null) {
@@ -754,6 +756,7 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_offset = off;
shdr.sh_size = size;
zig_object.debug_abbrev_section_dirty = true;
+ try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{});
}
if (self.debug_aranges_section_index == null) {
@@ -769,6 +772,7 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_offset = off;
shdr.sh_size = size;
zig_object.debug_aranges_section_dirty = true;
+ try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{});
}
if (self.debug_line_section_index == null) {
@@ -784,6 +788,7 @@ pub fn initMetadata(self: *Elf) !void {
shdr.sh_offset = off;
shdr.sh_size = size;
zig_object.debug_line_header_dirty = true;
+ try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{});
}
}
}
@@ -1510,14 +1515,14 @@ pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {
try self.initShStrtab();
try self.sortShdrs();
zig_object.updateRelaSectionsSizes(self);
- self.updateSymtabSizeObject(zig_object);
+ self.updateSymtabSizeZigObject(zig_object);
self.updateShStrtabSize();
try self.allocateNonAllocSections();
try self.writeShdrTable();
try zig_object.writeRelaSections(self);
- try self.writeSymtabObject(zig_object);
+ try self.writeSymtabZigObject(zig_object);
try self.writeShStrtab();
try self.writeElfHeader();
}
@@ -3579,7 +3584,8 @@ fn sortInitFini(self: *Elf) !void {
if (!is_init_fini and !is_ctor_dtor) continue;
- const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue;
+ const atom_list = self.output_sections.getPtr(@intCast(shndx)).?;
+ if (atom_list.items.len == 0) continue;
var entries = std.ArrayList(Entry).init(gpa);
try entries.ensureTotalCapacityPrecise(atom_list.items.len);
@@ -3909,6 +3915,20 @@ fn sortShdrs(self: *Elf) !void {
shdr.sh_info = backlinks[shdr.sh_info];
}
+ {
+ var output_sections = try self.output_sections.clone(gpa);
+ defer output_sections.deinit(gpa);
+
+ self.output_sections.clearRetainingCapacity();
+
+ var it = output_sections.iterator();
+ while (it.next()) |entry| {
+ const shndx = entry.key_ptr.*;
+ const meta = entry.value_ptr.*;
+ self.output_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta);
+ }
+ }
+
{
var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);
defer last_atom_and_free_list_table.deinit(gpa);
@@ -3962,7 +3982,6 @@ fn sortShdrs(self: *Elf) !void {
fn updateSectionSizes(self: *Elf) !void {
for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
- if (atom_list.items.len == 0) continue;
const shdr = &self.shdrs.items[shndx];
for (atom_list.items) |atom_index| {
const atom_ptr = self.atom(atom_index) orelse continue;
@@ -4056,7 +4075,6 @@ fn updateSectionSizes(self: *Elf) !void {
fn updateSectionSizesObject(self: *Elf) !void {
for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
- if (atom_list.items.len == 0) continue;
const shdr = &self.shdrs.items[shndx];
for (atom_list.items) |atom_index| {
const atom_ptr = self.atom(atom_index) orelse continue;
@@ -4317,7 +4335,6 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
/// Allocates alloc sections when merging relocatable objects files together.
fn allocateAllocSectionsObject(self: *Elf) !void {
_ = self;
- @panic("TODO");
}
/// Allocates non-alloc sections (debug info, symtabs, etc.).
@@ -4444,6 +4461,7 @@ fn writeAtoms(self: *Elf) !void {
if (shdr.sh_type == elf.SHT_NOBITS) continue;
const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
+ if (atom_list.items.len == 0) continue;
log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
@@ -4519,6 +4537,7 @@ fn writeAtomsObject(self: *Elf) !void {
if (shdr.sh_type == elf.SHT_NOBITS) continue;
const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
+ if (atom_list.items.len == 0) continue;
log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
@@ -4617,6 +4636,11 @@ fn updateSymtabSize(self: *Elf) void {
sizes.add(file_ptr.linker_defined.output_symtab_size);
}
+ // Section symbols
+ for (self.output_sections.keys()) |_| {
+ sizes.nlocals += 1;
+ }
+
const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
symtab_shdr.sh_info = sizes.nlocals + 1;
symtab_shdr.sh_link = self.strtab_section_index.?;
@@ -4632,9 +4656,16 @@ fn updateSymtabSize(self: *Elf) void {
strtab.sh_size = sizes.strsize + 1;
}
-fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void {
+fn updateSymtabSizeZigObject(self: *Elf, zig_object: *ZigObject) void {
+ var sizes = SymtabSize{};
+
zig_object.asFile().updateSymtabSize(self);
- const sizes = zig_object.output_symtab_size;
+ sizes.add(zig_object.output_symtab_size);
+
+ // Section symbols
+ for (self.output_sections.keys()) |_| {
+ sizes.nlocals += 1;
+ }
const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
symtab_shdr.sh_info = sizes.nlocals + 1;
@@ -4798,7 +4829,7 @@ fn writeSyntheticSectionsObject(self: *Elf) !void {
var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
defer buffer.deinit();
try eh_frame.writeEhFrame(self, buffer.writer());
- try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
+ // try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
}
try self.writeSymtab();
@@ -4812,6 +4843,16 @@ fn writeShStrtab(self: *Elf) !void {
}
}
+const WriteSymtabCtx = struct {
+ ilocal: usize,
+ iglobal: usize,
+
+ fn incr(this: *@This(), ss: SymtabSize) void {
+ this.ilocal += ss.nlocals;
+ this.iglobal += ss.nglobals;
+ }
+};
+
fn writeSymtab(self: *Elf) !void {
const gpa = self.base.allocator;
const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
@@ -4828,20 +4869,13 @@ fn writeSymtab(self: *Elf) !void {
const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
- const Ctx = struct {
- ilocal: usize,
- iglobal: usize,
-
- fn incr(this: *@This(), ss: SymtabSize) void {
- this.ilocal += ss.nlocals;
- this.iglobal += ss.nglobals;
- }
- };
- var ctx: Ctx = .{
+ var ctx: WriteSymtabCtx = .{
.ilocal = 1,
.iglobal = symtab_shdr.sh_info,
};
+ ctx.incr(self.writeSectionSymbols(ctx));
+
if (self.zigObjectPtr()) |zig_object| {
zig_object.asFile().writeSymtab(self, ctx);
ctx.incr(zig_object.output_symtab_size);
@@ -4915,7 +4949,7 @@ fn writeSymtab(self: *Elf) !void {
try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
}
-fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
+fn writeSymtabZigObject(self: *Elf, zig_object: *ZigObject) !void {
const gpa = self.base.allocator;
const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
@@ -4931,7 +4965,15 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
- zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info });
+ var ctx: WriteSymtabCtx = .{
+ .ilocal = 1,
+ .iglobal = symtab_shdr.sh_info,
+ };
+
+ ctx.incr(self.writeSectionSymbols(ctx));
+
+ zig_object.asFile().writeSymtab(self, ctx);
+ ctx.incr(zig_object.output_symtab_size);
const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
switch (self.ptr_width) {
@@ -4963,6 +5005,24 @@ fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void {
try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
}
+fn writeSectionSymbols(self: *Elf, ctx: WriteSymtabCtx) SymtabSize {
+ var ilocal = ctx.ilocal;
+ for (self.output_sections.keys()) |shndx| {
+ const shdr = self.shdrs.items[shndx];
+ const out_sym = &self.symtab.items[ilocal];
+ out_sym.* = .{
+ .st_name = 0,
+ .st_value = shdr.sh_addr,
+ .st_info = elf.STT_SECTION,
+ .st_shndx = @intCast(shndx),
+ .st_size = 0,
+ .st_other = 0,
+ };
+ ilocal += 1;
+ }
+ return .{ .nlocals = @intCast(ilocal - ctx.ilocal) };
+}
+
/// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
fn ptrWidthBytes(self: Elf) u8 {
return switch (self.ptr_width) {