mirror of
https://github.com/ziglang/zig.git
synced 2025-12-24 07:03:11 +00:00
Merge pull request #17933 from ziglang/elf-r-mode
elf: the dreaded `-r` mode
This commit is contained in:
commit
c550eb3e8a
@ -1664,6 +1664,8 @@ pub const EM = enum(u16) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const GRP_COMDAT = 1;
|
||||||
|
|
||||||
/// Section data should be writable during execution.
|
/// Section data should be writable during execution.
|
||||||
pub const SHF_WRITE = 0x1;
|
pub const SHF_WRITE = 0x1;
|
||||||
|
|
||||||
|
|||||||
1385
src/link/Elf.zig
1385
src/link/Elf.zig
File diff suppressed because it is too large
Load Diff
@ -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 {
|
pub fn outputShndx(self: Atom) ?u16 {
|
||||||
if (self.output_section_index == 0) return null;
|
if (self.output_section_index == 0) return null;
|
||||||
return self.output_section_index;
|
return self.output_section_index;
|
||||||
@ -280,13 +285,60 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
|
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).?) {
|
return switch (self.file(elf_file).?) {
|
||||||
.zig_object => |x| x.relocs.items[self.relocs_section_index].items,
|
.zig_object => |x| x.relocs.items[shndx].items,
|
||||||
.object => |x| x.getRelocs(self.relocs_section_index),
|
.object => |x| x.getRelocs(shndx),
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
|
||||||
|
relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
|
||||||
|
|
||||||
|
const file_ptr = self.file(elf_file).?;
|
||||||
|
for (self.relocs(elf_file)) |rel| {
|
||||||
|
const target_index = switch (file_ptr) {
|
||||||
|
.zig_object => |x| x.symbol(rel.r_sym()),
|
||||||
|
.object => |x| x.symbols.items[rel.r_sym()],
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
const target = elf_file.symbol(target_index);
|
||||||
|
const r_type = switch (rel.r_type()) {
|
||||||
|
Elf.R_X86_64_ZIG_GOT32,
|
||||||
|
Elf.R_X86_64_ZIG_GOTPCREL,
|
||||||
|
=> unreachable, // Sanity check if we accidentally emitted those.
|
||||||
|
else => |r_type| r_type,
|
||||||
|
};
|
||||||
|
const r_offset = self.value + rel.r_offset;
|
||||||
|
var r_addend = rel.r_addend;
|
||||||
|
var r_sym: u32 = 0;
|
||||||
|
switch (target.type(elf_file)) {
|
||||||
|
elf.STT_SECTION => {
|
||||||
|
r_addend += @intCast(target.value);
|
||||||
|
r_sym = elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
r_sym = target.outputSymtabIndex(elf_file) orelse 0;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
|
||||||
|
fmtRelocType(r_type),
|
||||||
|
r_offset,
|
||||||
|
r_sym,
|
||||||
|
target.name(elf_file),
|
||||||
|
r_addend,
|
||||||
|
});
|
||||||
|
|
||||||
|
out_relocs.appendAssumeCapacity(.{
|
||||||
|
.r_offset = r_offset,
|
||||||
|
.r_addend = r_addend,
|
||||||
|
.r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
|
pub fn fdes(self: Atom, elf_file: *Elf) []Fde {
|
||||||
if (self.fde_start == self.fde_end) return &[0]Fde{};
|
if (self.fde_start == self.fde_end) return &[0]Fde{};
|
||||||
const object = self.file(elf_file).?.object;
|
const object = self.file(elf_file).?.object;
|
||||||
|
|||||||
@ -3,7 +3,7 @@ symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
|||||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||||
|
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
|
|
||||||
pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
|
pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
|
||||||
self.symtab.deinit(allocator);
|
self.symtab.deinit(allocator);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
|
|||||||
alive: bool = true,
|
alive: bool = true,
|
||||||
num_dynrelocs: u32 = 0,
|
num_dynrelocs: u32 = 0,
|
||||||
|
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
output_ar_state: Archive.ArState = .{},
|
output_ar_state: Archive.ArState = .{},
|
||||||
|
|
||||||
pub fn isObject(path: []const u8) !bool {
|
pub fn isObject(path: []const u8) !bool {
|
||||||
@ -142,7 +142,7 @@ fn initAtoms(self: *Object, elf_file: *Elf) !void {
|
|||||||
const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
|
const group_nmembers = @divExact(group_raw_data.len, @sizeOf(u32));
|
||||||
const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
|
const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
|
||||||
|
|
||||||
if (group_members[0] != 0x1) { // GRP_COMDAT
|
if (group_members[0] != elf.GRP_COMDAT) {
|
||||||
// TODO convert into an error
|
// TODO convert into an error
|
||||||
log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
|
log.debug("{}: unknown SHT_GROUP format", .{self.fmtPath()});
|
||||||
continue;
|
continue;
|
||||||
@ -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 {
|
fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
|
||||||
const name = blk: {
|
const name = blk: {
|
||||||
const name = self.getString(shdr.sh_name);
|
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;
|
if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
|
||||||
const sh_name_prefixes: []const [:0]const u8 = &.{
|
const sh_name_prefixes: []const [:0]const u8 = &.{
|
||||||
".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
|
".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,
|
else => shdr.sh_type,
|
||||||
};
|
};
|
||||||
const flags = blk: {
|
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") {
|
break :blk switch (@"type") {
|
||||||
elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
|
elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE,
|
||||||
else => flags,
|
else => flags,
|
||||||
@ -487,6 +491,25 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
|
||||||
|
const first_global = self.first_global orelse return;
|
||||||
|
for (self.globals(), 0..) |index, i| {
|
||||||
|
const esym_index = @as(u32, @intCast(first_global + i));
|
||||||
|
const esym = self.symtab.items[esym_index];
|
||||||
|
if (esym.st_shndx != elf.SHN_UNDEF) continue;
|
||||||
|
|
||||||
|
const global = elf_file.symbol(index);
|
||||||
|
if (global.file(elf_file)) |file| {
|
||||||
|
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.value = 0;
|
||||||
|
global.atom_index = 0;
|
||||||
|
global.esym_index = esym_index;
|
||||||
|
global.file_index = self.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn markLive(self: *Object, elf_file: *Elf) void {
|
pub fn markLive(self: *Object, elf_file: *Elf) void {
|
||||||
const first_global = self.first_global orelse return;
|
const first_global = self.first_global orelse return;
|
||||||
for (self.globals(), 0..) |index, i| {
|
for (self.globals(), 0..) |index, i| {
|
||||||
@ -654,6 +677,40 @@ pub fn allocateAtoms(self: Object, elf_file: *Elf) void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn initRelaSections(self: Object, elf_file: *Elf) !void {
|
||||||
|
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];
|
||||||
|
const out_shndx = try self.initOutputSection(elf_file, shdr);
|
||||||
|
const out_shdr = &elf_file.shdrs.items[out_shndx];
|
||||||
|
out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela);
|
||||||
|
out_shdr.sh_entsize = @sizeOf(elf.Elf64_Rela);
|
||||||
|
out_shdr.sh_flags |= elf.SHF_INFO_LINK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn addAtomsToRelaSections(self: Object, elf_file: *Elf) !void {
|
||||||
|
for (self.atoms.items) |atom_index| {
|
||||||
|
const atom = elf_file.atom(atom_index) orelse continue;
|
||||||
|
if (!atom.flags.alive) continue;
|
||||||
|
const shndx = blk: {
|
||||||
|
const shndx = atom.relocsShndx() orelse continue;
|
||||||
|
const shdr = self.shdrs.items[shndx];
|
||||||
|
break :blk self.initOutputSection(elf_file, shdr) catch unreachable;
|
||||||
|
};
|
||||||
|
const shdr = &elf_file.shdrs.items[shndx];
|
||||||
|
shdr.sh_info = atom.outputShndx().?;
|
||||||
|
shdr.sh_link = elf_file.symtab_section_index.?;
|
||||||
|
|
||||||
|
const gpa = elf_file.base.allocator;
|
||||||
|
const gop = try elf_file.output_rela_sections.getOrPut(gpa, atom.outputShndx().?);
|
||||||
|
if (!gop.found_existing) gop.value_ptr.* = .{ .shndx = shndx };
|
||||||
|
try gop.value_ptr.atom_list.append(gpa, atom_index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
|
pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) !void {
|
||||||
const gpa = elf_file.base.allocator;
|
const gpa = elf_file.base.allocator;
|
||||||
const start = self.first_global orelse self.symtab.items.len;
|
const start = self.first_global orelse self.symtab.items.len;
|
||||||
@ -685,11 +742,13 @@ pub fn writeAr(self: Object, writer: anytype) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn locals(self: Object) []const Symbol.Index {
|
pub fn locals(self: Object) []const Symbol.Index {
|
||||||
|
if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
|
||||||
const end = self.first_global orelse self.symbols.items.len;
|
const end = self.first_global orelse self.symbols.items.len;
|
||||||
return self.symbols.items[0..end];
|
return self.symbols.items[0..end];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn globals(self: Object) []const Symbol.Index {
|
pub fn globals(self: Object) []const Symbol.Index {
|
||||||
|
if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
|
||||||
const start = self.first_global orelse self.symbols.items.len;
|
const start = self.first_global orelse self.symbols.items.len;
|
||||||
return self.symbols.items[start..];
|
return self.symbols.items[start..];
|
||||||
}
|
}
|
||||||
@ -881,16 +940,17 @@ fn formatComdatGroups(
|
|||||||
_ = options;
|
_ = options;
|
||||||
const object = ctx.object;
|
const object = ctx.object;
|
||||||
const elf_file = ctx.elf_file;
|
const elf_file = ctx.elf_file;
|
||||||
try writer.writeAll(" comdat groups\n");
|
try writer.writeAll(" COMDAT groups\n");
|
||||||
for (object.comdat_groups.items) |cg_index| {
|
for (object.comdat_groups.items) |cg_index| {
|
||||||
const cg = elf_file.comdatGroup(cg_index);
|
const cg = elf_file.comdatGroup(cg_index);
|
||||||
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
||||||
if (cg_owner.file != object.index) continue;
|
if (cg_owner.file != object.index) continue;
|
||||||
|
try writer.print(" COMDAT({d})\n", .{cg_index});
|
||||||
const cg_members = object.comdatGroupMembers(cg.shndx);
|
const cg_members = object.comdatGroupMembers(cg.shndx);
|
||||||
for (cg_members) |shndx| {
|
for (cg_members) |shndx| {
|
||||||
const atom_index = object.atoms.items[shndx];
|
const atom_index = object.atoms.items[shndx];
|
||||||
const atom = elf_file.atom(atom_index) orelse continue;
|
const atom = elf_file.atom(atom_index) orelse continue;
|
||||||
try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
|
try writer.print(" atom({d}) : {s}\n", .{ atom_index, atom.name(elf_file) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ verdef_sect_index: ?u16 = null,
|
|||||||
needed: bool,
|
needed: bool,
|
||||||
alive: bool,
|
alive: bool,
|
||||||
|
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
|
|
||||||
pub fn isSharedObject(path: []const u8) !bool {
|
pub fn isSharedObject(path: []const u8) !bool {
|
||||||
const file = try std.fs.cwd().openFile(path, .{});
|
const file = try std.fs.cwd().openFile(path, .{});
|
||||||
|
|||||||
@ -107,6 +107,24 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
|
|||||||
return symbol.value;
|
return symbol.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
|
||||||
|
if (!symbol.flags.output_symtab) return null;
|
||||||
|
const file_ptr = symbol.file(elf_file).?;
|
||||||
|
const symtab_ctx = switch (file_ptr) {
|
||||||
|
inline else => |x| x.output_symtab_ctx,
|
||||||
|
};
|
||||||
|
const idx = symbol.extra(elf_file).?.symtab;
|
||||||
|
return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setOutputSymtabIndex(symbol: *Symbol, index: u32, elf_file: *Elf) !void {
|
||||||
|
if (symbol.extra(elf_file)) |extras| {
|
||||||
|
var new_extras = extras;
|
||||||
|
new_extras.symtab = index;
|
||||||
|
symbol.setExtra(new_extras, elf_file);
|
||||||
|
} else try symbol.addExtra(.{ .symtab = index }, elf_file);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
|
||||||
if (!symbol.flags.has_got) return 0;
|
if (!symbol.flags.has_got) return 0;
|
||||||
const extras = symbol.extra(elf_file).?;
|
const extras = symbol.extra(elf_file).?;
|
||||||
@ -219,10 +237,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
|||||||
const st_shndx = blk: {
|
const st_shndx = blk: {
|
||||||
if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
|
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;
|
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 esym.st_shndx == elf.SHN_COMMON) break :blk elf.SHN_COMMON;
|
||||||
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;
|
||||||
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
|
|
||||||
break :blk elf.SHN_ABS;
|
|
||||||
break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
|
break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
|
||||||
};
|
};
|
||||||
const st_value = blk: {
|
const st_value = blk: {
|
||||||
@ -231,7 +247,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
|
|||||||
if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
|
if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
|
||||||
break :blk 0;
|
break :blk 0;
|
||||||
}
|
}
|
||||||
if (st_shndx == elf.SHN_ABS) break :blk symbol.value;
|
if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.value;
|
||||||
const shdr = &elf_file.shdrs.items[st_shndx];
|
const shdr = &elf_file.shdrs.items[st_shndx];
|
||||||
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
|
if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
|
||||||
break :blk symbol.value - elf_file.tlsAddress();
|
break :blk symbol.value - elf_file.tlsAddress();
|
||||||
@ -390,6 +406,7 @@ pub const Extra = struct {
|
|||||||
plt: u32 = 0,
|
plt: u32 = 0,
|
||||||
plt_got: u32 = 0,
|
plt_got: u32 = 0,
|
||||||
dynamic: u32 = 0,
|
dynamic: u32 = 0,
|
||||||
|
symtab: u32 = 0,
|
||||||
copy_rel: u32 = 0,
|
copy_rel: u32 = 0,
|
||||||
tlsgd: u32 = 0,
|
tlsgd: u32 = 0,
|
||||||
gottp: u32 = 0,
|
gottp: u32 = 0,
|
||||||
|
|||||||
@ -18,7 +18,7 @@ relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
|
|||||||
|
|
||||||
num_dynrelocs: u32 = 0,
|
num_dynrelocs: u32 = 0,
|
||||||
|
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
output_ar_state: Archive.ArState = .{},
|
output_ar_state: Archive.ArState = .{},
|
||||||
|
|
||||||
dwarf: ?Dwarf = null,
|
dwarf: ?Dwarf = null,
|
||||||
@ -75,6 +75,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
|
|||||||
const gpa = elf_file.base.allocator;
|
const gpa = elf_file.base.allocator;
|
||||||
|
|
||||||
try self.atoms.append(gpa, 0); // null input section
|
try self.atoms.append(gpa, 0); // null input section
|
||||||
|
try self.relocs.append(gpa, .{}); // null relocs section
|
||||||
try self.strtab.buffer.append(gpa, 0);
|
try self.strtab.buffer.append(gpa, 0);
|
||||||
|
|
||||||
const name_off = try self.strtab.insert(gpa, self.path);
|
const name_off = try self.strtab.insert(gpa, self.path);
|
||||||
@ -287,22 +288,6 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
|
|||||||
return 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.
|
/// TODO actually create fake input shdrs and return that instead.
|
||||||
pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
|
pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
|
||||||
_ = self;
|
_ = self;
|
||||||
@ -393,8 +378,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
|
|||||||
|
|
||||||
const global = elf_file.symbol(index);
|
const global = elf_file.symbol(index);
|
||||||
if (global.file(elf_file)) |file| {
|
if (global.file(elf_file)) |file| {
|
||||||
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or
|
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
|
||||||
file.index() <= self.index) continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.value = 0;
|
global.value = 0;
|
||||||
@ -549,94 +533,18 @@ pub fn writeAr(self: ZigObject, elf_file: *Elf, writer: anytype) !void {
|
|||||||
try writer.writeAll(contents);
|
try writer.writeAll(contents);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
|
pub fn addAtomsToRelaSections(self: ZigObject, elf_file: *Elf) !void {
|
||||||
_ = self;
|
for (self.atoms.items) |atom_index| {
|
||||||
|
const atom = elf_file.atom(atom_index) orelse continue;
|
||||||
|
if (!atom.flags.alive) continue;
|
||||||
|
_ = atom.relocsShndx() orelse continue;
|
||||||
|
const out_shndx = atom.outputShndx().?;
|
||||||
|
const out_shdr = elf_file.shdrs.items[out_shndx];
|
||||||
|
if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
|
||||||
|
|
||||||
for (&[_]?u16{
|
const gpa = elf_file.base.allocator;
|
||||||
elf_file.zig_text_rela_section_index,
|
const sec = elf_file.output_rela_sections.getPtr(out_shndx).?;
|
||||||
elf_file.zig_data_rel_ro_rela_section_index,
|
try sec.atom_list.append(gpa, atom_index);
|
||||||
elf_file.zig_data_rela_section_index,
|
|
||||||
}) |maybe_index| {
|
|
||||||
const index = maybe_index orelse continue;
|
|
||||||
const shdr = &elf_file.shdrs.items[index];
|
|
||||||
const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
|
|
||||||
const last_atom_index = meta.last_atom_index;
|
|
||||||
|
|
||||||
var atom = elf_file.atom(last_atom_index) orelse continue;
|
|
||||||
while (true) {
|
|
||||||
const relocs = atom.relocs(elf_file);
|
|
||||||
shdr.sh_size += relocs.len * shdr.sh_entsize;
|
|
||||||
if (elf_file.atom(atom.prev_index)) |prev| {
|
|
||||||
atom = prev;
|
|
||||||
} else break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (&[_]?u16{
|
|
||||||
elf_file.zig_text_rela_section_index,
|
|
||||||
elf_file.zig_data_rel_ro_rela_section_index,
|
|
||||||
elf_file.zig_data_rela_section_index,
|
|
||||||
}) |maybe_index| {
|
|
||||||
const index = maybe_index orelse continue;
|
|
||||||
const shdr = &elf_file.shdrs.items[index];
|
|
||||||
if (shdr.sh_size == 0) shdr.sh_offset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
|
|
||||||
const gpa = elf_file.base.allocator;
|
|
||||||
|
|
||||||
for (&[_]?u16{
|
|
||||||
elf_file.zig_text_rela_section_index,
|
|
||||||
elf_file.zig_data_rel_ro_rela_section_index,
|
|
||||||
elf_file.zig_data_rela_section_index,
|
|
||||||
}) |maybe_index| {
|
|
||||||
const index = maybe_index orelse continue;
|
|
||||||
const shdr = elf_file.shdrs.items[index];
|
|
||||||
const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
|
|
||||||
const last_atom_index = meta.last_atom_index;
|
|
||||||
|
|
||||||
var atom = elf_file.atom(last_atom_index) orelse continue;
|
|
||||||
|
|
||||||
var relocs = std.ArrayList(elf.Elf64_Rela).init(gpa);
|
|
||||||
defer relocs.deinit();
|
|
||||||
try relocs.ensureTotalCapacityPrecise(@intCast(@divExact(shdr.sh_size, shdr.sh_entsize)));
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
for (atom.relocs(elf_file)) |rel| {
|
|
||||||
const target = elf_file.symbol(self.symbol(rel.r_sym()));
|
|
||||||
const r_offset = atom.value + rel.r_offset;
|
|
||||||
const r_sym: u32 = if (target.flags.global)
|
|
||||||
(target.esym_index & symbol_mask) + @as(u32, @intCast(self.local_esyms.slice().len))
|
|
||||||
else
|
|
||||||
target.esym_index;
|
|
||||||
const r_type = switch (rel.r_type()) {
|
|
||||||
Elf.R_X86_64_ZIG_GOT32,
|
|
||||||
Elf.R_X86_64_ZIG_GOTPCREL,
|
|
||||||
=> unreachable, // Sanity check if we accidentally emitted those.
|
|
||||||
else => |r_type| r_type,
|
|
||||||
};
|
|
||||||
relocs.appendAssumeCapacity(.{
|
|
||||||
.r_offset = r_offset,
|
|
||||||
.r_addend = rel.r_addend,
|
|
||||||
.r_info = (@as(u64, @intCast(r_sym + 1)) << 32) | r_type,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (elf_file.atom(atom.prev_index)) |prev| {
|
|
||||||
atom = prev;
|
|
||||||
} else break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SortRelocs = struct {
|
|
||||||
pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
|
|
||||||
_ = ctx;
|
|
||||||
return lhs.r_offset < rhs.r_offset;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan);
|
|
||||||
|
|
||||||
try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -268,7 +268,11 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset + 4; // NULL terminator
|
if (!elf_file.isRelocatable()) {
|
||||||
|
offset += 4; // NULL terminator
|
||||||
|
}
|
||||||
|
|
||||||
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
|
pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
|
||||||
@ -282,6 +286,22 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize {
|
|||||||
return eh_frame_hdr_header_size + count * 8;
|
return eh_frame_hdr_header_size + count * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn calcEhFrameRelocs(elf_file: *Elf) usize {
|
||||||
|
var count: usize = 0;
|
||||||
|
for (elf_file.objects.items) |index| {
|
||||||
|
const object = elf_file.file(index).?.object;
|
||||||
|
for (object.cies.items) |cie| {
|
||||||
|
if (!cie.alive) continue;
|
||||||
|
count += cie.relocs(elf_file).len;
|
||||||
|
}
|
||||||
|
for (object.fdes.items) |fde| {
|
||||||
|
if (!fde.alive) continue;
|
||||||
|
count += fde.relocs(elf_file).len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {
|
fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file: *Elf, contents: []u8) !void {
|
||||||
const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow;
|
const offset = std.math.cast(usize, rel.r_offset - rec.offset) orelse return error.Overflow;
|
||||||
const P = @as(i64, @intCast(rec.address(elf_file) + offset));
|
const P = @as(i64, @intCast(rec.address(elf_file) + offset));
|
||||||
@ -357,6 +377,95 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
|
|||||||
try writer.writeInt(u32, 0, .little);
|
try writer.writeInt(u32, 0, .little);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
|
||||||
|
const gpa = elf_file.base.allocator;
|
||||||
|
|
||||||
|
for (elf_file.objects.items) |index| {
|
||||||
|
const object = elf_file.file(index).?.object;
|
||||||
|
|
||||||
|
for (object.cies.items) |cie| {
|
||||||
|
if (!cie.alive) continue;
|
||||||
|
try writer.writeAll(cie.data(elf_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (elf_file.objects.items) |index| {
|
||||||
|
const object = elf_file.file(index).?.object;
|
||||||
|
|
||||||
|
for (object.fdes.items) |fde| {
|
||||||
|
if (!fde.alive) continue;
|
||||||
|
|
||||||
|
const contents = try gpa.dupe(u8, fde.data(elf_file));
|
||||||
|
defer gpa.free(contents);
|
||||||
|
|
||||||
|
std.mem.writeInt(
|
||||||
|
i32,
|
||||||
|
contents[4..8],
|
||||||
|
@truncate(@as(i64, @intCast(fde.out_offset + 4)) - @as(i64, @intCast(fde.cie(elf_file).out_offset))),
|
||||||
|
.little,
|
||||||
|
);
|
||||||
|
|
||||||
|
try writer.writeAll(contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
|
||||||
|
const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset;
|
||||||
|
const r_type = rel.r_type();
|
||||||
|
var r_addend = rel.r_addend;
|
||||||
|
var r_sym: u32 = 0;
|
||||||
|
switch (sym.type(elf_file)) {
|
||||||
|
elf.STT_SECTION => {
|
||||||
|
r_addend += @intCast(sym.value);
|
||||||
|
r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
r_sym = sym.outputSymtabIndex(elf_file) orelse 0;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{
|
||||||
|
Atom.fmtRelocType(r_type),
|
||||||
|
r_offset,
|
||||||
|
r_sym,
|
||||||
|
sym.name(elf_file),
|
||||||
|
r_addend,
|
||||||
|
});
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.r_offset = r_offset,
|
||||||
|
.r_addend = r_addend,
|
||||||
|
.r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
|
||||||
|
relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr});
|
||||||
|
|
||||||
|
for (elf_file.objects.items) |index| {
|
||||||
|
const object = elf_file.file(index).?.object;
|
||||||
|
|
||||||
|
for (object.cies.items) |cie| {
|
||||||
|
if (!cie.alive) continue;
|
||||||
|
for (cie.relocs(elf_file)) |rel| {
|
||||||
|
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
|
||||||
|
const out_rel = emitReloc(elf_file, cie, sym, rel);
|
||||||
|
try writer.writeStruct(out_rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (object.fdes.items) |fde| {
|
||||||
|
if (!fde.alive) continue;
|
||||||
|
for (fde.relocs(elf_file)) |rel| {
|
||||||
|
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
|
||||||
|
const out_rel = emitReloc(elf_file, fde, sym, rel);
|
||||||
|
try writer.writeStruct(out_rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
|
pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
|
||||||
try writer.writeByte(1); // version
|
try writer.writeByte(1); // version
|
||||||
try writer.writeByte(EH_PE.pcrel | EH_PE.sdata4);
|
try writer.writeByte(EH_PE.pcrel | EH_PE.sdata4);
|
||||||
|
|||||||
@ -127,22 +127,22 @@ pub const File = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateSymtabSize(file: File, elf_file: *Elf) void {
|
pub fn updateSymtabSize(file: File, elf_file: *Elf) !void {
|
||||||
const output_symtab_size = switch (file) {
|
const output_symtab_ctx = switch (file) {
|
||||||
inline else => |x| &x.output_symtab_size,
|
inline else => |x| &x.output_symtab_ctx,
|
||||||
};
|
};
|
||||||
for (file.locals()) |local_index| {
|
for (file.locals()) |local_index| {
|
||||||
const local = elf_file.symbol(local_index);
|
const local = elf_file.symbol(local_index);
|
||||||
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||||
const esym = local.elfSym(elf_file);
|
const esym = local.elfSym(elf_file);
|
||||||
switch (esym.st_type()) {
|
switch (esym.st_type()) {
|
||||||
elf.STT_SECTION => if (!elf_file.isRelocatable()) continue,
|
elf.STT_SECTION, elf.STT_NOTYPE => continue,
|
||||||
elf.STT_NOTYPE => continue,
|
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
local.flags.output_symtab = true;
|
local.flags.output_symtab = true;
|
||||||
output_symtab_size.nlocals += 1;
|
try local.setOutputSymtabIndex(output_symtab_ctx.nlocals, elf_file);
|
||||||
output_symtab_size.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
|
output_symtab_ctx.nlocals += 1;
|
||||||
|
output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (file.globals()) |global_index| {
|
for (file.globals()) |global_index| {
|
||||||
@ -152,47 +152,38 @@ pub const File = union(enum) {
|
|||||||
if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
if (global.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
|
||||||
global.flags.output_symtab = true;
|
global.flags.output_symtab = true;
|
||||||
if (global.isLocal(elf_file)) {
|
if (global.isLocal(elf_file)) {
|
||||||
output_symtab_size.nlocals += 1;
|
try global.setOutputSymtabIndex(output_symtab_ctx.nlocals, elf_file);
|
||||||
|
output_symtab_ctx.nlocals += 1;
|
||||||
} else {
|
} else {
|
||||||
output_symtab_size.nglobals += 1;
|
try global.setOutputSymtabIndex(output_symtab_ctx.nglobals, elf_file);
|
||||||
|
output_symtab_ctx.nglobals += 1;
|
||||||
}
|
}
|
||||||
output_symtab_size.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
|
output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeSymtab(file: File, elf_file: *Elf, ctx: anytype) void {
|
pub fn writeSymtab(file: File, elf_file: *Elf) void {
|
||||||
var ilocal: usize = ctx.ilocal;
|
|
||||||
for (file.locals()) |local_index| {
|
for (file.locals()) |local_index| {
|
||||||
const local = elf_file.symbol(local_index);
|
const local = elf_file.symbol(local_index);
|
||||||
if (!local.flags.output_symtab) continue;
|
const idx = local.outputSymtabIndex(elf_file) orelse continue;
|
||||||
const out_sym = &elf_file.symtab.items[ilocal];
|
const out_sym = &elf_file.symtab.items[idx];
|
||||||
out_sym.st_name = @intCast(elf_file.strtab.items.len);
|
out_sym.st_name = @intCast(elf_file.strtab.items.len);
|
||||||
elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
|
elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
|
||||||
elf_file.strtab.appendAssumeCapacity(0);
|
elf_file.strtab.appendAssumeCapacity(0);
|
||||||
local.setOutputSym(elf_file, out_sym);
|
local.setOutputSym(elf_file, out_sym);
|
||||||
ilocal += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var iglobal: usize = ctx.iglobal;
|
|
||||||
for (file.globals()) |global_index| {
|
for (file.globals()) |global_index| {
|
||||||
const global = elf_file.symbol(global_index);
|
const global = elf_file.symbol(global_index);
|
||||||
const file_ptr = global.file(elf_file) orelse continue;
|
const file_ptr = global.file(elf_file) orelse continue;
|
||||||
if (file_ptr.index() != file.index()) continue;
|
if (file_ptr.index() != file.index()) continue;
|
||||||
if (!global.flags.output_symtab) continue;
|
const idx = global.outputSymtabIndex(elf_file) orelse continue;
|
||||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||||
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
|
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
|
||||||
elf_file.strtab.appendAssumeCapacity(0);
|
elf_file.strtab.appendAssumeCapacity(0);
|
||||||
if (global.isLocal(elf_file)) {
|
const out_sym = &elf_file.symtab.items[idx];
|
||||||
const out_sym = &elf_file.symtab.items[ilocal];
|
out_sym.st_name = st_name;
|
||||||
out_sym.st_name = st_name;
|
global.setOutputSym(elf_file, out_sym);
|
||||||
global.setOutputSym(elf_file, out_sym);
|
|
||||||
ilocal += 1;
|
|
||||||
} else {
|
|
||||||
const out_sym = &elf_file.symtab.items[iglobal];
|
|
||||||
out_sym.st_name = st_name;
|
|
||||||
global.setOutputSym(elf_file, out_sym);
|
|
||||||
iglobal += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -222,7 +222,7 @@ pub const DynamicSection = struct {
|
|||||||
|
|
||||||
pub const ZigGotSection = struct {
|
pub const ZigGotSection = struct {
|
||||||
entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
flags: Flags = .{},
|
flags: Flags = .{},
|
||||||
|
|
||||||
const Flags = packed struct {
|
const Flags = packed struct {
|
||||||
@ -359,15 +359,15 @@ pub const ZigGotSection = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
|
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
|
||||||
zig_got.output_symtab_size.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
|
zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
|
||||||
for (zig_got.entries.items) |entry| {
|
for (zig_got.entries.items) |entry| {
|
||||||
const name = elf_file.symbol(entry).name(elf_file);
|
const name = elf_file.symbol(entry).name(elf_file);
|
||||||
zig_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
|
zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf, ctx: anytype) void {
|
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
|
||||||
for (zig_got.entries.items, ctx.ilocal.., 0..) |entry, ilocal, index| {
|
for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
|
||||||
const symbol = elf_file.symbol(entry);
|
const symbol = elf_file.symbol(entry);
|
||||||
const symbol_name = symbol.name(elf_file);
|
const symbol_name = symbol.name(elf_file);
|
||||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||||
@ -420,7 +420,7 @@ pub const ZigGotSection = struct {
|
|||||||
|
|
||||||
pub const GotSection = struct {
|
pub const GotSection = struct {
|
||||||
entries: std.ArrayListUnmanaged(Entry) = .{},
|
entries: std.ArrayListUnmanaged(Entry) = .{},
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
tlsld_index: ?u32 = null,
|
tlsld_index: ?u32 = null,
|
||||||
flags: Flags = .{},
|
flags: Flags = .{},
|
||||||
|
|
||||||
@ -760,18 +760,18 @@ pub const GotSection = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
|
pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
|
||||||
got.output_symtab_size.nlocals = @as(u32, @intCast(got.entries.items.len));
|
got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len));
|
||||||
for (got.entries.items) |entry| {
|
for (got.entries.items) |entry| {
|
||||||
const symbol_name = switch (entry.tag) {
|
const symbol_name = switch (entry.tag) {
|
||||||
.tlsld => "",
|
.tlsld => "",
|
||||||
inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
|
inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
|
||||||
};
|
};
|
||||||
got.output_symtab_size.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
|
got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) void {
|
pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {
|
||||||
for (got.entries.items, ctx.ilocal..) |entry, ilocal| {
|
for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {
|
||||||
const symbol = switch (entry.tag) {
|
const symbol = switch (entry.tag) {
|
||||||
.tlsld => null,
|
.tlsld => null,
|
||||||
inline else => elf_file.symbol(entry.symbol_index),
|
inline else => elf_file.symbol(entry.symbol_index),
|
||||||
@ -831,7 +831,7 @@ pub const GotSection = struct {
|
|||||||
|
|
||||||
pub const PltSection = struct {
|
pub const PltSection = struct {
|
||||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
|
|
||||||
pub const preamble_size = 32;
|
pub const preamble_size = 32;
|
||||||
|
|
||||||
@ -909,15 +909,15 @@ pub const PltSection = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
|
pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
|
||||||
plt.output_symtab_size.nlocals = @as(u32, @intCast(plt.symbols.items.len));
|
plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len));
|
||||||
for (plt.symbols.items) |sym_index| {
|
for (plt.symbols.items) |sym_index| {
|
||||||
const name = elf_file.symbol(sym_index).name(elf_file);
|
const name = elf_file.symbol(sym_index).name(elf_file);
|
||||||
plt.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
|
plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeSymtab(plt: PltSection, elf_file: *Elf, ctx: anytype) void {
|
pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {
|
||||||
var ilocal = ctx.ilocal;
|
var ilocal = plt.output_symtab_ctx.ilocal;
|
||||||
for (plt.symbols.items) |sym_index| {
|
for (plt.symbols.items) |sym_index| {
|
||||||
const sym = elf_file.symbol(sym_index);
|
const sym = elf_file.symbol(sym_index);
|
||||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||||
@ -968,7 +968,7 @@ pub const GotPltSection = struct {
|
|||||||
|
|
||||||
pub const PltGotSection = struct {
|
pub const PltGotSection = struct {
|
||||||
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
||||||
output_symtab_size: Elf.SymtabSize = .{},
|
output_symtab_ctx: Elf.SymtabCtx = .{},
|
||||||
|
|
||||||
pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
|
pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
|
||||||
plt_got.symbols.deinit(allocator);
|
plt_got.symbols.deinit(allocator);
|
||||||
@ -1008,15 +1008,15 @@ pub const PltGotSection = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
|
pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
|
||||||
plt_got.output_symtab_size.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
|
plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
|
||||||
for (plt_got.symbols.items) |sym_index| {
|
for (plt_got.symbols.items) |sym_index| {
|
||||||
const name = elf_file.symbol(sym_index).name(elf_file);
|
const name = elf_file.symbol(sym_index).name(elf_file);
|
||||||
plt_got.output_symtab_size.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
|
plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf, ctx: anytype) void {
|
pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {
|
||||||
var ilocal = ctx.ilocal;
|
var ilocal = plt_got.output_symtab_ctx.ilocal;
|
||||||
for (plt_got.symbols.items) |sym_index| {
|
for (plt_got.symbols.items) |sym_index| {
|
||||||
const sym = elf_file.symbol(sym_index);
|
const sym = elf_file.symbol(sym_index);
|
||||||
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
|
||||||
@ -1499,6 +1499,54 @@ pub const VerneedSection = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ComdatGroupSection = struct {
|
||||||
|
shndx: u32,
|
||||||
|
cg_index: u32,
|
||||||
|
|
||||||
|
fn file(cgs: ComdatGroupSection, elf_file: *Elf) ?File {
|
||||||
|
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||||
|
const cg_owner = elf_file.comdatGroupOwner(cg.owner);
|
||||||
|
return elf_file.file(cg_owner.file);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
|
||||||
|
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||||
|
const object = cgs.file(elf_file).?.object;
|
||||||
|
const shdr = object.shdrs.items[cg.shndx];
|
||||||
|
return object.symbols.items[shdr.sh_info];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {
|
||||||
|
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||||
|
const object = cgs.file(elf_file).?.object;
|
||||||
|
const members = object.comdatGroupMembers(cg.shndx);
|
||||||
|
return (members.len + 1) * @sizeOf(u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write(cgs: ComdatGroupSection, elf_file: *Elf, writer: anytype) !void {
|
||||||
|
const cg = elf_file.comdatGroup(cgs.cg_index);
|
||||||
|
const object = cgs.file(elf_file).?.object;
|
||||||
|
const members = object.comdatGroupMembers(cg.shndx);
|
||||||
|
try writer.writeInt(u32, elf.GRP_COMDAT, .little);
|
||||||
|
for (members) |shndx| {
|
||||||
|
const shdr = object.shdrs.items[shndx];
|
||||||
|
switch (shdr.sh_type) {
|
||||||
|
elf.SHT_RELA => {
|
||||||
|
const atom_index = object.atoms.items[shdr.sh_info];
|
||||||
|
const atom = elf_file.atom(atom_index).?;
|
||||||
|
const rela = elf_file.output_rela_sections.get(atom.outputShndx().?).?;
|
||||||
|
try writer.writeInt(u32, rela.shndx, .little);
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
const atom_index = object.atoms.items[shndx];
|
||||||
|
const atom = elf_file.atom(atom_index).?;
|
||||||
|
try writer.writeInt(u32, atom.outputShndx().?, .little);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
|
fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
|
||||||
const entry_size = elf_file.archPtrWidthBytes();
|
const entry_size = elf_file.archPtrWidthBytes();
|
||||||
const endian = elf_file.base.options.target.cpu.arch.endian();
|
const endian = elf_file.base.options.target.cpu.arch.endian();
|
||||||
|
|||||||
@ -21,6 +21,11 @@ pub fn build(b: *Build) void {
|
|||||||
.abi = .gnu,
|
.abi = .gnu,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Exercise linker in -r mode
|
||||||
|
elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = musl_target }));
|
||||||
|
elf_step.dependOn(testEmitRelocatable(b, .{ .target = musl_target }));
|
||||||
|
elf_step.dependOn(testRelocatableEhFrame(b, .{ .target = musl_target }));
|
||||||
|
|
||||||
// Exercise linker in ar mode
|
// Exercise linker in ar mode
|
||||||
elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
|
elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target }));
|
||||||
|
|
||||||
@ -629,6 +634,53 @@ fn testDsoUndef(b: *Build, opts: Options) *Step {
|
|||||||
return test_step;
|
return test_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn testEmitRelocatable(b: *Build, opts: Options) *Step {
|
||||||
|
const test_step = addTestStep(b, "emit-relocatable", opts);
|
||||||
|
|
||||||
|
const obj1 = addObject(b, "obj1", opts);
|
||||||
|
addZigSourceBytes(obj1,
|
||||||
|
\\const std = @import("std");
|
||||||
|
\\extern var bar: i32;
|
||||||
|
\\export fn foo() i32 {
|
||||||
|
\\ return bar;
|
||||||
|
\\}
|
||||||
|
\\export fn printFoo() void {
|
||||||
|
\\ std.debug.print("foo={d}\n", .{foo()});
|
||||||
|
\\}
|
||||||
|
);
|
||||||
|
addCSourceBytes(obj1,
|
||||||
|
\\#include <stdio.h>
|
||||||
|
\\int bar = 42;
|
||||||
|
\\void printBar() {
|
||||||
|
\\ fprintf(stderr, "bar=%d\n", bar);
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
obj1.linkLibC();
|
||||||
|
|
||||||
|
const exe = addExecutable(b, "test", opts);
|
||||||
|
addZigSourceBytes(exe,
|
||||||
|
\\const std = @import("std");
|
||||||
|
\\extern fn printFoo() void;
|
||||||
|
\\extern fn printBar() void;
|
||||||
|
\\pub fn main() void {
|
||||||
|
\\ printFoo();
|
||||||
|
\\ printBar();
|
||||||
|
\\}
|
||||||
|
);
|
||||||
|
exe.addObject(obj1);
|
||||||
|
exe.linkLibC();
|
||||||
|
|
||||||
|
const run = addRunArtifact(exe);
|
||||||
|
run.expectStdErrEqual(
|
||||||
|
\\foo=42
|
||||||
|
\\bar=42
|
||||||
|
\\
|
||||||
|
);
|
||||||
|
test_step.dependOn(&run.step);
|
||||||
|
|
||||||
|
return test_step;
|
||||||
|
}
|
||||||
|
|
||||||
fn testEmitStaticLib(b: *Build, opts: Options) *Step {
|
fn testEmitStaticLib(b: *Build, opts: Options) *Step {
|
||||||
const test_step = addTestStep(b, "emit-static-lib", opts);
|
const test_step = addTestStep(b, "emit-static-lib", opts);
|
||||||
|
|
||||||
@ -951,7 +1003,6 @@ fn testGcSectionsZig(b: *Build, opts: Options) *Step {
|
|||||||
const obj = addObject(b, "obj", .{
|
const obj = addObject(b, "obj", .{
|
||||||
.target = opts.target,
|
.target = opts.target,
|
||||||
.use_llvm = true,
|
.use_llvm = true,
|
||||||
.use_lld = true,
|
|
||||||
});
|
});
|
||||||
addCSourceBytes(obj,
|
addCSourceBytes(obj,
|
||||||
\\int live_var1 = 1;
|
\\int live_var1 = 1;
|
||||||
@ -2089,6 +2140,89 @@ fn testPreinitArray(b: *Build, opts: Options) *Step {
|
|||||||
return test_step;
|
return test_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn testRelocatableEhFrame(b: *Build, opts: Options) *Step {
|
||||||
|
const test_step = addTestStep(b, "relocatable-eh-frame", opts);
|
||||||
|
|
||||||
|
{
|
||||||
|
const obj = addObject(b, "obj1", opts);
|
||||||
|
addCppSourceBytes(obj,
|
||||||
|
\\#include <stdexcept>
|
||||||
|
\\int try_me() {
|
||||||
|
\\ throw std::runtime_error("Oh no!");
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
addCppSourceBytes(obj,
|
||||||
|
\\extern int try_me();
|
||||||
|
\\int try_again() {
|
||||||
|
\\ return try_me();
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
obj.linkLibCpp();
|
||||||
|
|
||||||
|
const exe = addExecutable(b, "test1", opts);
|
||||||
|
addCppSourceBytes(exe,
|
||||||
|
\\#include <iostream>
|
||||||
|
\\#include <stdexcept>
|
||||||
|
\\extern int try_again();
|
||||||
|
\\int main() {
|
||||||
|
\\ try {
|
||||||
|
\\ try_again();
|
||||||
|
\\ } catch (const std::exception &e) {
|
||||||
|
\\ std::cout << "exception=" << e.what();
|
||||||
|
\\ }
|
||||||
|
\\ return 0;
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
exe.addObject(obj);
|
||||||
|
exe.linkLibCpp();
|
||||||
|
|
||||||
|
const run = addRunArtifact(exe);
|
||||||
|
run.expectStdOutEqual("exception=Oh no!");
|
||||||
|
test_step.dependOn(&run.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Let's make the object file COMDAT group heavy!
|
||||||
|
const obj = addObject(b, "obj2", opts);
|
||||||
|
addCppSourceBytes(obj,
|
||||||
|
\\#include <stdexcept>
|
||||||
|
\\int try_me() {
|
||||||
|
\\ throw std::runtime_error("Oh no!");
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
addCppSourceBytes(obj,
|
||||||
|
\\extern int try_me();
|
||||||
|
\\int try_again() {
|
||||||
|
\\ return try_me();
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
addCppSourceBytes(obj,
|
||||||
|
\\#include <iostream>
|
||||||
|
\\#include <stdexcept>
|
||||||
|
\\extern int try_again();
|
||||||
|
\\int main() {
|
||||||
|
\\ try {
|
||||||
|
\\ try_again();
|
||||||
|
\\ } catch (const std::exception &e) {
|
||||||
|
\\ std::cout << "exception=" << e.what();
|
||||||
|
\\ }
|
||||||
|
\\ return 0;
|
||||||
|
\\}
|
||||||
|
, &.{});
|
||||||
|
obj.linkLibCpp();
|
||||||
|
|
||||||
|
const exe = addExecutable(b, "test2", opts);
|
||||||
|
exe.addObject(obj);
|
||||||
|
exe.linkLibCpp();
|
||||||
|
|
||||||
|
const run = addRunArtifact(exe);
|
||||||
|
run.expectStdOutEqual("exception=Oh no!");
|
||||||
|
test_step.dependOn(&run.step);
|
||||||
|
}
|
||||||
|
|
||||||
|
return test_step;
|
||||||
|
}
|
||||||
|
|
||||||
fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
|
fn testSharedAbsSymbol(b: *Build, opts: Options) *Step {
|
||||||
const test_step = addTestStep(b, "shared-abs-symbol", opts);
|
const test_step = addTestStep(b, "shared-abs-symbol", opts);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user