elf: move initOutputSection into Elf from Object

This commit is contained in:
Jakub Konka
2024-08-27 15:22:33 +02:00
parent b44dd599ad
commit d32af9ea2a
2 changed files with 73 additions and 56 deletions

View File

@@ -1827,6 +1827,59 @@ fn scanRelocs(self: *Elf) !void {
}
}
pub fn initOutputSection(self: *Elf, args: struct {
name: [:0]const u8,
flags: u64,
type: u32,
}) error{OutOfMemory}!u32 {
const name = blk: {
if (self.base.isRelocatable()) break :blk args.name;
if (args.flags & elf.SHF_MERGE != 0) break :blk args.name;
const 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 (name_prefixes) |prefix| {
if (std.mem.eql(u8, args.name, prefix) or std.mem.startsWith(u8, args.name, prefix ++ ".")) {
break :blk prefix;
}
}
break :blk args.name;
};
const @"type" = tt: {
if (self.getTarget().cpu.arch == .x86_64 and
args.type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS;
switch (args.type) {
elf.SHT_NULL => unreachable,
elf.SHT_PROGBITS => {
if (std.mem.eql(u8, args.name, ".init_array") or std.mem.startsWith(u8, args.name, ".init_array."))
break :tt elf.SHT_INIT_ARRAY;
if (std.mem.eql(u8, args.name, ".fini_array") or std.mem.startsWith(u8, args.name, ".fini_array."))
break :tt elf.SHT_FINI_ARRAY;
break :tt args.type;
},
else => break :tt args.type,
}
};
const flags = blk: {
var flags = args.flags;
if (!self.base.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,
};
};
const out_shndx = self.sectionByName(name) orelse try self.addSection(.{
.type = @"type",
.flags = flags,
.name = try self.insertShString(name),
});
return out_shndx;
}
fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
dev.check(.lld_linker);

View File

@@ -311,58 +311,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
};
}
fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 {
const name = blk: {
const name = self.getString(shdr.sh_name);
if (elf_file.base.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",
".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" = tt: {
if (elf_file.getTarget().cpu.arch == .x86_64 and
shdr.sh_type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS;
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;
},
else => shdr.sh_type,
};
break :tt @"type";
};
const flags = blk: {
var flags = shdr.sh_flags;
if (!elf_file.base.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,
};
};
const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
.type = @"type",
.flags = flags,
.name = try elf_file.insertShString(name),
});
return out_shndx;
}
fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
const comp = elf_file.base.comp;
const shdr = self.shdrs.items[index];
@@ -985,7 +933,11 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void {
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.alive) continue;
const shdr = atom_ptr.inputShdr(elf_file);
_ = try self.initOutputSection(elf_file, shdr);
_ = try elf_file.initOutputSection(.{
.name = self.getString(shdr.sh_name),
.flags = shdr.sh_flags,
.type = shdr.sh_type,
});
}
}
@@ -994,7 +946,11 @@ pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void {
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.alive) continue;
const shdr = atom_ptr.inputShdr(elf_file);
atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable;
atom_ptr.output_section_index = elf_file.initOutputSection(.{
.name = self.getString(shdr.sh_name),
.flags = shdr.sh_flags,
.type = shdr.sh_type,
}) catch unreachable;
const comp = elf_file.base.comp;
const gpa = comp.gpa;
@@ -1009,7 +965,11 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void {
if (!atom_ptr.alive) continue;
const shndx = atom_ptr.relocsShndx() orelse continue;
const shdr = self.shdrs.items[shndx];
const out_shndx = try self.initOutputSection(elf_file, shdr);
const out_shndx = try elf_file.initOutputSection(.{
.name = self.getString(shdr.sh_name),
.flags = shdr.sh_flags,
.type = shdr.sh_type,
});
const out_shdr = &elf_file.sections.items(.shdr)[out_shndx];
out_shdr.sh_type = elf.SHT_RELA;
out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);
@@ -1025,7 +985,11 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void {
const shndx = blk: {
const shndx = atom_ptr.relocsShndx() orelse continue;
const shdr = self.shdrs.items[shndx];
break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
break :blk elf_file.initOutputSection(.{
.name = self.getString(shdr.sh_name),
.flags = shdr.sh_flags,
.type = shdr.sh_type,
}) catch unreachable;
};
const slice = elf_file.sections.slice();
const shdr = &slice.items(.shdr)[shndx];