elf: nuke ZigGotSection from existence

This commit is contained in:
Jakub Konka 2024-08-09 09:10:59 +02:00
parent 4c2b34e8ab
commit d328140858
8 changed files with 30 additions and 438 deletions

View File

@ -110,21 +110,11 @@ pub fn emitMir(emit: *Emit) Error!void {
});
},
.linker_reloc => |data| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
const is_obj_or_static_lib = switch (emit.lower.output_mode) {
.Exe => false,
.Obj => true,
.Lib => emit.lower.link_mode == .static,
};
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const sym = zo.symbol(data.sym_index);
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
_ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file);
}
if (emit.lower.pic) {
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
link.File.Elf.R_ZIG_GOTPCREL
else if (sym.flags.needs_got)
const r_type: u32 = if (sym.flags.needs_got)
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
else
@intFromEnum(std.elf.R_X86_64.PC32);
@ -134,28 +124,17 @@ pub fn emitMir(emit: *Emit) Error!void {
.r_addend = -4,
});
} else {
if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) {
const r_type = @intFromEnum(std.elf.R_X86_64.PC32);
try atom.addReloc(elf_file, .{
.r_offset = end_offset - 4,
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
.r_addend = -4,
});
} else {
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
link.File.Elf.R_ZIG_GOT32
else if (sym.flags.needs_got)
@intFromEnum(std.elf.R_X86_64.GOT32)
else if (sym.flags.is_tls)
@intFromEnum(std.elf.R_X86_64.TPOFF32)
else
@intFromEnum(std.elf.R_X86_64.@"32");
try atom.addReloc(elf_file, .{
.r_offset = end_offset - 4,
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
.r_addend = 0,
});
}
const r_type: u32 = if (sym.flags.needs_got)
@intFromEnum(std.elf.R_X86_64.GOT32)
else if (sym.flags.is_tls)
@intFromEnum(std.elf.R_X86_64.TPOFF32)
else
@intFromEnum(std.elf.R_X86_64.@"32");
try atom.addReloc(elf_file, .{
.r_offset = end_offset - 4,
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
.r_addend = 0,
});
}
} else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
const is_obj_or_static_lib = switch (emit.lower.output_mode) {

View File

@ -398,30 +398,20 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
_ = lower.reloc(.{ .linker_reloc = sym });
break :op if (lower.pic) switch (mnemonic) {
.lea => {
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
},
.mov => {
if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea;
break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
},
.lea => break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
.mov => break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) },
else => unreachable,
} else switch (mnemonic) {
.call => break :op if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) .{
.imm = Immediate.s(0),
} else .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.call => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .ds },
}) },
.lea => {
emit_mnemonic = .mov;
break :op .{ .imm = Immediate.s(0) };
},
.mov => {
if (is_obj_or_static_lib and elf_sym.flags.needs_zig_got) emit_mnemonic = .lea;
break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .ds },
}) };
},
.mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
.base = .{ .reg = .ds },
}) },
else => unreachable,
};
} else if (lower.bin_file.cast(.macho)) |macho_file| {

View File

@ -64,9 +64,6 @@ phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
/// Tracked loadable segments during incremental linking.
/// The index into the program headers of a PT_LOAD program header with Read and Execute flags
phdr_zig_load_re_index: ?u16 = null,
/// The index into the program headers of the global offset table.
/// It needs PT_LOAD and Read flags.
phdr_zig_got_index: ?u16 = null,
/// The index into the program headers of a PT_LOAD program header with Read flag
phdr_zig_load_ro_index: ?u16 = null,
/// The index into the program headers of a PT_LOAD program header with Write flag
@ -130,8 +127,6 @@ plt_got: PltGotSection = .{},
copy_rel: CopyRelSection = .{},
/// .rela.plt section
rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
/// .got.zig section
zig_got: ZigGotSection = .{},
/// SHT_GROUP sections
/// Applies only to a relocatable.
comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{},
@ -142,7 +137,6 @@ zig_text_section_index: ?u32 = null,
zig_data_rel_ro_section_index: ?u32 = null,
zig_data_section_index: ?u32 = null,
zig_bss_section_index: ?u32 = null,
zig_got_section_index: ?u32 = null,
debug_info_section_index: ?u32 = null,
debug_abbrev_section_index: ?u32 = null,
@ -474,7 +468,6 @@ pub fn deinit(self: *Elf) void {
self.copy_rel.deinit(gpa);
self.rela_dyn.deinit(gpa);
self.rela_plt.deinit(gpa);
self.zig_got.deinit(gpa);
self.comdat_group_sections.deinit(gpa);
}
@ -618,21 +611,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
});
}
if (self.phdr_zig_got_index == null) {
const alignment = self.page_size;
const filesz = @as(u64, ptr_size) * options.symbol_count_hint;
const off = self.findFreeSpace(filesz, alignment);
self.phdr_zig_got_index = try self.addPhdr(.{
.type = elf.PT_LOAD,
.offset = off,
.filesz = filesz,
.addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
.memsz = filesz,
.@"align" = alignment,
.flags = elf.PF_R | elf.PF_W,
});
}
if (self.phdr_zig_load_ro_index == null) {
const alignment = self.page_size;
const filesz: u64 = 1024;
@ -701,27 +679,6 @@ pub fn initMetadata(self: *Elf, options: InitMetadataOptions) !void {
try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
}
if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
self.zig_got_section_index = try self.addSection(.{
.name = try self.insertShString(".got.zig"),
.type = elf.SHT_PROGBITS,
.addralign = ptr_size,
.flags = elf.SHF_ALLOC | elf.SHF_WRITE,
.offset = std.math.maxInt(u64),
});
const shdr = &self.shdrs.items[self.zig_got_section_index.?];
const phndx = self.phdr_zig_got_index.?;
const phdr = self.phdrs.items[phndx];
shdr.sh_addr = phdr.p_vaddr;
shdr.sh_offset = phdr.p_offset;
shdr.sh_size = phdr.p_memsz;
try self.phdr_to_shdr_table.putNoClobber(
gpa,
self.zig_got_section_index.?,
self.phdr_zig_got_index.?,
);
}
if (self.zig_data_rel_ro_section_index == null) {
self.zig_data_rel_ro_section_index = try self.addSection(.{
.name = try self.insertShString(".data.rel.ro.zig"),
@ -3156,8 +3113,8 @@ fn initSyntheticSections(self: *Elf) !void {
});
const needs_rela_dyn = blk: {
if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;
if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or self.copy_rel.symbols.items.len > 0)
break :blk true;
if (self.zigObjectPtr()) |zig_object| {
if (zig_object.num_dynrelocs > 0) break :blk true;
}
@ -3562,7 +3519,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
for (&[_]*?u16{
&self.phdr_zig_load_re_index,
&self.phdr_zig_got_index,
&self.phdr_zig_load_ro_index,
&self.phdr_zig_load_zerofill_index,
&self.phdr_table_index,
@ -3694,7 +3650,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) !void {
&self.versym_section_index,
&self.verneed_section_index,
&self.zig_text_section_index,
&self.zig_got_section_index,
&self.zig_data_rel_ro_section_index,
&self.zig_data_section_index,
&self.zig_bss_section_index,
@ -3893,7 +3848,7 @@ fn updateSectionSizes(self: *Elf) !void {
}
if (self.rela_dyn_section_index) |shndx| {
var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();
var num = self.got.numRela(self) + self.copy_rel.numRela();
if (self.zigObjectPtr()) |zig_object| {
num += zig_object.num_dynrelocs;
}
@ -4431,15 +4386,6 @@ pub fn updateSymtabSize(self: *Elf) !void {
strsize += ctx.strsize;
}
if (self.zigObjectPtr()) |_| {
if (self.zig_got_section_index) |_| {
self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
self.zig_got.updateSymtabSize(self);
nlocals += self.zig_got.output_symtab_ctx.nlocals;
strsize += self.zig_got.output_symtab_ctx.strsize;
}
}
if (self.got_section_index) |_| {
self.got.output_symtab_ctx.ilocal = nlocals + 1;
self.got.updateSymtabSize(self);
@ -4576,9 +4522,6 @@ fn writeSyntheticSections(self: *Elf) !void {
const shdr = self.shdrs.items[shndx];
try self.got.addRela(self);
try self.copy_rel.addRela(self);
if (self.zigObjectPtr()) |_| {
try self.zig_got.addRela(self);
}
self.sortRelaDyn();
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
}
@ -4674,10 +4617,6 @@ pub fn writeSymtab(self: *Elf) !void {
obj.asFile().writeSymtab(self);
}
if (self.zig_got_section_index) |_| {
self.zig_got.writeSymtab(self);
}
if (self.got_section_index) |_| {
self.got.writeSymtab(self);
}
@ -5085,7 +5024,6 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
self.zig_data_rel_ro_section_index,
self.zig_data_section_index,
self.zig_bss_section_index,
self.zig_got_section_index,
}) |maybe_index| {
if (maybe_index) |index| {
if (index == shndx) return true;
@ -5704,7 +5642,6 @@ fn fmtDumpState(
}
}
try writer.print("{}\n", .{self.zig_got.fmt(self)});
try writer.print("{}\n", .{self.got.fmt(self)});
try writer.print("{}\n", .{self.plt.fmt(self)});
@ -5995,20 +5932,12 @@ const RelaSection = struct {
};
const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
pub const R_ZIG_GOT32: u32 = 0xff00;
pub const R_ZIG_GOTPCREL: u32 = 0xff01;
pub const R_ZIG_GOT_HI20: u32 = 0xff02;
pub const R_ZIG_GOT_LO12: u32 = 0xff03;
pub const R_GOT_HI20_STATIC: u32 = 0xff04;
pub const R_GOT_LO12_I_STATIC: u32 = 0xff05;
// Comptime asserts that no Zig relocs overlap with another ISA's reloc number
comptime {
const zig_relocs = .{
R_ZIG_GOT32,
R_ZIG_GOT_HI20,
R_ZIG_GOT_LO12,
R_ZIG_GOTPCREL,
R_GOT_HI20_STATIC,
R_GOT_LO12_I_STATIC,
};
@ -6099,6 +6028,5 @@ const StringTable = @import("StringTable.zig");
const Thunk = thunks.Thunk;
const Value = @import("../Value.zig");
const VerneedSection = synthetic_sections.VerneedSection;
const ZigGotSection = synthetic_sections.ZigGotSection;
const ZigObject = @import("Elf/ZigObject.zig");
const riscv = @import("riscv.zig");

View File

@ -750,8 +750,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
const S = target.address(.{}, elf_file);
// Address of the global offset table.
const GOT = elf_file.gotAddress();
// Address of the .zig.got table entry if any.
const ZIG_GOT = target.zigGotAddress(elf_file);
// Address of the offset table entry if any.
const ZIG_GOT = target.zigOffsetTableAddress(elf_file);
// Relative offset to the start of the global offset table.
const G = target.gotAddress(elf_file) - GOT;
// // Address of the thread pointer.
@ -759,14 +759,13 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
// Address of the dynamic thread pointer.
const DTP = elf_file.dtpAddress();
relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ZG2({x}) ({s})", .{
relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
relocation.fmtRelocType(rel.r_type(), cpu_arch),
r_offset,
P,
S + A,
G + GOT + A,
ZIG_GOT + A,
target.zigOffsetTableAddress(elf_file) + A,
target.name(elf_file),
});
@ -1181,16 +1180,7 @@ const x86_64 = struct {
.TLSDESC_CALL,
=> {},
else => |x| switch (@intFromEnum(x)) {
// Zig custom relocations
Elf.R_ZIG_GOT32,
Elf.R_ZIG_GOTPCREL,
=> {
assert(symbol.flags.has_zig_got);
},
else => try atom.reportUnhandledRelocError(rel, elf_file),
},
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
}
@ -1228,7 +1218,7 @@ const x86_64 = struct {
.PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
.PC32 => {
const S_ = if (target.flags.zig_offset_table) target.zigOffsetTableAddress(elf_file) else S;
const S_ = if (target.flags.zig_offset_table) ZIG_GOT else S;
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
},
@ -1255,7 +1245,7 @@ const x86_64 = struct {
},
.@"32" => {
const S_ = if (target.flags.zig_offset_table) target.zigOffsetTableAddress(elf_file) else S;
const S_ = if (target.flags.zig_offset_table) ZIG_GOT else S;
try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S_ + A)))), .little);
},
.@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
@ -1336,13 +1326,7 @@ const x86_64 = struct {
.GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
else => |x| switch (@intFromEnum(x)) {
// Zig custom relocations
Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
else => try atom.reportUnhandledRelocError(rel, elf_file),
},
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
}
@ -2006,12 +1990,6 @@ const riscv = struct {
=> {},
else => |x| switch (@intFromEnum(x)) {
Elf.R_ZIG_GOT_HI20,
Elf.R_ZIG_GOT_LO12,
=> {
assert(symbol.flags.has_zig_got);
},
Elf.R_GOT_HI20_STATIC,
Elf.R_GOT_LO12_I_STATIC,
=> symbol.flags.needs_got = true,
@ -2038,6 +2016,7 @@ const riscv = struct {
const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
_ = TP;
_ = DTP;
_ = ZIG_GOT;
switch (r_type) {
.NONE => unreachable,
@ -2156,18 +2135,6 @@ const riscv = struct {
else => |x| switch (@intFromEnum(x)) {
// Zig custom relocations
Elf.R_ZIG_GOT_HI20 => {
assert(target.flags.has_zig_got);
const disp: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow);
riscv_util.writeInstU(code[r_offset..][0..4], disp);
},
Elf.R_ZIG_GOT_LO12 => {
assert(target.flags.has_zig_got);
const value: u32 = @bitCast(math.cast(i32, ZIG_GOT + A) orelse return error.Overflow);
riscv_util.writeInstI(code[r_offset..][0..4], value);
},
Elf.R_GOT_HI20_STATIC => {
assert(target.flags.has_got);
const disp: u32 = @bitCast(math.cast(i32, G + GOT + A) orelse return error.Overflow);

View File

@ -217,25 +217,6 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
return entry.address(elf_file);
}
const GetOrCreateZigGotEntryResult = struct {
found_existing: bool,
index: ZigGotSection.Index,
};
pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
assert(!elf_file.base.isRelocatable());
assert(symbol.flags.needs_zig_got);
if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got };
const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
return .{ .found_existing = false, .index = index };
}
pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_zig_got) return 0;
const extras = symbol.extra(elf_file);
return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
}
pub fn zigOffsetTableAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.zig_offset_table) return 0;
const zo = elf_file.zigObjectPtr().?;
@ -267,7 +248,6 @@ const AddExtraOpts = struct {
tlsgd: ?u32 = null,
gottp: ?u32 = null,
tlsdesc: ?u32 = null,
zig_got: ?u32 = null,
zig_offset_table: ?u32 = null,
};
@ -465,10 +445,6 @@ pub const Flags = packed struct {
needs_tlsdesc: bool = false,
has_tlsdesc: bool = false,
/// Whether the symbol contains .zig.got indirection.
needs_zig_got: bool = false,
has_zig_got: bool = false,
/// Whether the symbol is a TLS variable.
/// TODO this is really not needed if only we operated on esyms between
/// codegen and ZigObject.
@ -491,7 +467,6 @@ pub const Extra = struct {
tlsgd: u32 = 0,
gottp: u32 = 0,
tlsdesc: u32 = 0,
zig_got: u32 = 0,
merge_section: u32 = 0,
zig_offset_table: u32 = 0,
};

View File

@ -756,15 +756,7 @@ pub fn getOrCreateMetadataForLazySymbol(
.const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
};
switch (state_ptr.*) {
.unused => {
const gpa = elf_file.base.comp.gpa;
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const sym = self.symbol(symbol_index);
if (lazy_sym.kind != .code) {
sym.flags.needs_zig_got = true;
}
symbol_index_ptr.* = symbol_index;
},
.unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0),
.pending_flush => return symbol_index_ptr.*,
.flushed => {},
}
@ -818,9 +810,6 @@ pub fn getOrCreateMetadataForNav(
sym.flags.is_tls = true;
}
}
if (!sym.flags.is_tls and nav_val.typeOf(zcu).zigTypeTag(zcu) != .Fn) {
sym.flags.needs_zig_got = true;
}
gop.value_ptr.* = .{ .symbol_index = symbol_index };
}
return gop.value_ptr.symbol_index;
@ -921,14 +910,6 @@ fn updateNavCode(
sym.value = 0;
esym.st_value = 0;
if (stt_bits != elf.STT_FUNC) {
if (!elf_file.base.isRelocatable()) {
log.debug(" (writing new offset table entry)", .{});
assert(sym.flags.has_zig_got);
const extra = sym.extra(elf_file);
try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
}
}
if (stt_bits == elf.STT_FUNC) {
const extra = sym.extra(elf_file);
const offset_table = self.offsetTablePtr().?;
@ -944,13 +925,6 @@ fn updateNavCode(
sym.value = 0;
esym.st_value = 0;
if (stt_bits != elf.STT_FUNC) {
sym.flags.needs_zig_got = true;
if (!elf_file.base.isRelocatable()) {
const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
try elf_file.zig_got.writeOne(elf_file, gop.index);
}
}
}
if (elf_file.base.child_pid) |pid| {
@ -1278,16 +1252,8 @@ fn updateLazySymbol(
errdefer self.freeNavMetadata(elf_file, symbol_index);
local_sym.value = 0;
if (sym.kind != .code) {
local_sym.flags.needs_zig_got = true;
}
local_esym.st_value = 0;
if (!elf_file.base.isRelocatable()) {
const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
try elf_file.zig_got.writeOne(elf_file, gop.index);
}
const shdr = elf_file.shdrs.items[output_section_index];
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
try elf_file.base.file.?.pwriteAll(code, file_offset);

View File

@ -113,10 +113,6 @@ fn formatRelocType(
_ = options;
const r_type = ctx.r_type;
switch (r_type) {
Elf.R_ZIG_GOT32 => try writer.writeAll("R_ZIG_GOT32"),
Elf.R_ZIG_GOTPCREL => try writer.writeAll("R_ZIG_GOTPCREL"),
Elf.R_ZIG_GOT_HI20 => try writer.writeAll("R_ZIG_GOT_HI20"),
Elf.R_ZIG_GOT_LO12 => try writer.writeAll("R_ZIG_GOT_LO12"),
Elf.R_GOT_HI20_STATIC => try writer.writeAll("R_GOT_HI20_STATIC"),
Elf.R_GOT_LO12_I_STATIC => try writer.writeAll("R_GOT_LO12_I_STATIC"),
else => switch (ctx.cpu_arch) {

View File

@ -223,215 +223,6 @@ pub const DynamicSection = struct {
}
};
pub const ZigGotSection = struct {
entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
output_symtab_ctx: Elf.SymtabCtx = .{},
flags: Flags = .{},
const Flags = packed struct {
needs_rela: bool = false,
dirty: bool = false,
};
pub const Index = u32;
pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void {
zig_got.entries.deinit(allocator);
}
fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index {
try zig_got.entries.ensureUnusedCapacity(allocator, 1);
// TODO add free list
const index = @as(Index, @intCast(zig_got.entries.items.len));
_ = zig_got.entries.addOneAssumeCapacity();
zig_got.flags.dirty = true;
return index;
}
pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const zo = elf_file.zigObjectPtr().?;
const index = try zig_got.allocateEntry(gpa);
const entry = &zig_got.entries.items[index];
entry.* = sym_index;
const symbol = zo.symbol(sym_index);
symbol.flags.has_zig_got = true;
if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
zig_got.flags.needs_rela = true;
}
symbol.addExtra(.{ .zig_got = index }, elf_file);
return index;
}
pub fn entryOffset(zig_got: ZigGotSection, index: Index, elf_file: *Elf) u64 {
_ = zig_got;
const entry_size = elf_file.archPtrWidthBytes();
const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];
return shdr.sh_offset + @as(u64, entry_size) * index;
}
pub fn entryAddress(zig_got: ZigGotSection, index: Index, elf_file: *Elf) i64 {
_ = zig_got;
const entry_size = elf_file.archPtrWidthBytes();
const shdr = elf_file.shdrs.items[elf_file.zig_got_section_index.?];
return @as(i64, @intCast(shdr.sh_addr)) + entry_size * index;
}
pub fn size(zig_got: ZigGotSection, elf_file: *Elf) usize {
return elf_file.archPtrWidthBytes() * zig_got.entries.items.len;
}
pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void {
const zo = elf_file.zigObjectPtr().?;
if (zig_got.flags.dirty) {
const needed_size = zig_got.size(elf_file);
try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size);
zig_got.flags.dirty = false;
}
const entry_size: u16 = elf_file.archPtrWidthBytes();
const target = elf_file.getTarget();
const endian = target.cpu.arch.endian();
const off = zig_got.entryOffset(index, elf_file);
const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));
const entry = zig_got.entries.items[index];
const value = zo.symbol(entry).address(.{}, elf_file);
switch (entry_size) {
2 => {
var buf: [2]u8 = undefined;
std.mem.writeInt(u16, &buf, @intCast(value), endian);
try elf_file.base.file.?.pwriteAll(&buf, off);
},
4 => {
var buf: [4]u8 = undefined;
std.mem.writeInt(u32, &buf, @intCast(value), endian);
try elf_file.base.file.?.pwriteAll(&buf, off);
},
8 => {
var buf: [8]u8 = undefined;
std.mem.writeInt(u64, &buf, @intCast(value), endian);
try elf_file.base.file.?.pwriteAll(&buf, off);
if (elf_file.base.child_pid) |pid| {
switch (builtin.os.tag) {
.linux => {
var local_vec: [1]std.posix.iovec_const = .{.{
.base = &buf,
.len = buf.len,
}};
var remote_vec: [1]std.posix.iovec_const = .{.{
.base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
.len = buf.len,
}};
const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
switch (std.os.linux.E.init(rc)) {
.SUCCESS => assert(rc == buf.len),
else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
}
},
else => return error.HotSwapUnavailableOnHostOperatingSystem,
}
}
},
else => unreachable,
}
}
pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void {
const zo = elf_file.zigObjectPtr().?;
for (zig_got.entries.items) |entry| {
const symbol = zo.symbol(entry);
const value = symbol.address(.{ .plt = false }, elf_file);
try writeInt(value, elf_file, writer);
}
}
pub fn numRela(zig_got: ZigGotSection) usize {
return zig_got.entries.items.len;
}
pub fn addRela(zig_got: ZigGotSection, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
const zo = elf_file.zigObjectPtr().?;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela());
for (zig_got.entries.items) |entry| {
const symbol = zo.symbol(entry);
const offset = symbol.zigGotAddress(elf_file);
elf_file.addRelaDynAssumeCapacity(.{
.offset = @intCast(offset),
.type = relocation.encode(.rel, cpu_arch),
.addend = symbol.address(.{ .plt = false }, elf_file),
});
}
}
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
const zo = elf_file.zigObjectPtr().?;
zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
for (zig_got.entries.items) |entry| {
const name = zo.symbol(entry).name(elf_file);
zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
}
}
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
const zo = elf_file.zigObjectPtr().?;
for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
const symbol = zo.symbol(entry);
const symbol_name = symbol.name(elf_file);
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
elf_file.strtab.appendSliceAssumeCapacity("$ziggot");
elf_file.strtab.appendAssumeCapacity(0);
const st_value = zig_got.entryAddress(@intCast(index), elf_file);
const st_size = elf_file.archPtrWidthBytes();
elf_file.symtab.items[ilocal] = .{
.st_name = st_name,
.st_info = elf.STT_OBJECT,
.st_other = 0,
.st_shndx = @intCast(elf_file.zig_got_section_index.?),
.st_value = @intCast(st_value),
.st_size = st_size,
};
}
}
const FormatCtx = struct {
zig_got: ZigGotSection,
elf_file: *Elf,
};
pub fn fmt(zig_got: ZigGotSection, elf_file: *Elf) std.fmt.Formatter(format2) {
return .{ .data = .{ .zig_got = zig_got, .elf_file = elf_file } };
}
pub fn format2(
ctx: FormatCtx,
comptime unused_fmt_string: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = options;
_ = unused_fmt_string;
const zig_got = ctx.zig_got;
const elf_file = ctx.elf_file;
try writer.writeAll(".zig.got\n");
for (zig_got.entries.items, 0..) |entry, index| {
const zo = elf_file.zigObjectPtr().?;
const symbol = zo.symbol(entry);
try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
index,
zig_got.entryAddress(@intCast(index), elf_file),
entry,
symbol.address(.{}, elf_file),
symbol.name(elf_file),
});
}
}
};
pub const GotSection = struct {
entries: std.ArrayListUnmanaged(Entry) = .{},
output_symtab_ctx: Elf.SymtabCtx = .{},