mirror of
https://github.com/ziglang/zig.git
synced 2026-01-21 06:45:24 +00:00
Write page zero as first segment for Mach-O exes
According to the Mach-O file format reference, the first load command should be a `__PAGEZERO` segment command. The segment is located at virtual memory location 0, has no protection rights, and causes acccesses to NULL to immediately crash. Signed-off-by: Jakub Konka <kubkon@jakubkonka.com>
This commit is contained in:
parent
91de5c212f
commit
9164daaa39
@ -6,6 +6,8 @@ const assert = std.debug.assert;
|
||||
const fs = std.fs;
|
||||
const log = std.log.scoped(.link);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
const Module = @import("../Module.zig");
|
||||
const link = @import("../link.zig");
|
||||
@ -15,6 +17,14 @@ pub const base_tag: Tag = File.Tag.macho;
|
||||
|
||||
base: File,
|
||||
|
||||
/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
|
||||
/// Same order as in the file.
|
||||
segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){},
|
||||
|
||||
/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
|
||||
/// Same order as in the file.
|
||||
sections: std.ArrayListUnmanaged(macho.@"section_64") = std.ArrayListUnmanaged(macho.@"section_64"){},
|
||||
|
||||
entry_addr: ?u64 = null,
|
||||
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
@ -86,9 +96,34 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach
|
||||
};
|
||||
errdefer self.deinit();
|
||||
|
||||
if (options.output_mode == .Exe) {
|
||||
// The first segment command for executables is always a __PAGEZERO segment.
|
||||
try self.segment_cmds.append(allocator, .{
|
||||
.cmd = macho.LC_SEGMENT_64,
|
||||
.cmdsize = @sizeOf(macho.segment_command_64),
|
||||
.segname = self.makeString("__PAGEZERO"),
|
||||
.vmaddr = 0,
|
||||
.vmsize = 0,
|
||||
.fileoff = 0,
|
||||
.filesize = 0,
|
||||
.maxprot = 0,
|
||||
.initprot = 0,
|
||||
.nsects = 0,
|
||||
.flags = 0,
|
||||
});
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 {
|
||||
if (bytes.len > 16) @compileError("MachO segment/section name too long");
|
||||
|
||||
var buf: [16]u8 = undefined;
|
||||
mem.copy(u8, buf[0..], bytes);
|
||||
return buf;
|
||||
}
|
||||
|
||||
fn writeMachOHeader(self: *MachO) !void {
|
||||
var hdr: macho.mach_header_64 = undefined;
|
||||
hdr.magic = macho.MH_MAGIC_64;
|
||||
@ -122,9 +157,12 @@ fn writeMachOHeader(self: *MachO) !void {
|
||||
};
|
||||
hdr.filetype = filetype;
|
||||
|
||||
// TODO the rest of the header
|
||||
hdr.ncmds = 0;
|
||||
hdr.sizeofcmds = 0;
|
||||
// TODO consider other commands
|
||||
const ncmds = try math.cast(u32, self.segment_cmds.items.len);
|
||||
hdr.ncmds = ncmds;
|
||||
hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64);
|
||||
|
||||
// TODO should these be set to something else?
|
||||
hdr.flags = 0;
|
||||
hdr.reserved = 0;
|
||||
|
||||
@ -133,6 +171,17 @@ fn writeMachOHeader(self: *MachO) !void {
|
||||
|
||||
pub fn flush(self: *MachO, module: *Module) !void {
|
||||
// TODO implement flush
|
||||
{
|
||||
const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len);
|
||||
defer self.base.allocator.free(buf);
|
||||
|
||||
for (buf) |*seg, i| {
|
||||
seg.* = self.segment_cmds.items[i];
|
||||
}
|
||||
|
||||
try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64));
|
||||
}
|
||||
|
||||
if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
|
||||
log.debug("flushing. no_entry_point_found = true\n", .{});
|
||||
self.error_flags.no_entry_point_found = true;
|
||||
@ -143,7 +192,10 @@ pub fn flush(self: *MachO, module: *Module) !void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *MachO) void {}
|
||||
pub fn deinit(self: *MachO) void {
|
||||
self.segment_cmds.deinit(self.base.allocator);
|
||||
self.@"sections".deinit(self.base.allocator);
|
||||
}
|
||||
|
||||
pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user