Skip to content

Commit

Permalink
Merge pull request #103 from kubkon/big-sur
Browse files Browse the repository at this point in the history
macho: macOS 11 fixes
  • Loading branch information
kubkon authored Jan 24, 2024
2 parents 706065e + b97a0bb commit d90c5c8
Show file tree
Hide file tree
Showing 11 changed files with 216 additions and 155 deletions.
15 changes: 13 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ on: [push, pull_request]
jobs:
default_tools:
name: Test default system tools
runs-on: ${{ matrix.os }}-latest
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# https://github.com/kubkon/zld/issues/44
# os: [macos, ubuntu, windows]
os: [macos, ubuntu]
os: [ macos-12, macos-latest, ubuntu-latest ]

steps:
- if: matrix.os == 'windows'
Expand All @@ -22,6 +22,17 @@ jobs:
version: master
- run: zig version
- run: zig fmt --check src
- run: zig build test -Dhas-static -Dhas-zig -Dhas-objc-msgsend-stubs

macos_11:
name: Test macos 11.0
runs-on: macos-11
steps:
- uses: actions/checkout@v3
- uses: goto-bus-stop/setup-zig@v2
with:
version: master
- run: zig version
- run: zig build test -Dhas-static -Dhas-zig

gcc_musl:
Expand Down
2 changes: 2 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub fn build(b: *std.Build) void {
const has_static = b.option(bool, "has-static", "Whether the system compiler supports '-static' flag") orelse false;
const has_zig = b.option(bool, "has-zig", "Whether the Zig compiler is in path") orelse false;
const is_musl = b.option(bool, "musl", "Whether the tests are linked against musl libc") orelse false;
const has_objc_msgsend_stubs = b.option(bool, "has-objc-msgsend-stubs", "Whether the system compiler supports '-fobjc-msgsend-selector-stubs' flag") orelse false;

const unit_tests = b.addTest(.{
.root_source_file = .{ .path = "src/Zld.zig" },
Expand All @@ -93,6 +94,7 @@ pub fn build(b: *std.Build) void {
.has_static = has_static,
.has_zig = has_zig,
.is_musl = is_musl,
.has_objc_msgsend_stubs = has_objc_msgsend_stubs,
}));
}

