link.Elf: update to not use GenericWriter

This commit is contained in:
Andrew Kelley 2025-08-16 20:01:30 -07:00
parent cc931660eb
commit 6713745ec4
9 changed files with 244 additions and 291 deletions

View File

@ -811,10 +811,6 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
if (self.base.gc_sections) {
try gc.gcAtoms(self);
if (self.base.print_gc_sections) {
try gc.dumpPrunedAtoms(self);
}
}
self.checkDuplicates() catch |err| switch (err) {
@ -3005,7 +3001,7 @@ fn writeAtoms(self: *Elf) !void {
undefs.deinit();
}
var buffer = std.array_list.Managed(u8).init(gpa);
var buffer: std.Io.Writer.Allocating = .init(gpa);
defer buffer.deinit();
const slice = self.sections.slice();
@ -3032,9 +3028,9 @@ fn writeAtoms(self: *Elf) !void {
try buffer.ensureUnusedCapacity(thunk_size);
const shdr = slice.items(.shdr)[th.output_section_index];
const offset = @as(u64, @intCast(th.value)) + shdr.sh_offset;
try th.write(self, buffer.writer());
assert(buffer.items.len == thunk_size);
try self.pwriteAll(buffer.items, offset);
try th.write(self, &buffer.writer);
assert(buffer.written().len == thunk_size);
try self.pwriteAll(buffer.written(), offset);
buffer.clearRetainingCapacity();
}
}
@ -3166,26 +3162,26 @@ fn writeSyntheticSections(self: *Elf) !void {
if (self.section_indexes.verneed) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.verneed.size());
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.verneed.size());
defer buffer.deinit();
try self.verneed.write(buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.verneed.write(&buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.dynamic) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.dynamic.size(self));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.dynamic.size(self));
defer buffer.deinit();
try self.dynamic.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.dynamic.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.dynsymtab) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.dynsym.size());
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.dynsym.size());
defer buffer.deinit();
try self.dynsym.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.dynsym.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.dynstrtab) |shndx| {
@ -3201,28 +3197,28 @@ fn writeSyntheticSections(self: *Elf) !void {
};
const shdr = slice.items(.shdr)[shndx];
const sh_size = try self.cast(usize, shdr.sh_size);
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, @intCast(sh_size - existing_size));
defer buffer.deinit();
try eh_frame.writeEhFrame(self, buffer.writer());
assert(buffer.items.len == sh_size - existing_size);
try self.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
try eh_frame.writeEhFrame(self, &buffer.writer);
assert(buffer.written().len == sh_size - existing_size);
try self.pwriteAll(buffer.written(), shdr.sh_offset + existing_size);
}
if (self.section_indexes.eh_frame_hdr) |shndx| {
const shdr = slice.items(.shdr)[shndx];
const sh_size = try self.cast(usize, shdr.sh_size);
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, sh_size);
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, sh_size);
defer buffer.deinit();
try eh_frame.writeEhFrameHdr(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try eh_frame.writeEhFrameHdr(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.got) |index| {
const shdr = slice.items(.shdr)[index];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.got.size(self));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.got.size(self));
defer buffer.deinit();
try self.got.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.got.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.rela_dyn) |shndx| {
@ -3235,26 +3231,26 @@ fn writeSyntheticSections(self: *Elf) !void {
if (self.section_indexes.plt) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.plt.size(self));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.plt.size(self));
defer buffer.deinit();
try self.plt.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.plt.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.got_plt) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.got_plt.size(self));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.got_plt.size(self));
defer buffer.deinit();
try self.got_plt.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.got_plt.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.plt_got) |shndx| {
const shdr = slice.items(.shdr)[shndx];
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, self.plt_got.size(self));
var buffer = try std.Io.Writer.Allocating.initCapacity(gpa, self.plt_got.size(self));
defer buffer.deinit();
try self.plt_got.write(self, buffer.writer());
try self.pwriteAll(buffer.items, shdr.sh_offset);
try self.plt_got.write(self, &buffer.writer);
try self.pwriteAll(buffer.written(), shdr.sh_offset);
}
if (self.section_indexes.rela_plt) |shndx| {
@ -3757,7 +3753,7 @@ pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
const gpa = self.base.comp.gpa;
const off = @as(u32, @intCast(self.shstrtab.items.len));
try self.shstrtab.ensureUnusedCapacity(gpa, name.len + 1);
self.shstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
self.shstrtab.print(gpa, "{s}\x00", .{name}) catch unreachable;
return off;
}
@ -3770,7 +3766,7 @@ pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
const gpa = self.base.comp.gpa;
const off = @as(u32, @intCast(self.dynstrtab.items.len));
try self.dynstrtab.ensureUnusedCapacity(gpa, name.len + 1);
self.dynstrtab.writer(gpa).print("{s}\x00", .{name}) catch unreachable;
self.dynstrtab.print(gpa, "{s}\x00", .{name}) catch unreachable;
return off;
}

View File

