authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-08-20 09:34:33+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-08-20 09:34:33+02:00
log83b0e52079298244912f2d2f28b256457c8dc3a5
treea1fc4070f2a06bcfe665f93ae094f99166a674c9
parent91de5c212fe847a309f047e3097491bba6f86ae1
parentad79b80524820d3f0ec60d4d21461208227cd4c8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6102 from kubkon/macho-pagezero

Write page zero as first segment for Mach-O exes

1 files changed, 55 insertions(+), 4 deletions(-)

src-self-hosted/link/MachO.zig+55-4
...@@ -6,6 +6,8 @@ const assert = std.debug.assert;...@@ -6,6 +6,8 @@ const assert = std.debug.assert;
6const fs = std.fs;6const fs = std.fs;
7const log = std.log.scoped(.link);7const log = std.log.scoped(.link);
8const macho = std.macho;8const macho = std.macho;
9const math = std.math;
10const mem = std.mem;
911
10const Module = @import("../Module.zig");12const Module = @import("../Module.zig");
11const link = @import("../link.zig");13const link = @import("../link.zig");
...@@ -15,6 +17,14 @@ pub const base_tag: Tag = File.Tag.macho;...@@ -15,6 +17,14 @@ pub const base_tag: Tag = File.Tag.macho;
1517
16base: File,18base: File,
1719
20/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
21/// Same order as in the file.
22segment_cmds: std.ArrayListUnmanaged(macho.segment_command_64) = std.ArrayListUnmanaged(macho.segment_command_64){},
23
24/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
25/// Same order as in the file.
26sections: std.ArrayListUnmanaged(macho.section_64) = std.ArrayListUnmanaged(macho.section_64){},
27
18entry_addr: ?u64 = null,28entry_addr: ?u64 = null,
1929
20error_flags: File.ErrorFlags = File.ErrorFlags{},30error_flags: File.ErrorFlags = File.ErrorFlags{},
...@@ -86,9 +96,33 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach...@@ -86,9 +96,33 @@ fn createFile(allocator: *Allocator, file: fs.File, options: link.Options) !Mach
86 };96 };
87 errdefer self.deinit();97 errdefer self.deinit();
8898
99 if (options.output_mode == .Exe) {
100 // The first segment command for executables is always a __PAGEZERO segment.
101 try self.segment_cmds.append(allocator, .{
102 .cmd = macho.LC_SEGMENT_64,
103 .cmdsize = @sizeOf(macho.segment_command_64),
104 .segname = self.makeString("__PAGEZERO"),
105 .vmaddr = 0,
106 .vmsize = 0,
107 .fileoff = 0,
108 .filesize = 0,
109 .maxprot = 0,
110 .initprot = 0,
111 .nsects = 0,
112 .flags = 0,
113 });
114 }
115
89 return self;116 return self;
90}117}
91118
119fn makeString(self: *MachO, comptime bytes: []const u8) [16]u8 {
120 var buf: [16]u8 = undefined;
121 if (bytes.len > buf.len) @compileError("MachO segment/section name too long");
122 mem.copy(u8, buf[0..], bytes);
123 return buf;
124}
125
92fn writeMachOHeader(self: *MachO) !void {126fn writeMachOHeader(self: *MachO) !void {
93 var hdr: macho.mach_header_64 = undefined;127 var hdr: macho.mach_header_64 = undefined;
94 hdr.magic = macho.MH_MAGIC_64;128 hdr.magic = macho.MH_MAGIC_64;
...@@ -122,9 +156,12 @@ fn writeMachOHeader(self: *MachO) !void {...@@ -122,9 +156,12 @@ fn writeMachOHeader(self: *MachO) !void {
122 };156 };
123 hdr.filetype = filetype;157 hdr.filetype = filetype;
124158
125 // TODO the rest of the header159 // TODO consider other commands
126 hdr.ncmds = 0;160 const ncmds = try math.cast(u32, self.segment_cmds.items.len);
127 hdr.sizeofcmds = 0;161 hdr.ncmds = ncmds;
162 hdr.sizeofcmds = ncmds * @sizeOf(macho.segment_command_64);
163
164 // TODO should these be set to something else?
128 hdr.flags = 0;165 hdr.flags = 0;
129 hdr.reserved = 0;166 hdr.reserved = 0;
130167
...@@ -133,6 +170,17 @@ fn writeMachOHeader(self: *MachO) !void {...@@ -133,6 +170,17 @@ fn writeMachOHeader(self: *MachO) !void {
133170
134pub fn flush(self: *MachO, module: *Module) !void {171pub fn flush(self: *MachO, module: *Module) !void {
135 // TODO implement flush172 // TODO implement flush
173 {
174 const buf = try self.base.allocator.alloc(macho.segment_command_64, self.segment_cmds.items.len);
175 defer self.base.allocator.free(buf);
176
177 for (buf) |*seg, i| {
178 seg.* = self.segment_cmds.items[i];
179 }
180
181 try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), @sizeOf(macho.mach_header_64));
182 }
183
136 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {184 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
137 log.debug("flushing. no_entry_point_found = true\n", .{});185 log.debug("flushing. no_entry_point_found = true\n", .{});
138 self.error_flags.no_entry_point_found = true;186 self.error_flags.no_entry_point_found = true;
...@@ -143,7 +191,10 @@ pub fn flush(self: *MachO, module: *Module) !void {...@@ -143,7 +191,10 @@ pub fn flush(self: *MachO, module: *Module) !void {
143 }191 }
144}192}
145193
146pub fn deinit(self: *MachO) void {}194pub fn deinit(self: *MachO) void {
195 self.segment_cmds.deinit(self.base.allocator);
196 self.sections.deinit(self.base.allocator);
197}
147198
148pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}199pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {}
149200