mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-03-08 01:24:49 +01:00
link.MachO: support sdata4 pointer encoding (#30846)
Fixes https://codeberg.org/ziglang/zig/issues/30669 Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30846 Reviewed-by: Andrew Kelley <andrew@ziglang.org> Co-authored-by: Vladislav Shabanov <vshabanov88@gmail.com> Co-committed-by: Vladislav Shabanov <vshabanov88@gmail.com>
This commit is contained in:
parent
eaa3a4299b
commit
63f345a75a
2 changed files with 129 additions and 29 deletions
|
|
@ -3,6 +3,7 @@ pub const Cie = struct {
|
|||
offset: u32,
|
||||
out_offset: u32 = 0,
|
||||
size: u32,
|
||||
address_ptr_size: enum { p32, p64 } = .p64,
|
||||
lsda_size: ?enum { p32, p64 } = null,
|
||||
personality: ?Personality = null,
|
||||
file: File.Index = 0,
|
||||
|
|
@ -27,9 +28,15 @@ pub const Cie = struct {
|
|||
for (aug[1..]) |ch| switch (ch) {
|
||||
'R' => {
|
||||
const enc: DW.EH.PE = @bitCast(try reader.takeByte());
|
||||
if (enc != @as(DW.EH.PE, .{ .type = .absptr, .rel = .pcrel })) {
|
||||
if (enc.rel != .pcrel) {
|
||||
@panic("unexpected pointer encoding"); // TODO error
|
||||
}
|
||||
|
||||
switch (enc.type) {
|
||||
.sdata4 => cie.address_ptr_size = .p32,
|
||||
.absptr => cie.address_ptr_size = .p64,
|
||||
else => @panic("unexpected pointer encoding"), // TODO error
|
||||
}
|
||||
},
|
||||
'P' => {
|
||||
const enc: DW.EH.PE = @bitCast(try reader.takeByte());
|
||||
|
|
@ -131,21 +138,6 @@ pub const Fde = struct {
|
|||
const object = fde.getObject(macho_file);
|
||||
const sect = object.sections.items(.header)[object.eh_frame_sect_index.?];
|
||||
|
||||
// Parse target atom index
|
||||
const pc_begin = std.mem.readInt(i64, data[8..][0..8], .little);
|
||||
const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
|
||||
fde.atom = object.findAtom(taddr) orelse {
|
||||
try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
|
||||
sect.segName(), sect.sectName(), fde.offset + 8,
|
||||
});
|
||||
return error.MalformedObject;
|
||||
};
|
||||
const atom = fde.getAtom(macho_file);
|
||||
fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
|
||||
|
||||
// Parse pc_range (function size)
|
||||
fde.pc_range = std.mem.readInt(u64, data[16..][0..8], .little);
|
||||
|
||||
// Associate with a CIE
|
||||
const cie_ptr = std.mem.readInt(u32, data[4..8], .little);
|
||||
const cie_offset = fde.offset + 4 - cie_ptr;
|
||||
|
|
@ -163,10 +155,34 @@ pub const Fde = struct {
|
|||
|
||||
const cie = fde.getCie(macho_file);
|
||||
|
||||
// Parse target atom index
|
||||
const pc_begin = switch (cie.address_ptr_size) {
|
||||
.p32 => std.mem.readInt(i32, data[8..][0..4], .little),
|
||||
.p64 => std.mem.readInt(i64, data[8..][0..8], .little),
|
||||
};
|
||||
const taddr: u64 = @intCast(@as(i64, @intCast(sect.addr + fde.offset + 8)) + pc_begin);
|
||||
fde.atom = object.findAtom(taddr) orelse {
|
||||
try macho_file.reportParseError2(object.index, "{s},{s}: 0x{x}: invalid function reference in FDE", .{
|
||||
sect.segName(), sect.sectName(), fde.offset + 8,
|
||||
});
|
||||
return error.MalformedObject;
|
||||
};
|
||||
const atom = fde.getAtom(macho_file);
|
||||
fde.atom_offset = @intCast(taddr - atom.getInputAddress(macho_file));
|
||||
|
||||
// Parse pc_range (function size)
|
||||
fde.pc_range = switch (cie.address_ptr_size) {
|
||||
.p32 => std.mem.readInt(u32, data[12..][0..4], .little),
|
||||
.p64 => std.mem.readInt(u64, data[16..][0..8], .little),
|
||||
};
|
||||
|
||||
// Parse LSDA atom index if any
|
||||
if (cie.lsda_size) |lsda_size| {
|
||||
var reader: std.Io.Reader = .fixed(data);
|
||||
reader.seek = 24;
|
||||
reader.seek = switch (cie.address_ptr_size) {
|
||||
.p32 => 16,
|
||||
.p64 => 24,
|
||||
};
|
||||
_ = try reader.takeLeb128(u64); // augmentation length
|
||||
fde.lsda_ptr_offset = @intCast(reader.seek);
|
||||
const lsda_ptr = switch (lsda_size) {
|
||||
|
|
@ -378,12 +394,21 @@ pub fn write(macho_file: *MachO, buffer: []u8) void {
|
|||
const offset = fde.out_offset + 8;
|
||||
const saddr = sect.addr + offset;
|
||||
const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
|
||||
std.mem.writeInt(
|
||||
i64,
|
||||
buffer[offset..][0..8],
|
||||
@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
|
||||
.little,
|
||||
);
|
||||
|
||||
switch (fde.getCie(macho_file).address_ptr_size) {
|
||||
.p32 => std.mem.writeInt(
|
||||
i32,
|
||||
buffer[offset..][0..4],
|
||||
@intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))),
|
||||
.little,
|
||||
),
|
||||
.p64 => std.mem.writeInt(
|
||||
i64,
|
||||
buffer[offset..][0..8],
|
||||
@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
|
||||
.little,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (fde.getLsdaAtom(macho_file)) |atom| {
|
||||
|
|
@ -465,12 +490,21 @@ pub fn writeRelocs(macho_file: *MachO, code: []u8, relocs: []macho.relocation_in
|
|||
const offset = fde.out_offset + 8;
|
||||
const saddr = sect.addr + offset;
|
||||
const taddr = fde.getAtom(macho_file).getAddress(macho_file) + fde.atom_offset;
|
||||
std.mem.writeInt(
|
||||
i64,
|
||||
code[offset..][0..8],
|
||||
@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
|
||||
.little,
|
||||
);
|
||||
|
||||
switch (fde.getCie(macho_file).address_ptr_size) {
|
||||
.p32 => std.mem.writeInt(
|
||||
i32,
|
||||
code[offset..][0..4],
|
||||
@intCast(@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr))),
|
||||
.little,
|
||||
),
|
||||
.p64 => std.mem.writeInt(
|
||||
i64,
|
||||
code[offset..][0..8],
|
||||
@as(i64, @intCast(taddr)) - @as(i64, @intCast(saddr)),
|
||||
.little,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (fde.getLsdaAtom(macho_file)) |atom| {
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
|
|||
macho_step.dependOn(testUnwindInfo(b, .{ .target = default_target }));
|
||||
macho_step.dependOn(testUnwindInfoNoSubsectionsX64(b, .{ .target = x86_64_target }));
|
||||
macho_step.dependOn(testUnwindInfoNoSubsectionsArm64(b, .{ .target = aarch64_target }));
|
||||
macho_step.dependOn(testEhFramePointerEncodingSdata4(b, .{ .target = aarch64_target }));
|
||||
macho_step.dependOn(testWeakBind(b, .{ .target = x86_64_target }));
|
||||
macho_step.dependOn(testWeakRef(b, .{ .target = b.resolveTargetQuery(.{
|
||||
.cpu_arch = .x86_64,
|
||||
|
|
@ -2852,6 +2853,71 @@ fn testUnwindInfo(b: *Build, opts: Options) *Step {
|
|||
return test_step;
|
||||
}
|
||||
|
||||
fn testEhFramePointerEncodingSdata4(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "eh_frame-pointer-encoding-sdata4", opts);
|
||||
|
||||
const a_o = addObject(b, opts, .{ .name = "foo", .asm_source_bytes =
|
||||
\\.global _foo
|
||||
\\.align 2
|
||||
\\_foo:
|
||||
\\ mov w0, #100
|
||||
\\ ret
|
||||
\\LEND_foo:
|
||||
\\
|
||||
\\.section __TEXT,__gcc_except_tab
|
||||
\\LLSDA_foo:
|
||||
\\ .byte 0xff
|
||||
\\ .byte 0xff
|
||||
\\ .byte 0x01
|
||||
\\ .uleb128 0
|
||||
\\
|
||||
\\.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
|
||||
\\LCIE:
|
||||
\\ .long LCIE_end - LCIE_start
|
||||
\\LCIE_start:
|
||||
\\ .long 0 ; CIE ID
|
||||
\\ .byte 1 ; Version
|
||||
\\ .asciz "zLR" ; Augmentation string
|
||||
\\ .uleb128 1 ; Code alignment factor
|
||||
\\ .sleb128 -8 ; Data alignment factor
|
||||
\\ .byte 30 ; Return address register
|
||||
\\ .uleb128 2 ; Augmentation data length
|
||||
\\ .byte 0x1b ; LSDA pointer encoding (DW_EH_PE_pcrel | DW_EH_PE_sdata4)
|
||||
\\ .byte 0x1b ; FDE pointer encoding (DW_EH_PE_pcrel | DW_EH_PE_sdata4)
|
||||
\\ .byte 0x0c ; DW_CFA_def_cfa
|
||||
\\ .uleb128 31 ; Reg 31
|
||||
\\ .uleb128 0 ; Offset 0
|
||||
\\ .align 3
|
||||
\\LCIE_end:
|
||||
\\LFDE:
|
||||
\\ .long LFDE_end - LFDE_start
|
||||
\\LFDE_start:
|
||||
\\ .long LFDE_start - LCIE ; CIE pointer
|
||||
\\ .long _foo - . ; PC begin
|
||||
\\ .long LEND_foo - _foo ; PC range
|
||||
\\ .uleb128 4 ; Augmentation data length
|
||||
\\ .long LLSDA_foo - . ; LSDA pointer
|
||||
\\ .align 3
|
||||
\\LFDE_end:
|
||||
});
|
||||
|
||||
const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes =
|
||||
\\#include <stdio.h>
|
||||
\\int foo();
|
||||
\\int main() {
|
||||
\\ printf("%d\n", foo());
|
||||
\\ return 0;
|
||||
\\}
|
||||
});
|
||||
exe.root_module.addObject(a_o);
|
||||
|
||||
const run = addRunArtifact(exe);
|
||||
run.expectStdOutEqual("100\n");
|
||||
test_step.dependOn(&run.step);
|
||||
|
||||
return test_step;
|
||||
}
|
||||
|
||||
fn testUnwindInfoNoSubsectionsArm64(b: *Build, opts: Options) *Step {
|
||||
const test_step = addTestStep(b, "unwind-info-no-subsections-arm64", opts);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue