mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
Link against libSystem when generating Mach-O exe
This is required when generating an exe on macOS. Signed-off-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
parent
2516db9645
commit
1698e6d7a7
@ -11,6 +11,7 @@ const macho = std.macho;
|
|||||||
usingnamespace @import("../os/bits.zig");
|
usingnamespace @import("../os/bits.zig");
|
||||||
|
|
||||||
extern "c" fn __error() *c_int;
|
extern "c" fn __error() *c_int;
|
||||||
|
pub extern "c" fn NSVersionOfRunTimeLibrary(library_name: [*:0]const u8) u32;
|
||||||
pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
|
pub extern "c" fn _NSGetExecutablePath(buf: [*]u8, bufsize: *u32) c_int;
|
||||||
pub extern "c" fn _dyld_image_count() u32;
|
pub extern "c" fn _dyld_image_count() u32;
|
||||||
pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
|
pub extern "c" fn _dyld_get_image_header(image_index: u32) ?*mach_header;
|
||||||
|
|||||||
@ -119,6 +119,38 @@ pub const dylinker_command = extern struct {
|
|||||||
name: u32,
|
name: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const dylib_command = extern struct {
|
||||||
|
/// LC_ID_DYLIB, LC_LOAD_WEAK_DYLIB, LC_LOAD_DYLIB, LC_REEXPORT_DYLIB
|
||||||
|
cmd: u32,
|
||||||
|
|
||||||
|
/// includes pathname string
|
||||||
|
cmdsize: u32,
|
||||||
|
|
||||||
|
/// the library identification
|
||||||
|
dylib: dylib,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Dynamicaly linked shared libraries are identified by two things. The
|
||||||
|
/// pathname (the name of the library as found for execution), and the
|
||||||
|
/// compatibility version number. The pathname must match and the compatibility
|
||||||
|
/// number in the user of the library must be greater than or equal to the
|
||||||
|
/// library being used. The time stamp is used to record the time a library was
|
||||||
|
/// built and copied into user so it can be use to determined if the library used
|
||||||
|
/// at runtime is exactly the same as used to built the program.
|
||||||
|
pub const dylib = extern struct {
|
||||||
|
/// library's pathname (offset pointing at the end of dylib_command)
|
||||||
|
name: u32,
|
||||||
|
|
||||||
|
/// library's build timestamp
|
||||||
|
timestamp: u32,
|
||||||
|
|
||||||
|
/// library's current version number
|
||||||
|
current_version: u32,
|
||||||
|
|
||||||
|
/// library's compatibility version number
|
||||||
|
compatibility_version: u32,
|
||||||
|
};
|
||||||
|
|
||||||
/// The segment load command indicates that a part of this file is to be
|
/// The segment load command indicates that a part of this file is to be
|
||||||
/// mapped into the task's address space. The size of this segment in memory,
|
/// mapped into the task's address space. The size of this segment in memory,
|
||||||
/// vmsize, maybe equal to or larger than the amount to map from this file,
|
/// vmsize, maybe equal to or larger than the amount to map from this file,
|
||||||
|
|||||||
@ -49,6 +49,10 @@ const alloc_den = 3;
|
|||||||
/// Default path to dyld
|
/// Default path to dyld
|
||||||
const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
|
const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
|
||||||
|
|
||||||
|
/// We always have to link against libSystem since macOS Catalina (TODO link)
|
||||||
|
const LIB_SYSTEM_NAME: [*:0]const u8 = "System";
|
||||||
|
const LIB_SYSTEM_PATH: [*:0]const u8 = "/usr/lib/libSystem.B.dylib";
|
||||||
|
|
||||||
pub const TextBlock = struct {
|
pub const TextBlock = struct {
|
||||||
pub const empty = TextBlock{};
|
pub const empty = TextBlock{};
|
||||||
};
|
};
|
||||||
@ -226,12 +230,41 @@ pub fn flush(self: *MachO, module: *Module) !void {
|
|||||||
|
|
||||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylinker[0..1]), self.command_file_offset.?);
|
try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylinker[0..1]), self.command_file_offset.?);
|
||||||
|
|
||||||
const padded_path = try self.base.allocator.alloc(u8, cmdsize - @sizeOf(macho.dylinker_command));
|
const file_offset = self.command_file_offset.? + @sizeOf(macho.dylinker_command);
|
||||||
defer self.base.allocator.free(padded_path);
|
try self.addPadding(cmdsize - @sizeOf(macho.dylinker_command), file_offset);
|
||||||
mem.set(u8, padded_path[0..], 0);
|
|
||||||
mem.copy(u8, padded_path[0..], mem.spanZ(DEFAULT_DYLD_PATH));
|
|
||||||
|
|
||||||
try self.base.file.?.pwriteAll(padded_path, self.command_file_offset.? + @sizeOf(macho.dylinker_command));
|
try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), file_offset);
|
||||||
|
self.command_file_offset.? += cmdsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Link against libSystem
|
||||||
|
const cmdsize = commandSize(@intCast(u32, @sizeOf(macho.dylib_command) + mem.lenZ(LIB_SYSTEM_PATH)));
|
||||||
|
const version = std.c.NSVersionOfRunTimeLibrary(LIB_SYSTEM_NAME);
|
||||||
|
const dylib = .{
|
||||||
|
.name = @sizeOf(macho.dylib_command),
|
||||||
|
.timestamp = 2, // not sure why not simply 0; this is reverse engineered from Mach-O files
|
||||||
|
.current_version = version,
|
||||||
|
.compatibility_version = 0x10000, // not sure why this either; value from reverse engineering
|
||||||
|
};
|
||||||
|
const load_dylib = [1]macho.dylib_command{
|
||||||
|
.{
|
||||||
|
.cmd = macho.LC_LOAD_DYLIB,
|
||||||
|
.cmdsize = cmdsize,
|
||||||
|
.dylib = dylib,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try self.commands.append(self.base.allocator, .{
|
||||||
|
.cmd = macho.LC_LOAD_DYLIB,
|
||||||
|
.cmdsize = cmdsize,
|
||||||
|
});
|
||||||
|
|
||||||
|
try self.base.file.?.pwriteAll(mem.sliceAsBytes(load_dylib[0..1]), self.command_file_offset.?);
|
||||||
|
|
||||||
|
const file_offset = self.command_file_offset.? + @sizeOf(macho.dylib_command);
|
||||||
|
try self.addPadding(cmdsize - @sizeOf(macho.dylib_command), file_offset);
|
||||||
|
|
||||||
|
try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), file_offset);
|
||||||
self.command_file_offset.? += cmdsize;
|
self.command_file_offset.? += cmdsize;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -431,3 +464,14 @@ fn commandSize(min_size: u32) u32 {
|
|||||||
const div = min_size / @sizeOf(u64);
|
const div = min_size / @sizeOf(u64);
|
||||||
return (div + 1) * @sizeOf(u64);
|
return (div + 1) * @sizeOf(u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn addPadding(self: *MachO, size: u32, file_offset: u64) !void {
|
||||||
|
if (size == 0) return;
|
||||||
|
|
||||||
|
const buf = try self.base.allocator.alloc(u8, size);
|
||||||
|
defer self.base.allocator.free(buf);
|
||||||
|
|
||||||
|
mem.set(u8, buf[0..], 0);
|
||||||
|
|
||||||
|
try self.base.file.?.pwriteAll(buf, file_offset);
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user