Expand Down
104 changes: 61 additions & 43 deletions src/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ pub fn flush(self: *MachO) !void {
// The most important here is to have the correct vm and filesize of the __LINKEDIT segment
// where the code signature goes into.
var codesig = CodeSignature.init(self.getPageSize());
codesig.code_directory.ident = self.options.emit.sub_path;
codesig.code_directory.ident = std.fs.path.basename(self.options.emit.sub_path);
if (self.options.entitlements) |path| try codesig.addEntitlements(gpa, path);
try self.writeCodeSignaturePadding(&codesig);
break :blk codesig;
Expand Down Expand Up @@ -1470,14 +1470,14 @@ fn initSyntheticSections(self: *MachO) !void {
}

const needs_unwind_info = for (self.objects.items) |index| {
if (self.getFile(index).?.object.compact_unwind_sect_index != null) break true;
if (self.getFile(index).?.object.hasUnwindRecords()) break true;
} else false;
if (needs_unwind_info) {
self.unwind_info_sect_index = try self.addSection("__TEXT", "__unwind_info", .{});
}

const needs_eh_frame = for (self.objects.items) |index| {
if (self.getFile(index).?.object.eh_frame_sect_index != null) break true;
if (self.getFile(index).?.object.hasEhFrameRecords()) break true;
} else false;
if (needs_eh_frame) {
assert(needs_unwind_info);
Expand Down Expand Up @@ -1536,50 +1536,71 @@ fn getSegmentProt(segname: []const u8) macho.vm_prot_t {

fn getSegmentRank(segname: []const u8) u4 {
if (mem.eql(u8, segname, "__PAGEZERO")) return 0x0;
if (mem.eql(u8, segname, "__TEXT")) return 0x1;
if (mem.eql(u8, segname, "__DATA_CONST")) return 0x2;
if (mem.eql(u8, segname, "__DATA")) return 0x3;
if (mem.eql(u8, segname, "__LINKEDIT")) return 0x5;
if (mem.startsWith(u8, segname, "__TEXT")) return 0x1;
if (mem.startsWith(u8, segname, "__DATA_CONST")) return 0x2;
if (mem.startsWith(u8, segname, "__DATA")) return 0x3;
return 0x4;
}

fn getSectionRank(self: *MachO, sect_index: u8) u8 {
const header = self.sections.items(.header)[sect_index];
const segment_rank = getSegmentRank(header.segName());
const section_rank: u4 = blk: {
if (header.isCode()) {
if (mem.eql(u8, "__text", header.sectName())) break :blk 0x0;
if (header.type() == macho.S_SYMBOL_STUBS) break :blk 0x1;
break :blk 0x2;
}
switch (header.type()) {
macho.S_NON_LAZY_SYMBOL_POINTERS,
macho.S_LAZY_SYMBOL_POINTERS,
=> break :blk 0x0,

macho.S_MOD_INIT_FUNC_POINTERS => break :blk 0x1,
macho.S_MOD_TERM_FUNC_POINTERS => break :blk 0x2,
macho.S_ZEROFILL => break :blk 0xf,
macho.S_THREAD_LOCAL_REGULAR => break :blk 0xd,
macho.S_THREAD_LOCAL_ZEROFILL => break :blk 0xe,

else => {
if (mem.eql(u8, "__unwind_info", header.sectName())) break :blk 0xe;
if (mem.eql(u8, "__compact_unwind", header.sectName())) break :blk 0xe;
if (mem.eql(u8, "__eh_frame", header.sectName())) break :blk 0xf;
break :blk 0x3;
},
fn segmentLessThan(ctx: void, lhs: []const u8, rhs: []const u8) bool {
_ = ctx;
const lhs_rank = getSegmentRank(lhs);
const rhs_rank = getSegmentRank(rhs);
if (lhs_rank == rhs_rank) {
return mem.order(u8, lhs, rhs) == .lt;
}
return lhs_rank < rhs_rank;
}

fn getSectionRank(section: macho.section_64) u8 {
if (section.isCode()) {
if (mem.eql(u8, "__text", section.sectName())) return 0x0;
if (section.type() == macho.S_SYMBOL_STUBS) return 0x1;
return 0x2;
}
switch (section.type()) {
macho.S_NON_LAZY_SYMBOL_POINTERS,
macho.S_LAZY_SYMBOL_POINTERS,
=> return 0x0,

macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
macho.S_ZEROFILL => return 0xf,
macho.S_THREAD_LOCAL_REGULAR => return 0xd,
macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,

else => {
if (mem.eql(u8, "__unwind_info", section.sectName())) return 0xe;
if (mem.eql(u8, "__compact_unwind", section.sectName())) return 0xe;
if (mem.eql(u8, "__eh_frame", section.sectName())) return 0xf;
return 0x3;
},
}
}

fn sectionLessThan(ctx: void, lhs: macho.section_64, rhs: macho.section_64) bool {
if (mem.eql(u8, lhs.segName(), rhs.segName())) {
const lhs_rank = getSectionRank(lhs);
const rhs_rank = getSectionRank(rhs);
if (lhs_rank == rhs_rank) {
return mem.order(u8, lhs.sectName(), rhs.sectName()) == .lt;
}
};
return (@as(u8, @intCast(segment_rank)) << 4) + section_rank;
return lhs_rank < rhs_rank;
}
return segmentLessThan(ctx, lhs.segName(), rhs.segName());
}

pub fn sortSections(self: *MachO) !void {
const Entry = struct {
index: u8,

pub fn lessThan(macho_file: *MachO, lhs: @This(), rhs: @This()) bool {
return macho_file.getSectionRank(lhs.index) < macho_file.getSectionRank(rhs.index);
return sectionLessThan(
{},
macho_file.sections.items(.header)[lhs.index],
macho_file.sections.items(.header)[rhs.index],
);
}
};

Expand Down Expand Up @@ -1741,7 +1762,7 @@ fn calcSectionSizes(self: *MachO) !void {
const header = &self.sections.items(.header)[idx];
header.size = self.stubs.size(self);
header.@"align" = switch (cpu_arch) {
.x86_64 => 0,
.x86_64 => 1,
.aarch64 => 2,
else => 0,
};
Expand All @@ -1750,11 +1771,7 @@ fn calcSectionSizes(self: *MachO) !void {
if (self.stubs_helper_sect_index) |idx| {
const header = &self.sections.items(.header)[idx];
header.size = self.stubs_helper.size(self);
header.@"align" = switch (cpu_arch) {
.x86_64 => 0,
.aarch64 => 2,
else => 0,
};
header.@"align" = 2;
}

if (self.la_symbol_ptr_sect_index) |idx| {
Expand Down Expand Up @@ -1789,11 +1806,13 @@ fn initSegments(self: *MachO) !void {
const segname = header.segName();
if (self.getSegmentByName(segname) == null) {
const prot = getSegmentProt(segname);
const flags: u32 = if (mem.startsWith(u8, segname, "__DATA_CONST")) 0x10 else 0; // TODO usee macho.SG_READ_ONLY once upstreamed
try self.segments.append(gpa, .{
.cmdsize = @sizeOf(macho.segment_command_64),
.segname = makeStaticString(segname),
.maxprot = prot,
.initprot = prot,
.flags = flags,
});
}
}
Expand Down Expand Up @@ -1839,8 +1858,7 @@ fn initSegments(self: *MachO) !void {

const sortFn = struct {
fn sortFn(ctx: void, lhs: macho.segment_command_64, rhs: macho.segment_command_64) bool {
_ = ctx;
return getSegmentRank(lhs.segName()) < getSegmentRank(rhs.segName());
return segmentLessThan(ctx, lhs.segName(), rhs.segName());
}
}.sortFn;

Expand Down
29 changes: 13 additions & 16 deletions src/MachO/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
switch (rel.type) {
.branch => {
const symbol = rel.getTargetSymbol(macho_file);
if (symbol.flags.import or (symbol.flags.@"export" and (symbol.flags.weak or symbol.flags.interposable))) {
if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {
symbol.flags.stubs = true;
if (symbol.flags.weak) {
macho_file.binds_to_weak = true;
Expand All @@ -199,7 +199,8 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
=> {
const symbol = rel.getTargetSymbol(macho_file);
if (symbol.flags.import or
(symbol.flags.@"export" and (symbol.flags.weak or symbol.flags.interposable)) or
(symbol.flags.@"export" and symbol.flags.weak) or
symbol.flags.interposable or
macho_file.options.cpu_arch.? == .aarch64) // TODO relax on arm64
{
symbol.flags.got = true;
Expand All @@ -224,7 +225,7 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
.{ object.fmtPath(), self.getName(macho_file), symbol.getName(macho_file) },
);
}
if (symbol.flags.import or (symbol.flags.@"export" and (symbol.flags.weak or symbol.flags.interposable))) {
if (symbol.flags.import or (symbol.flags.@"export" and symbol.flags.weak) or symbol.flags.interposable) {
symbol.flags.tlv_ptr = true;
if (symbol.flags.weak) {
macho_file.binds_to_weak = true;
Expand All @@ -248,13 +249,11 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
}
continue;
}
if (symbol.flags.@"export") {
if (symbol.flags.weak) {
object.num_weak_bind_relocs += 1;
macho_file.binds_to_weak = true;
} else if (symbol.flags.interposable) {
object.num_bind_relocs += 1;
}
if (symbol.flags.@"export" and symbol.flags.weak) {
object.num_weak_bind_relocs += 1;
macho_file.binds_to_weak = true;
} else if (symbol.flags.interposable) {
object.num_bind_relocs += 1;
}
}
object.num_rebase_relocs += 1;
Expand Down Expand Up @@ -391,12 +390,10 @@ fn resolveRelocInner(
}
return;
}
if (sym.flags.@"export") {
if (sym.flags.weak) {
macho_file.weak_bind.entries.appendAssumeCapacity(entry);
} else if (sym.flags.interposable) {
macho_file.bind.entries.appendAssumeCapacity(entry);
}
if (sym.flags.@"export" and sym.flags.weak) {
macho_file.weak_bind.entries.appendAssumeCapacity(entry);
} else if (sym.flags.interposable) {
macho_file.bind.entries.appendAssumeCapacity(entry);
}
}
macho_file.rebase.entries.appendAssumeCapacity(.{
Expand Down
Loading

0 comments on commit d90c5c8

Please sign in to comment.