mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
205 lines
7.3 KiB
Zig
205 lines
7.3 KiB
Zig
value: i64 = 0,
|
|
size: u64 = 0,
|
|
alignment: Atom.Alignment = .@"1",
|
|
output_section_index: u32 = 0,
|
|
// atoms: std.ArrayList(Elf.Ref) = .empty,
|
|
atoms: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty,
|
|
|
|
dirty: bool = true,
|
|
|
|
pub fn deinit(list: *AtomList, allocator: Allocator) void {
|
|
list.atoms.deinit(allocator);
|
|
}
|
|
|
|
pub fn address(list: AtomList, elf_file: *Elf) i64 {
|
|
const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
|
|
return @as(i64, @intCast(shdr.sh_addr)) + list.value;
|
|
}
|
|
|
|
pub fn offset(list: AtomList, elf_file: *Elf) u64 {
|
|
const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
|
|
return shdr.sh_offset + @as(u64, @intCast(list.value));
|
|
}
|
|
|
|
pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
|
|
assert(list.dirty);
|
|
for (list.atoms.keys()) |ref| {
|
|
const atom_ptr = elf_file.atom(ref).?;
|
|
assert(atom_ptr.alive);
|
|
const off = atom_ptr.alignment.forward(list.size);
|
|
const padding = off - list.size;
|
|
atom_ptr.value = @intCast(off);
|
|
list.size += padding + atom_ptr.size;
|
|
list.alignment = list.alignment.max(atom_ptr.alignment);
|
|
}
|
|
}
|
|
|
|
pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
|
|
assert(list.dirty);
|
|
|
|
const alloc_res = try elf_file.allocateChunk(.{
|
|
.shndx = list.output_section_index,
|
|
.size = list.size,
|
|
.alignment = list.alignment,
|
|
.requires_padding = false,
|
|
});
|
|
list.value = @intCast(alloc_res.value);
|
|
|
|
log.debug("allocated atom_list({d}) at 0x{x}", .{ list.output_section_index, list.address(elf_file) });
|
|
|
|
const slice = elf_file.sections.slice();
|
|
const shdr = &slice.items(.shdr)[list.output_section_index];
|
|
const last_atom_ref = &slice.items(.last_atom)[list.output_section_index];
|
|
|
|
const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
|
|
placement_atom.nextAtom(elf_file) == null
|
|
else
|
|
true;
|
|
if (expand_section) last_atom_ref.* = list.lastAtom(elf_file).ref();
|
|
shdr.sh_addralign = @max(shdr.sh_addralign, list.alignment.toByteUnits().?);
|
|
|
|
// This currently ignores Thunks as valid chunks.
|
|
{
|
|
var idx: usize = 0;
|
|
while (idx < list.atoms.keys().len) : (idx += 1) {
|
|
const curr_atom_ptr = elf_file.atom(list.atoms.keys()[idx]).?;
|
|
if (idx > 0) {
|
|
curr_atom_ptr.prev_atom_ref = list.atoms.keys()[idx - 1];
|
|
}
|
|
if (idx + 1 < list.atoms.keys().len) {
|
|
curr_atom_ptr.next_atom_ref = list.atoms.keys()[idx + 1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (elf_file.atom(alloc_res.placement)) |placement_atom| {
|
|
list.firstAtom(elf_file).prev_atom_ref = placement_atom.ref();
|
|
list.lastAtom(elf_file).next_atom_ref = placement_atom.next_atom_ref;
|
|
placement_atom.next_atom_ref = list.firstAtom(elf_file).ref();
|
|
}
|
|
|
|
// If we had a link from Atom to parent AtomList we would not need to
|
|
// update Atom's value or osec index.
|
|
for (list.atoms.keys()) |ref| {
|
|
const atom_ptr = elf_file.atom(ref).?;
|
|
atom_ptr.output_section_index = list.output_section_index;
|
|
atom_ptr.value += list.value;
|
|
}
|
|
|
|
list.dirty = false;
|
|
}
|
|
|
|
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);
|
|
assert(!list.dirty);
|
|
|
|
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.writer.splatByteAll(0, list_size);
|
|
|
|
for (list.atoms.keys()) |ref| {
|
|
const atom_ptr = elf_file.atom(ref).?;
|
|
assert(atom_ptr.alive);
|
|
|
|
const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
|
|
const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
|
|
|
|
log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
|
|
|
|
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.written()[off..][0..size];
|
|
@memcpy(out_code, code);
|
|
|
|
if (osec.sh_flags & elf.SHF_ALLOC == 0)
|
|
try atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, undefs)
|
|
else
|
|
try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
|
|
}
|
|
|
|
try elf_file.base.file.?.pwriteAll(buffer.written(), list.offset(elf_file));
|
|
buffer.clearRetainingCapacity();
|
|
}
|
|
|
|
pub fn writeRelocatable(list: AtomList, buffer: *std.array_list.Managed(u8), 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);
|
|
|
|
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);
|
|
|
|
for (list.atoms.keys()) |ref| {
|
|
const atom_ptr = elf_file.atom(ref).?;
|
|
assert(atom_ptr.alive);
|
|
|
|
const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
|
|
const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
|
|
|
|
log.debug(" atom({f}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
|
|
|
|
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];
|
|
@memcpy(out_code, code);
|
|
}
|
|
|
|
try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
|
|
buffer.clearRetainingCapacity();
|
|
}
|
|
|
|
pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom {
|
|
assert(list.atoms.keys().len > 0);
|
|
return elf_file.atom(list.atoms.keys()[0]).?;
|
|
}
|
|
|
|
pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
|
|
assert(list.atoms.keys().len > 0);
|
|
return elf_file.atom(list.atoms.keys()[list.atoms.keys().len - 1]).?;
|
|
}
|
|
|
|
const Format = struct {
|
|
atom_list: AtomList,
|
|
elf_file: *Elf,
|
|
|
|
fn default(f: Format, writer: *std.Io.Writer) std.Io.Writer.Error!void {
|
|
const list = f.atom_list;
|
|
try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{
|
|
list.address(f.elf_file),
|
|
list.output_section_index,
|
|
list.alignment.toByteUnits() orelse 0,
|
|
list.size,
|
|
});
|
|
try writer.writeAll(" : atoms{ ");
|
|
for (list.atoms.keys(), 0..) |ref, i| {
|
|
try writer.print("{f}", .{ref});
|
|
if (i < list.atoms.keys().len - 1) try writer.writeAll(", ");
|
|
}
|
|
try writer.writeAll(" }");
|
|
}
|
|
};
|
|
|
|
pub fn fmt(atom_list: AtomList, elf_file: *Elf) std.fmt.Alt(Format, Format.default) {
|
|
return .{ .data = .{ .atom_list = atom_list, .elf_file = elf_file } };
|
|
}
|
|
|
|
const assert = std.debug.assert;
|
|
const elf = std.elf;
|
|
const log = std.log.scoped(.link);
|
|
const math = std.math;
|
|
const std = @import("std");
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
const Atom = @import("Atom.zig");
|
|
const AtomList = @This();
|
|
const Elf = @import("../Elf.zig");
|
|
const Object = @import("Object.zig");
|