@ -123,8 +123,7 @@ pub fn setArHdr(opts: struct {
@memcpy(&hdr.ar_fmag, elf.ARFMAG);
{
var stream = std.io.fixedBufferStream(&hdr.ar_name);
const writer = stream.writer();
var writer: std.Io.Writer = .fixed(&hdr.ar_name);
switch (opts.name) {
.symtab => writer.print("{s}", .{elf.SYM64NAME}) catch unreachable,
.strtab => writer.print("//", .{}) catch unreachable,
@ -133,8 +132,8 @@ pub fn setArHdr(opts: struct {
}
}
{
var stream = std.io.fixedBufferStream(&hdr.ar_size);
stream.writer().print("{d}", .{opts.size}) catch unreachable;
var writer: std.Io.Writer = .fixed(&hdr.ar_size);
writer.print("{d}", .{opts.size}) catch unreachable;
}
return hdr;
@ -246,7 +245,7 @@ pub const ArStrtab = struct {
pub fn insert(ar: *ArStrtab, allocator: Allocator, name: []const u8) error{OutOfMemory}!u32 {
const off = @as(u32, @intCast(ar.buffer.items.len));
try ar.buffer.writer(allocator).print("{s}/{c}", .{ name, strtab_delimiter });
try ar.buffer.print(allocator, "{s}/{c}", .{ name, strtab_delimiter });
return off;
}

View File

@ -621,7 +621,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
const cpu_arch = elf_file.getTarget().cpu.arch;
const file_ptr = self.file(elf_file).?;
var stream = std.io.fixedBufferStream(code);
const rels = self.relocs(elf_file);
var it = RelocsIterator{ .relocs = rels };
@ -661,20 +660,16 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
target.name(elf_file),
});
try stream.seekTo(r_offset);
const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };
switch (cpu_arch) {
.x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
error.RelocFailure,
error.RelaxFailure,
error.InvalidInstruction,
error.CannotEncode,
=> has_reloc_errors = true,
else => |e| return e,
},
.aarch64, .aarch64_be => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.aarch64, .aarch64_be => aarch64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
error.RelocFailure,
error.RelaxFailure,
error.UnexpectedRemainder,
@ -682,7 +677,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
=> has_reloc_errors = true,
else => |e| return e,
},
.riscv64, .riscv64be => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.riscv64, .riscv64be => riscv.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code) catch |err| switch (err) {
error.RelocFailure,
error.RelaxFailure,
=> has_reloc_errors = true,
@ -701,7 +696,8 @@ fn resolveDynAbsReloc(
rel: elf.Elf64_Rela,
action: RelocAction,
elf_file: *Elf,
writer: anytype,
code: []u8,
r_offset: usize,
) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
@ -726,7 +722,7 @@ fn resolveDynAbsReloc(
.copyrel,
.cplt,
.none,
=> try writer.writeInt(i64, S + A, .little),
=> mem.writeInt(i64, code[r_offset..][0..8], S + A, .little),
.dyn_copyrel => {
if (is_writeable or elf_file.z_nocopyreloc) {
@ -737,9 +733,9 @@ fn resolveDynAbsReloc(
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
applyDynamicReloc(A, code, r_offset);
} else {
try writer.writeInt(i64, S + A, .little);
mem.writeInt(i64, code[r_offset..][0..8], S + A, .little);
}
},
@ -752,9 +748,9 @@ fn resolveDynAbsReloc(
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
applyDynamicReloc(A, code, r_offset);
} else {
try writer.writeInt(i64, S + A, .little);
mem.writeInt(i64, code[r_offset..][0..8], S + A, .little);
}
},
@ -766,7 +762,7 @@ fn resolveDynAbsReloc(
.addend = A,
.target = target,
});
try applyDynamicReloc(A, elf_file, writer);
applyDynamicReloc(A, code, r_offset);
},
.baserel => {
@ -776,7 +772,7 @@ fn resolveDynAbsReloc(
.addend = S + A,
.target = target,
});
try applyDynamicReloc(S + A, elf_file, writer);
applyDynamicReloc(S + A, code, r_offset);
},
.ifunc => {
@ -787,16 +783,13 @@ fn resolveDynAbsReloc(
.addend = S_ + A,
.target = target,
});
try applyDynamicReloc(S_ + A, elf_file, writer);
applyDynamicReloc(S_ + A, code, r_offset);
},
}
}
fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void {
_ = elf_file;
// if (elf_file.options.apply_dynamic_relocs) {
try writer.writeInt(i64, value, .little);
// }
fn applyDynamicReloc(value: i64, code: []u8, r_offset: usize) void {
mem.writeInt(i64, code[r_offset..][0..8], value, .little);
}
pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void {
@ -804,7 +797,6 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
const cpu_arch = elf_file.getTarget().cpu.arch;
const file_ptr = self.file(elf_file).?;
var stream = std.io.fixedBufferStream(code);
const rels = self.relocs(elf_file);
var has_reloc_errors = false;
@ -863,18 +855,16 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
target.name(elf_file),
});
try stream.seekTo(r_offset);
switch (cpu_arch) {
.x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
},
.aarch64, .aarch64_be => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.aarch64, .aarch64_be => aarch64.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
},
.riscv64, .riscv64be => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
.riscv64, .riscv64be => riscv.resolveRelocNonAlloc(self, elf_file, rel, target, args, code[r_offset..]) catch |err| switch (err) {
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
},
@ -915,7 +905,7 @@ const Format = struct {
atom: Atom,
elf_file: *Elf,
fn default(f: Format, w: *std.io.Writer) std.io.Writer.Error!void {
fn default(f: Format, w: *Writer) Writer.Error!void {
const atom = f.atom;
const elf_file = f.elf_file;
try w.print("atom({d}) : {s} : @{x} : shdr({d}) : align({x}) : size({x}) : prev({f}) : next({f})", .{
@ -1068,16 +1058,13 @@ const x86_64 = struct {
args: ResolveArgs,
it: *RelocsIterator,
code: []u8,
stream: anytype,
) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
) !void {
dev.check(.x86_64_backend);
const t = &elf_file.base.comp.root_mod.resolved_target.result;
const diags = &elf_file.base.comp.link_diags;
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const cwriter = stream.writer();
const P, const A, const S, const GOT, const G, const TP, const DTP = args;
switch (r_type) {
@ -1089,58 +1076,60 @@ const x86_64 = struct {
rel,
dynAbsRelocAction(target, elf_file),
elf_file,
cwriter,
code,
r_offset,
);
},
.PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
.PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
.PLT32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little),
.PC32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little),
.GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
.GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
.GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
.GOTPCREL => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little),
.GOTPC32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(GOT + A - P)), .little),
.GOTPC64 => mem.writeInt(i64, code[r_offset..][0..8], GOT + A - P, .little),
.GOTPCRELX => {
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
x86_64.relaxGotpcrelx(code[r_offset - 2 ..], t) catch break :blk;
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little);
return;
}
try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little);
},
.REX_GOTPCRELX => {
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..], t) catch break :blk;
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S + A - P)), .little);
return;
}
try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + GOT + A - P)), .little);
},
.@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
.@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
.@"32" => mem.writeInt(u32, code[r_offset..][0..4], @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
.@"32S" => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little),
.TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
.TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
.TPOFF32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A - TP)), .little),
.TPOFF64 => mem.writeInt(i64, code[r_offset..][0..8], S + A - TP, .little),
.DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
.DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
.DTPOFF32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A - DTP)), .little),
.DTPOFF64 => mem.writeInt(i64, code[r_offset..][0..8], S + A - DTP, .little),
.TLSGD => {
if (target.flags.has_tlsgd) {
const S_ = target.tlsGdAddress(elf_file);
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
} else if (target.flags.has_gottp) {
const S_ = target.gotTpAddress(elf_file);
try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);
try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, code, r_offset);
} else {
try x86_64.relaxTlsGdToLe(
atom,
&.{ rel, it.next().? },
@as(i32, @intCast(S - TP)),
elf_file,
stream,
code,
r_offset,
);
}
},
@ -1149,14 +1138,15 @@ const x86_64 = struct {
if (elf_file.got.tlsld_index) |entry_index| {
const tlsld_entry = elf_file.got.entries.items[entry_index];
const S_ = tlsld_entry.address(elf_file);
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
} else {
try x86_64.relaxTlsLdToLe(
atom,
&.{ rel, it.next().? },
@as(i32, @intCast(TP - elf_file.tlsAddress())),
elf_file,
stream,
code,
r_offset,
);
}
},
@ -1164,7 +1154,7 @@ const x86_64 = struct {
.GOTPC32_TLSDESC => {
if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file);
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
} else {
x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..], t) catch {
var err = try diags.addErrorWithNotes(1);
@ -1176,26 +1166,26 @@ const x86_64 = struct {
});
return error.RelaxFailure;
};
try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S - TP)), .little);
}
},
.TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
// call -> nop
try cwriter.writeAll(&.{ 0x66, 0x90 });
code[r_offset..][0..2].* = .{ 0x66, 0x90 };
},
.GOTTPOFF => {
if (target.flags.has_gottp) {
const S_ = target.gotTpAddress(elf_file);
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S_ + A - P)), .little);
} else {
x86_64.relaxGotTpOff(code[r_offset - 3 ..], t);
try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(S - TP)), .little);
}
},
.GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + A)), .little),
.GOT32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @intCast(G + A)), .little),
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
@ -1207,45 +1197,42 @@ const x86_64 = struct {
rel: elf.Elf64_Rela,
target: *const Symbol,
args: ResolveArgs,
it: *RelocsIterator,
code: []u8,
stream: anytype,
) !void {
dev.check(.x86_64_backend);
_ = code;
_ = it;
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
const cwriter = stream.writer();
_, const A, const S, const GOT, _, _, const DTP = args;
var writer: Writer = .fixed(code);
switch (r_type) {
.NONE => unreachable,
.@"8" => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),
.@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
.@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
.@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
.@"8" => try writer.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),
.@"16" => try writer.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
.@"32" => try writer.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
.@"32S" => try writer.writeInt(i32, @as(i32, @intCast(S + A)), .little),
.@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
try cwriter.writeInt(u64, value, .little)
try writer.writeInt(u64, value, .little)
else
try cwriter.writeInt(i64, S + A, .little),
try writer.writeInt(i64, S + A, .little),
.DTPOFF32 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
try cwriter.writeInt(u64, value, .little)
try writer.writeInt(u64, value, .little)
else
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
try writer.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
.DTPOFF64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
try cwriter.writeInt(u64, value, .little)
try writer.writeInt(u64, value, .little)
else
try cwriter.writeInt(i64, S + A - DTP, .little),
.GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),
.GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
try writer.writeInt(i64, S + A - DTP, .little),
.GOTOFF64 => try writer.writeInt(i64, S + A - GOT, .little),
.GOTPC64 => try writer.writeInt(i64, GOT + A, .little),
.SIZE32 => {
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
try cwriter.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);
try writer.writeInt(u32, @bitCast(@as(i32, @intCast(size + A))), .little);
},
.SIZE64 => {
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
try cwriter.writeInt(i64, @intCast(size + A), .little);
try writer.writeInt(i64, @intCast(size + A), .little);
},
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
@ -1288,12 +1275,12 @@ const x86_64 = struct {
rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
code: []u8,
r_offset: usize,
) !void {
dev.check(.x86_64_backend);
assert(rels.len == 2);
const diags = &elf_file.base.comp.link_diags;
const writer = stream.writer();
const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
switch (rel) {
.PC32,
@ -1304,8 +1291,7 @@ const x86_64 = struct {
0x48, 0x03, 0x05, 0, 0, 0, 0, // add foo@gottpoff(%rip), %rax
};
std.mem.writeInt(i32, insts[12..][0..4], value - 12, .little);
try stream.seekBy(-4);
try writer.writeAll(&insts);
@memcpy(code[r_offset - 4 ..][0..insts.len], &insts);
},
else => {
@ -1329,12 +1315,12 @@ const x86_64 = struct {
rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
code: []u8,
r_offset: usize,
) !void {
dev.check(.x86_64_backend);
assert(rels.len == 2);
const diags = &elf_file.base.comp.link_diags;
const writer = stream.writer();
const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
switch (rel) {
.PC32,
@ -1346,8 +1332,7 @@ const x86_64 = struct {
0x48, 0x2d, 0, 0, 0, 0, // sub $tls_size, %rax
};
std.mem.writeInt(i32, insts[8..][0..4], value, .little);
try stream.seekBy(-3);
try writer.writeAll(&insts);
@memcpy(code[r_offset - 3 ..][0..insts.len], &insts);
},
.GOTPCREL,
@ -1360,8 +1345,7 @@ const x86_64 = struct {
0x90, // nop
};
std.mem.writeInt(i32, insts[8..][0..4], value, .little);
try stream.seekBy(-3);
try writer.writeAll(&insts);
@memcpy(code[r_offset - 3 ..][0..insts.len], &insts);
},
else => {
@ -1390,7 +1374,7 @@ const x86_64 = struct {
// TODO: hack to force imm32s in the assembler
.{ .imm = .s(-129) },
}, t) catch return false;
var trash: std.io.Writer.Discarding = .init(&.{});
var trash: Writer.Discarding = .init(&.{});
inst.encode(&trash.writer, .{}) catch return false;
return true;
},
@ -1437,12 +1421,12 @@ const x86_64 = struct {
rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
code: []u8,
r_offset: usize,
) !void {
dev.check(.x86_64_backend);
assert(rels.len == 2);
const diags = &elf_file.base.comp.link_diags;
const writer = stream.writer();
const rel: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
switch (rel) {
.PC32,
@ -1455,8 +1439,7 @@ const x86_64 = struct {
0x48, 0x81, 0xc0, 0, 0, 0, 0, // add $tp_offset, %rax
};
std.mem.writeInt(i32, insts[12..][0..4], value, .little);
try stream.seekBy(-4);
try writer.writeAll(&insts);
@memcpy(code[r_offset - 4 ..][0..insts.len], &insts);
relocs_log.debug(" relaxing {f} and {f}", .{
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
@ -1486,8 +1469,8 @@ const x86_64 = struct {
}
fn encode(insts: []const Instruction, code: []u8) !void {
var stream: std.io.Writer = .fixed(code);
for (insts) |inst| try inst.encode(&stream, .{});
var writer: Writer = .fixed(code);
for (insts) |inst| try inst.encode(&writer, .{});
}
const bits = @import("../../arch/x86_64/bits.zig");
@ -1592,14 +1575,12 @@ const aarch64 = struct {
args: ResolveArgs,
it: *RelocsIterator,
code_buffer: []u8,
stream: anytype,
) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
_ = it;
const diags = &elf_file.base.comp.link_diags;
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const cwriter = stream.writer();
const code = code_buffer[r_offset..][0..4];
const file_ptr = atom.file(elf_file).?;
@ -1614,7 +1595,8 @@ const aarch64 = struct {
rel,
dynAbsRelocAction(target, elf_file),
elf_file,
cwriter,
code_buffer,
r_offset,
);
},
@ -1782,25 +1764,20 @@ const aarch64 = struct {
rel: elf.Elf64_Rela,
target: *const Symbol,
args: ResolveArgs,
it: *RelocsIterator,
code: []u8,
stream: anytype,
) !void {
_ = it;
_ = code;
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
const cwriter = stream.writer();
_, const A, const S, _, _, _, _ = args;
var writer: Writer = .fixed(code);
switch (r_type) {
.NONE => unreachable,
.ABS32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
.ABS32 => try writer.writeInt(i32, @as(i32, @intCast(S + A)), .little),
.ABS64 => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
try cwriter.writeInt(u64, value, .little)
try writer.writeInt(u64, value, .little)
else
try cwriter.writeInt(i64, S + A, .little),
try writer.writeInt(i64, S + A, .little),
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
}
@ -1861,12 +1838,10 @@ const riscv = struct {
args: ResolveArgs,
it: *RelocsIterator,
code: []u8,
stream: anytype,
) !void {
const diags = &elf_file.base.comp.link_diags;
const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const cwriter = stream.writer();
const P, const A, const S, const GOT, const G, const TP, const DTP = args;
_ = TP;
@ -1875,7 +1850,7 @@ const riscv = struct {
switch (r_type) {
.NONE => unreachable,
.@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
.@"32" => mem.writeInt(u32, code[r_offset..][0..4], @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
.@"64" => {
try atom.resolveDynAbsReloc(
@ -1883,7 +1858,8 @@ const riscv = struct {
rel,
dynAbsRelocAction(target, elf_file),
elf_file,
cwriter,
code,
r_offset,
);
},
@ -1997,15 +1973,9 @@ const riscv = struct {
rel: elf.Elf64_Rela,
target: *const Symbol,
args: ResolveArgs,
it: *RelocsIterator,
code: []u8,
stream: anytype,
) !void {
_ = it;
const r_type: elf.R_RISCV = @enumFromInt(rel.r_type());
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const cwriter = stream.writer();
_, const A, const S, const GOT, _, _, const DTP = args;
_ = GOT;
@ -2014,30 +1984,29 @@ const riscv = struct {
switch (r_type) {
.NONE => unreachable,
.@"32" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
.@"32" => mem.writeInt(i32, code[0..4], @intCast(S + A), .little),
.@"64" => if (atom.debugTombstoneValue(target.*, elf_file)) |value|
try cwriter.writeInt(u64, value, .little)
mem.writeInt(u64, code[0..8], value, .little)
else
try cwriter.writeInt(i64, S + A, .little),
mem.writeInt(i64, code[0..8], S + A, .little),
.ADD8 => riscv_util.writeAddend(i8, .add, code[0..1], S + A),
.SUB8 => riscv_util.writeAddend(i8, .sub, code[0..1], S + A),
.ADD16 => riscv_util.writeAddend(i16, .add, code[0..2], S + A),
.SUB16 => riscv_util.writeAddend(i16, .sub, code[0..2], S + A),
.ADD32 => riscv_util.writeAddend(i32, .add, code[0..4], S + A),
.SUB32 => riscv_util.writeAddend(i32, .sub, code[0..4], S + A),
.ADD64 => riscv_util.writeAddend(i64, .add, code[0..8], S + A),
.SUB64 => riscv_util.writeAddend(i64, .sub, code[0..8], S + A),
.ADD8 => riscv_util.writeAddend(i8, .add, code[r_offset..][0..1], S + A),
.SUB8 => riscv_util.writeAddend(i8, .sub, code[r_offset..][0..1], S + A),
.ADD16 => riscv_util.writeAddend(i16, .add, code[r_offset..][0..2], S + A),
.SUB16 => riscv_util.writeAddend(i16, .sub, code[r_offset..][0..2], S + A),
.ADD32 => riscv_util.writeAddend(i32, .add, code[r_offset..][0..4], S + A),
.SUB32 => riscv_util.writeAddend(i32, .sub, code[r_offset..][0..4], S + A),
.ADD64 => riscv_util.writeAddend(i64, .add, code[r_offset..][0..8], S + A),
.SUB64 => riscv_util.writeAddend(i64, .sub, code[r_offset..][0..8], S + A),
.SET8 => mem.writeInt(i8, code[0..1], @as(i8, @truncate(S + A)), .little),
.SET16 => mem.writeInt(i16, code[0..2], @as(i16, @truncate(S + A)), .little),
.SET32 => mem.writeInt(i32, code[0..4], @as(i32, @truncate(S + A)), .little),
.SET8 => mem.writeInt(i8, code[r_offset..][0..1], @as(i8, @truncate(S + A)), .little),
.SET16 => mem.writeInt(i16, code[r_offset..][0..2], @as(i16, @truncate(S + A)), .little),
.SET32 => mem.writeInt(i32, code[r_offset..][0..4], @as(i32, @truncate(S + A)), .little),
.SET6 => riscv_util.writeSetSub6(.set, code[0..1], S + A),
.SUB6 => riscv_util.writeSetSub6(.sub, code[0..1], S + A),
.SET6 => riscv_util.writeSetSub6(.set, code[r_offset..][0..1], S + A),
.SUB6 => riscv_util.writeSetSub6(.sub, code[r_offset..][0..1], S + A),
.SET_ULEB128 => try riscv_util.writeSetSubUleb(.set, stream, S + A),
.SUB_ULEB128 => try riscv_util.writeSetSubUleb(.sub, stream, S - A),
.SET_ULEB128 => riscv_util.writeSetUleb(code, S + A),
.SUB_ULEB128 => riscv_util.writeSubUleb(code, S - A),
else => try atom.reportUnhandledRelocError(rel, elf_file),
}
@ -2108,14 +2077,16 @@ pub const Extra = struct {
const std = @import("std");
const assert = std.debug.assert;
const elf = std.elf;
const eh_frame = @import("eh_frame.zig");
const log = std.log.scoped(.link);
const math = std.math;
const mem = std.mem;
const relocs_log = std.log.scoped(.link_relocs);
const Allocator = mem.Allocator;
const Writer = std.Io.Writer;
const eh_frame = @import("eh_frame.zig");
const relocation = @import("relocation.zig");
const Allocator = mem.Allocator;
const Atom = @This();
const Elf = @import("../Elf.zig");
const Fde = eh_frame.Fde;

View File

@ -89,7 +89,7 @@ pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
list.dirty = false;
}
pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytype, elf_file: *Elf) !void {
pub fn write(list: AtomList, buffer: *std.Io.Writer.Allocating, undefs: anytype, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
const osec = elf_file.sections.items(.shdr)[list.output_section_index];
assert(osec.sh_type != elf.SHT_NOBITS);
@ -98,8 +98,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
const list_size = math.cast(usize, list.size) orelse return error.Overflow;
try buffer.ensureUnusedCapacity(list_size);
buffer.appendNTimesAssumeCapacity(0, list_size);
try buffer.writer.splatByteAll(0, list_size);
for (list.atoms.keys()) |ref| {
const atom_ptr = elf_file.atom(ref).?;
@ -113,7 +112,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
const object = atom_ptr.file(elf_file).?.object;
const code = try object.codeDecompressAlloc(elf_file, ref.index);
defer gpa.free(code);
const out_code = buffer.items[off..][0..size];
const out_code = buffer.written()[off..][0..size];
@memcpy(out_code, code);
if (osec.sh_flags & elf.SHF_ALLOC == 0)
@ -122,7 +121,7 @@ pub fn write(list: AtomList, buffer: *std.array_list.Managed(u8), undefs: anytyp
try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
}
try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
try elf_file.base.file.?.pwriteAll(buffer.written(), list.offset(elf_file));
buffer.clearRetainingCapacity();
}

View File

@ -952,7 +952,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
const is_tls = sym.type(elf_file) == elf.STT_TLS;
const name = if (is_tls) ".tls_common" else ".common";
const name_offset = @as(u32, @intCast(self.strtab.items.len));
try self.strtab.writer(gpa).print("{s}\x00", .{name});
try self.strtab.print(gpa, "{s}\x00", .{name});
var sh_flags: u32 = elf.SHF_ALLOC | elf.SHF_WRITE;
if (is_tls) sh_flags |= elf.SHF_TLS;

View File

@ -162,22 +162,6 @@ fn prune(elf_file: *Elf) void {
}
}
pub fn dumpPrunedAtoms(elf_file: *Elf) !void {
const stderr = std.fs.File.stderr().deprecatedWriter();
for (elf_file.objects.items) |index| {
const file = elf_file.file(index).?;
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (!atom.alive)
// TODO should we simply print to stderr?
try stderr.print("link: removing unused section '{s}' in file '{f}'\n", .{
atom.name(elf_file),
atom.file(elf_file).?.fmtPath(),
});
}
}
}
const Level = struct {
value: usize = 0,

View File

@ -100,32 +100,33 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
}
var buffer = std.array_list.Managed(u8).init(gpa);
defer buffer.deinit();
try buffer.ensureTotalCapacityPrecise(total_size);
const buffer = try gpa.alloc(u8, total_size);
defer gpa.free(buffer);
var writer: std.Io.Writer = .fixed(buffer);
// Write magic
try buffer.writer().writeAll(elf.ARMAG);
try writer.writeAll(elf.ARMAG);
// Write symtab
try ar_symtab.write(.p64, elf_file, buffer.writer());
try ar_symtab.write(.p64, elf_file, &writer);
// Write strtab
if (ar_strtab.size() > 0) {
if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
try ar_strtab.write(buffer.writer());
if (!mem.isAligned(writer.end, 2)) try writer.writeByte(0);
try ar_strtab.write(&writer);
}
// Write object files
for (files.items) |index| {
if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
try elf_file.file(index).?.writeAr(elf_file, buffer.writer());
if (!mem.isAligned(writer.end, 2)) try writer.writeByte(0);
try elf_file.file(index).?.writeAr(elf_file, &writer);
}
assert(buffer.items.len == total_size);
assert(writer.buffered().len == total_size);
try elf_file.base.file.?.setEndPos(total_size);
try elf_file.base.file.?.pwriteAll(buffer.items, 0);
try elf_file.base.file.?.pwriteAll(writer.buffered(), 0);
if (diags.hasErrors()) return error.LinkFailure;
}
@ -407,15 +408,16 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
};
const shdr = slice.items(.shdr)[shndx];
const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
defer buffer.deinit();
try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer());
const buffer = try gpa.alloc(u8, @intCast(sh_size - existing_size));
defer gpa.free(buffer);
var writer: std.Io.Writer = .fixed(buffer);
try eh_frame.writeEhFrameRelocatable(elf_file, &writer);
log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
shdr.sh_offset + existing_size,
shdr.sh_offset + sh_size,
});
assert(buffer.items.len == sh_size - existing_size);
try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
assert(writer.buffered().len == sh_size - existing_size);
try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset + existing_size);
}
if (elf_file.section_indexes.eh_frame_rela) |shndx| {
const shdr = slice.items(.shdr)[shndx];
@ -446,15 +448,16 @@ fn writeGroups(elf_file: *Elf) !void {
for (elf_file.group_sections.items) |cgs| {
const shdr = elf_file.sections.items(.shdr)[cgs.shndx];
const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
var buffer = try std.array_list.Managed(u8).initCapacity(gpa, sh_size);
defer buffer.deinit();
try cgs.write(elf_file, buffer.writer());
assert(buffer.items.len == sh_size);
const buffer = try gpa.alloc(u8, sh_size);
defer gpa.free(buffer);
var writer: std.Io.Writer = .fixed(buffer);
try cgs.write(elf_file, &writer);
assert(writer.buffered().len == sh_size);
log.debug("writing group from 0x{x} to 0x{x}", .{
shdr.sh_offset,
shdr.sh_offset + shdr.sh_size,
});
try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
try elf_file.base.file.?.pwriteAll(writer.buffered(), shdr.sh_offset);
}
}

View File

@ -94,134 +94,134 @@ pub const DynamicSection = struct {
return nentries * @sizeOf(elf.Elf64_Dyn);
}
pub fn write(dt: DynamicSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(dt: DynamicSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const shdrs = elf_file.sections.items(.shdr);
// NEEDED
for (dt.needed.items) |off| {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NEEDED, .d_val = off });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_NEEDED, .d_val = off }), .little);
}
if (dt.soname) |off| {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SONAME, .d_val = off });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SONAME, .d_val = off }), .little);
}
// RUNPATH
// TODO add option in Options to revert to old RPATH tag
if (dt.rpath > 0) {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RUNPATH, .d_val = dt.rpath }), .little);
}
// INIT
if (elf_file.sectionByName(".init")) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT, .d_val = addr }), .little);
}
// FINI
if (elf_file.sectionByName(".fini")) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI, .d_val = addr }), .little);
}
// INIT_ARRAY
if (elf_file.sectionByName(".init_array")) |shndx| {
const shdr = shdrs[shndx];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT_ARRAY, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_INIT_ARRAYSZ, .d_val = shdr.sh_size }), .little);
}
// FINI_ARRAY
if (elf_file.sectionByName(".fini_array")) |shndx| {
const shdr = shdrs[shndx];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI_ARRAY, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FINI_ARRAYSZ, .d_val = shdr.sh_size }), .little);
}
// RELA
if (elf_file.section_indexes.rela_dyn) |shndx| {
const shdr = shdrs[shndx];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELA, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELASZ, .d_val = shdr.sh_size }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_RELAENT, .d_val = shdr.sh_entsize }), .little);
}
// JMPREL
if (elf_file.section_indexes.rela_plt) |shndx| {
const shdr = shdrs[shndx];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_JMPREL, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTRELSZ, .d_val = shdr.sh_size }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTREL, .d_val = elf.DT_RELA }), .little);
}
// PLTGOT
if (elf_file.section_indexes.got_plt) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_PLTGOT, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_PLTGOT, .d_val = addr }), .little);
}
{
assert(elf_file.section_indexes.hash != null);
const addr = shdrs[elf_file.section_indexes.hash.?].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_HASH, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_HASH, .d_val = addr }), .little);
}
if (elf_file.section_indexes.gnu_hash) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_GNU_HASH, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_GNU_HASH, .d_val = addr }), .little);
}
// TEXTREL
if (elf_file.has_text_reloc) {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_TEXTREL, .d_val = 0 });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_TEXTREL, .d_val = 0 }), .little);
}
// SYMTAB + SYMENT
{
assert(elf_file.section_indexes.dynsymtab != null);
const shdr = shdrs[elf_file.section_indexes.dynsymtab.?];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SYMTAB, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_SYMENT, .d_val = shdr.sh_entsize }), .little);
}
// STRTAB + STRSZ
{
assert(elf_file.section_indexes.dynstrtab != null);
const shdr = shdrs[elf_file.section_indexes.dynstrtab.?];
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr });
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_STRTAB, .d_val = shdr.sh_addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_STRSZ, .d_val = shdr.sh_size }), .little);
}
// VERSYM
if (elf_file.section_indexes.versym) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERSYM, .d_val = addr });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_VERSYM, .d_val = addr }), .little);
}
// VERNEED + VERNEEDNUM
if (elf_file.section_indexes.verneed) |shndx| {
const addr = shdrs[shndx].sh_addr;
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_VERNEED, .d_val = addr });
try writer.writeStruct(elf.Elf64_Dyn{
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_VERNEED, .d_val = addr }), .little);
try writer.writeStruct(@as(elf.Elf64_Dyn, .{
.d_tag = elf.DT_VERNEEDNUM,
.d_val = elf_file.verneed.verneed.items.len,
});
}), .little);
}
// FLAGS
if (dt.getFlags(elf_file)) |flags| {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS, .d_val = flags });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FLAGS, .d_val = flags }), .little);
}
// FLAGS_1
if (dt.getFlags1(elf_file)) |flags_1| {
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_FLAGS_1, .d_val = flags_1 }), .little);
}
// DEBUG
if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_DEBUG, .d_val = 0 });
if (!elf_file.isEffectivelyDynLib()) try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_DEBUG, .d_val = 0 }), .little);
// NULL
try writer.writeStruct(elf.Elf64_Dyn{ .d_tag = elf.DT_NULL, .d_val = 0 });
try writer.writeStruct(@as(elf.Elf64_Dyn, .{ .d_tag = elf.DT_NULL, .d_val = 0 }), .little);
}
};
@ -360,7 +360,7 @@ pub const GotSection = struct {
return s;
}
pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(got: GotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const comp = elf_file.base.comp;
const is_dyn_lib = elf_file.isEffectivelyDynLib();
const apply_relocs = true; // TODO add user option for this
@ -666,7 +666,7 @@ pub const PltSection = struct {
};
}
pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const cpu_arch = elf_file.getTarget().cpu.arch;
switch (cpu_arch) {
.x86_64 => try x86_64.write(plt, elf_file, writer),
@ -763,7 +763,7 @@ pub const PltSection = struct {
}
const x86_64 = struct {
fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {
fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const shdrs = elf_file.sections.items(.shdr);
const plt_addr = shdrs[elf_file.section_indexes.plt.?].sh_addr;
const got_plt_addr = shdrs[elf_file.section_indexes.got_plt.?].sh_addr;
@ -778,7 +778,7 @@ pub const PltSection = struct {
disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4;
mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little);
try writer.writeAll(&preamble);
try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len);
try writer.splatByteAll(0xcc, preambleSize(.x86_64) - preamble.len);
for (plt.symbols.items, 0..) |ref, i| {
const sym = elf_file.symbol(ref).?;
@ -798,7 +798,7 @@ pub const PltSection = struct {
};
const aarch64 = struct {
fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void {
fn write(plt: PltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
{
const shdrs = elf_file.sections.items(.shdr);
const plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.plt.?].sh_addr);
@ -853,7 +853,7 @@ pub const GotPltSection = struct {
return preamble_size + elf_file.plt.symbols.items.len * 8;
}
pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(got_plt: GotPltSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
_ = got_plt;
{
// [0]: _DYNAMIC
@ -904,7 +904,7 @@ pub const PltGotSection = struct {
};
}
pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const cpu_arch = elf_file.getTarget().cpu.arch;
switch (cpu_arch) {
.x86_64 => try x86_64.write(plt_got, elf_file, writer),
@ -940,7 +940,7 @@ pub const PltGotSection = struct {
}
const x86_64 = struct {
pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
for (plt_got.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotAddress(elf_file);
@ -958,7 +958,7 @@ pub const PltGotSection = struct {
};
const aarch64 = struct {
fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
fn write(plt_got: PltGotSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
for (plt_got.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotAddress(elf_file);
@ -1133,14 +1133,14 @@ pub const DynsymSection = struct {
return @as(u32, @intCast(dynsym.entries.items.len + 1));
}
pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void {
try writer.writeStruct(Elf.null_sym);
pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
try writer.writeStruct(Elf.null_sym, .little);
for (dynsym.entries.items) |entry| {
const sym = elf_file.symbol(entry.ref).?;
var out_sym: elf.Elf64_Sym = Elf.null_sym;
sym.setOutputSym(elf_file, &out_sym);
out_sym.st_name = entry.off;
try writer.writeStruct(out_sym);
try writer.writeStruct(out_sym, .little);
}
}
};
@ -1175,10 +1175,12 @@ pub const HashSection = struct {
}
try hs.buffer.ensureTotalCapacityPrecise(gpa, (2 + nsyms * 2) * 4);
hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
hs.buffer.writer(gpa).writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(buckets)) catch unreachable;
hs.buffer.writer(gpa).writeAll(mem.sliceAsBytes(chains)) catch unreachable;
var w: std.Io.Writer = .fixed(hs.buffer.unusedCapacitySlice());
w.writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
w.writeInt(u32, @as(u32, @intCast(nsyms)), .little) catch unreachable;
w.writeAll(@ptrCast(buckets)) catch unreachable;
w.writeAll(@ptrCast(chains)) catch unreachable;
hs.buffer.items.len += w.end;
}
pub inline fn size(hs: HashSection) usize {
@ -1439,7 +1441,7 @@ pub const VerneedSection = struct {
return vern.verneed.items.len * @sizeOf(elf.Elf64_Verneed) + vern.vernaux.items.len * @sizeOf(elf.Vernaux);
}
pub fn write(vern: VerneedSection, writer: anytype) !void {
pub fn write(vern: VerneedSection, writer: *std.Io.Writer) !void {
try writer.writeAll(mem.sliceAsBytes(vern.verneed.items));
try writer.writeAll(mem.sliceAsBytes(vern.vernaux.items));
}
@ -1467,7 +1469,7 @@ pub const GroupSection = struct {
return (members.len + 1) * @sizeOf(u32);
}
pub fn write(cgs: GroupSection, elf_file: *Elf, writer: anytype) !void {
pub fn write(cgs: GroupSection, elf_file: *Elf, writer: *std.Io.Writer) !void {
const cg = cgs.group(elf_file);
const object = cg.file(elf_file).object;
const members = cg.members(elf_file);
@ -1495,7 +1497,7 @@ pub const GroupSection = struct {
}
};
fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
fn writeInt(value: anytype, elf_file: *Elf, writer: *std.Io.Writer) !void {
const entry_size = elf_file.archPtrWidthBytes();
const target = elf_file.getTarget();
const endian = target.cpu.arch.endian();

View File

@ -9,29 +9,28 @@ pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytyp
mem.writeInt(u8, code, value, .little);
}
pub fn writeSetSubUleb(comptime op: enum { set, sub }, stream: *std.io.FixedBufferStream([]u8), addend: i64) !void {
switch (op) {
.set => try overwriteUleb(stream, @intCast(addend)),
.sub => {
const position = try stream.getPos();
const value: u64 = try std.leb.readUleb128(u64, stream.reader());
try stream.seekTo(position);
try overwriteUleb(stream, value -% @as(u64, @intCast(addend)));
},
}
pub fn writeSubUleb(code: []u8, addend: i64) void {
var reader: std.Io.Reader = .fixed(code);
const value = reader.takeLeb128(u64) catch unreachable;
overwriteUleb(code, value -% @as(u64, @intCast(addend)));
}
fn overwriteUleb(stream: *std.io.FixedBufferStream([]u8), addend: u64) !void {
pub fn writeSetUleb(code: []u8, addend: i64) void {
overwriteUleb(code, @intCast(addend));
}
fn overwriteUleb(code: []u8, addend: u64) void {
var value: u64 = addend;
const writer = stream.writer();
var i: usize = 0;
while (true) {
const byte = stream.buffer[stream.pos];
const byte = code[i];
if (byte & 0x80 == 0) break;
try writer.writeByte(0x80 | @as(u8, @truncate(value & 0x7f)));
code[i] = 0x80 | @as(u8, @truncate(value & 0x7f));
i += 1;
value >>= 7;
}
stream.buffer[stream.pos] = @truncate(value & 0x7f);
code[i] = @truncate(value & 0x7f);
}
pub fn writeAddend(