| author | |
| committer | |
| log | 633c4a2a6094cd301648c2e2c6b5002917e0ef2c |
| tree | fdad1685dde93d39af844d257440ddd42ba3046b |
| parent | 2036af94e97f0ac16293556423c144ec9e1b8226 |
`std.os.darwin.MachTask` wraps `mach_port_t` and can be used to issue
kernel calls tied to the wrapped Mach kernel port/task.6 files changed, 255 insertions(+), 47 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -460,6 +460,7 @@ set(ZIG_STAGE2_SOURCES |
| 460 | 460 | "${CMAKE_SOURCE_DIR}/lib/std/meta/trait.zig" |
| 461 | 461 | "${CMAKE_SOURCE_DIR}/lib/std/multi_array_list.zig" |
| 462 | 462 | "${CMAKE_SOURCE_DIR}/lib/std/os.zig" |
| 463 | "${CMAKE_SOURCE_DIR}/lib/std/os/darwin.zig" | |
| 463 | 464 | "${CMAKE_SOURCE_DIR}/lib/std/os/linux.zig" |
| 464 | 465 | "${CMAKE_SOURCE_DIR}/lib/std/os/linux/errno/generic.zig" |
| 465 | 466 | "${CMAKE_SOURCE_DIR}/lib/std/os/linux/x86_64.zig" |
lib/std/c/darwin.zig+18-7| ... | ... | @@ -201,9 +201,9 @@ pub const vm_object_id_t = u64; |
| 201 | 201 | |
| 202 | 202 | pub const vm_region_submap_info_64 = extern struct { |
| 203 | 203 | // present across protection |
| 204 | protection: std.macho.vm_prot_t, | |
| 204 | protection: vm_prot_t, | |
| 205 | 205 | // max avail through vm_prot |
| 206 | max_protection: std.macho.vm_prot_t, | |
| 206 | max_protection: vm_prot_t, | |
| 207 | 207 | // behavior of map/obj on fork |
| 208 | 208 | inheritance: vm_inherit_t, |
| 209 | 209 | // offset into object/map |
| ... | ... | @@ -391,6 +391,7 @@ pub const task_vm_info = extern struct { |
| 391 | 391 | }; |
| 392 | 392 | pub const task_vm_info_data_t = task_vm_info; |
| 393 | 393 | |
| 394 | pub const vm_prot_t = c_int; | |
| 394 | 395 | pub const boolean_t = c_int; |
| 395 | 396 | |
| 396 | 397 | pub extern "c" fn mach_vm_protect( |
| ... | ... | @@ -398,7 +399,7 @@ pub extern "c" fn mach_vm_protect( |
| 398 | 399 | address: mach_vm_address_t, |
| 399 | 400 | size: mach_vm_size_t, |
| 400 | 401 | set_maximum: boolean_t, |
| 401 | new_protection: std.macho.vm_prot_t, | |
| 402 | new_protection: vm_prot_t, | |
| 402 | 403 | ) kern_return_t; |
| 403 | 404 | |
| 404 | 405 | pub extern "c" fn mach_port_deallocate(target_tport: mach_port_name_t, task: mach_port_name_t) kern_return_t; |
| ... | ... | @@ -920,13 +921,19 @@ pub const STDERR_FILENO = 2; |
| 920 | 921 | |
| 921 | 922 | pub const PROT = struct { |
| 922 | 923 | /// [MC2] no permissions |
| 923 | pub const NONE = 0x00; | |
| 924 | pub const NONE: vm_prot_t = 0x00; | |
| 924 | 925 | /// [MC2] pages can be read |
| 925 | pub const READ = 0x01; | |
| 926 | pub const READ: vm_prot_t = 0x01; | |
| 926 | 927 | /// [MC2] pages can be written |
| 927 | pub const WRITE = 0x02; | |
| 928 | pub const WRITE: vm_prot_t = 0x02; | |
| 928 | 929 | /// [MC2] pages can be executed |
| 929 | pub const EXEC = 0x04; | |
| 930 | pub const EXEC: vm_prot_t = 0x04; | |
| 931 | /// When a caller finds that they cannot obtain write permission on a | |
| 932 | /// mapped entry, the following flag can be used. The entry will be | |
| 933 | /// made "needs copy" effectively copying the object (using COW), | |
| 934 | /// and write permission will be added to the maximum protections for | |
| 935 | /// the associated entry. | |
| 936 | pub const COPY: vm_prot_t = 0x10; | |
| 930 | 937 | }; |
| 931 | 938 | |
| 932 | 939 | pub const MAP = struct { |
| ... | ... | @@ -1771,6 +1778,10 @@ pub const E = enum(u16) { |
| 1771 | 1778 | _, |
| 1772 | 1779 | }; |
| 1773 | 1780 | |
| 1781 | pub fn getKernError(err: kern_return_t) KernE { | |
| 1782 | return @intToEnum(KernE, err); | |
| 1783 | } | |
| 1784 | ||
| 1774 | 1785 | /// Kernel return values |
| 1775 | 1786 | pub const KernE = enum(u8) { |
| 1776 | 1787 | SUCCESS = 0, |
lib/std/macho.zig+10-31| ... | ... | @@ -2,12 +2,16 @@ const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | const assert = std.debug.assert; |
| 4 | 4 | const io = std.io; |
| 5 | const os = std.os.darwin; | |
| 5 | 6 | const mem = std.mem; |
| 6 | 7 | const meta = std.meta; |
| 7 | 8 | const testing = std.testing; |
| 8 | 9 | |
| 9 | 10 | const Allocator = mem.Allocator; |
| 10 | 11 | |
| 12 | pub const cpu_type_t = os.integer_t; | |
| 13 | pub const cpu_subtype_t = os.integer_t; | |
| 14 | ||
| 11 | 15 | pub const mach_header = extern struct { |
| 12 | 16 | magic: u32, |
| 13 | 17 | cputype: cpu_type_t, |
| ... | ... | @@ -601,10 +605,10 @@ pub const segment_command = extern struct { |
| 601 | 605 | filesize: u32, |
| 602 | 606 | |
| 603 | 607 | /// maximum VM protection |
| 604 | maxprot: vm_prot_t, | |
| 608 | maxprot: os.vm_prot_t, | |
| 605 | 609 | |
| 606 | 610 | /// initial VM protection |
| 607 | initprot: vm_prot_t, | |
| 611 | initprot: os.vm_prot_t, | |
| 608 | 612 | |
| 609 | 613 | /// number of sections in segment |
| 610 | 614 | nsects: u32, |
| ... | ... | @@ -638,10 +642,10 @@ pub const segment_command_64 = extern struct { |
| 638 | 642 | filesize: u64 = 0, |
| 639 | 643 | |
| 640 | 644 | /// maximum VM protection |
| 641 | maxprot: vm_prot_t = VM_PROT_NONE, | |
| 645 | maxprot: os.vm_prot_t = os.PROT.NONE, | |
| 642 | 646 | |
| 643 | 647 | /// initial VM protection |
| 644 | initprot: vm_prot_t = VM_PROT_NONE, | |
| 648 | initprot: os.vm_prot_t = os.PROT.NONE, | |
| 645 | 649 | |
| 646 | 650 | /// number of sections in segment |
| 647 | 651 | nsects: u32 = 0, |
| ... | ... | @@ -1438,11 +1442,6 @@ pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15; |
| 1438 | 1442 | /// 32-bit offsets to initializers |
| 1439 | 1443 | pub const S_INIT_FUNC_OFFSETS = 0x16; |
| 1440 | 1444 | |
| 1441 | pub const cpu_type_t = integer_t; | |
| 1442 | pub const cpu_subtype_t = integer_t; | |
| 1443 | pub const integer_t = c_int; | |
| 1444 | pub const vm_prot_t = c_int; | |
| 1445 | ||
| 1446 | 1445 | /// CPU type targeting 64-bit Intel-based Macs |
| 1447 | 1446 | pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007; |
| 1448 | 1447 | |
| ... | ... | @@ -1455,26 +1454,6 @@ pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3; |
| 1455 | 1454 | /// All ARM-based Macs |
| 1456 | 1455 | pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0; |
| 1457 | 1456 | |
| 1458 | // Protection values defined as bits within the vm_prot_t type | |
| 1459 | /// No VM protection | |
| 1460 | pub const VM_PROT_NONE: vm_prot_t = 0x0; | |
| 1461 | ||
| 1462 | /// VM read permission | |
| 1463 | pub const VM_PROT_READ: vm_prot_t = 0x1; | |
| 1464 | ||
| 1465 | /// VM write permission | |
| 1466 | pub const VM_PROT_WRITE: vm_prot_t = 0x2; | |
| 1467 | ||
| 1468 | /// VM execute permission | |
| 1469 | pub const VM_PROT_EXECUTE: vm_prot_t = 0x4; | |
| 1470 | ||
| 1471 | /// When a caller finds that they cannot obtain write permission on a | |
| 1472 | /// mapped entry, the following flag can be used. The entry will be | |
| 1473 | /// made "needs copy" effectively copying the object (using COW), | |
| 1474 | /// and write permission will be added to the maximum protections for | |
| 1475 | /// the associated entry. | |
| 1476 | pub const VM_PROT_COPY: vm_prot_t = 0x10; | |
| 1477 | ||
| 1478 | 1457 | // The following are used to encode rebasing information |
| 1479 | 1458 | pub const REBASE_TYPE_POINTER: u8 = 1; |
| 1480 | 1459 | pub const REBASE_TYPE_TEXT_ABSOLUTE32: u8 = 2; |
| ... | ... | @@ -2169,8 +2148,8 @@ test "read-write segment command" { |
| 2169 | 2148 | .vmaddr = 4294967296, |
| 2170 | 2149 | .vmsize = 294912, |
| 2171 | 2150 | .filesize = 294912, |
| 2172 | .maxprot = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, | |
| 2173 | .initprot = VM_PROT_EXECUTE | VM_PROT_READ, | |
| 2151 | .maxprot = os.PROT.READ | os.PROT.WRITE | os.PROT.EXEC, | |
| 2152 | .initprot = os.PROT.EXEC | os.PROT.READ, | |
| 2174 | 2153 | .nsects = 1, |
| 2175 | 2154 | }, |
| 2176 | 2155 | }; |
lib/std/os.zig+1-1| ... | ... | @@ -29,7 +29,7 @@ const Allocator = std.mem.Allocator; |
| 29 | 29 | const Preopen = std.fs.wasi.Preopen; |
| 30 | 30 | const PreopenList = std.fs.wasi.PreopenList; |
| 31 | 31 | |
| 32 | pub const darwin = std.c; | |
| 32 | pub const darwin = @import("os/darwin.zig"); | |
| 33 | 33 | pub const dragonfly = std.c; |
| 34 | 34 | pub const freebsd = std.c; |
| 35 | 35 | pub const haiku = std.c; |
lib/std/os/darwin.zig created+216| ... | ... | @@ -0,0 +1,216 @@ |
| 1 | const std = @import("std"); | |
| 2 | const log = std.log; | |
| 3 | const mem = std.mem; | |
| 4 | const os = @This(); | |
| 5 | ||
| 6 | pub usingnamespace @import("../c.zig"); | |
| 7 | ||
| 8 | pub const MachError = error{ | |
| 9 | /// Not enough permissions held to perform the requested kernel | |
| 10 | /// call. | |
| 11 | PermissionDenied, | |
| 12 | /// Kernel returned an unhandled and unexpected error code. | |
| 13 | /// This is a catch-all for any yet unobserved kernel response | |
| 14 | /// to some Mach message. | |
| 15 | Unexpected, | |
| 16 | }; | |
| 17 | ||
| 18 | pub const MachTask = struct { | |
| 19 | port: os.mach_port_name_t, | |
| 20 | ||
| 21 | pub fn isValid(self: MachTask) bool { | |
| 22 | return self.port != 0; | |
| 23 | } | |
| 24 | ||
| 25 | pub fn getCurrProtection(task: MachTask, address: u64, len: usize) MachError!os.vm_prot_t { | |
| 26 | var base_addr = address; | |
| 27 | var base_len: os.mach_vm_size_t = if (len == 1) 2 else len; | |
| 28 | var objname: os.mach_port_t = undefined; | |
| 29 | var info: os.vm_region_submap_info_64 = undefined; | |
| 30 | var count: os.mach_msg_type_number_t = os.VM_REGION_SUBMAP_SHORT_INFO_COUNT_64; | |
| 31 | switch (os.getKernError(os.mach_vm_region( | |
| 32 | task.port, | |
| 33 | &base_addr, | |
| 34 | &base_len, | |
| 35 | os.VM_REGION_BASIC_INFO_64, | |
| 36 | @ptrCast(os.vm_region_info_t, &info), | |
| 37 | &count, | |
| 38 | &objname, | |
| 39 | ))) { | |
| 40 | .SUCCESS => return info.protection, | |
| 41 | .FAILURE => return error.PermissionDenied, | |
| 42 | else => |err| { | |
| 43 | log.err("mach_vm_region kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 44 | return error.Unexpected; | |
| 45 | }, | |
| 46 | } | |
| 47 | } | |
| 48 | ||
| 49 | pub fn setMaxProtection(task: MachTask, address: u64, len: usize, prot: os.vm_prot_t) MachError!void { | |
| 50 | return task.setProtectionImpl(address, len, true, prot); | |
| 51 | } | |
| 52 | ||
| 53 | pub fn setCurrProtection(task: MachTask, address: u64, len: usize, prot: os.vm_prot_t) MachError!void { | |
| 54 | return task.setProtectionImpl(address, len, false, prot); | |
| 55 | } | |
| 56 | ||
| 57 | fn setProtectionImpl(task: MachTask, address: u64, len: usize, set_max: bool, prot: os.vm_prot_t) MachError!void { | |
| 58 | switch (os.getKernError(os.mach_vm_protect(task.port, address, len, @boolToInt(set_max), prot))) { | |
| 59 | .SUCCESS => return, | |
| 60 | .FAILURE => return error.PermissionDenied, | |
| 61 | else => |err| { | |
| 62 | log.err("mach_vm_protect kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 63 | return error.Unexpected; | |
| 64 | }, | |
| 65 | } | |
| 66 | } | |
| 67 | ||
| 68 | /// Will write to VM even if current protection attributes specifically prohibit | |
| 69 | /// us from doing so, by temporarily setting protection level to a level with VM_PROT_COPY | |
| 70 | /// variant, and resetting after a successful or unsuccessful write. | |
| 71 | pub fn writeMemProtected(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 72 | const curr_prot = try task.getCurrProtection(address, buf.len); | |
| 73 | try task.setCurrProtection( | |
| 74 | address, | |
| 75 | buf.len, | |
| 76 | os.PROT.READ | os.PROT.WRITE | os.PROT.COPY, | |
| 77 | ); | |
| 78 | defer { | |
| 79 | task.setCurrProtection(address, buf.len, curr_prot) catch {}; | |
| 80 | } | |
| 81 | return task.writeMem(address, buf, arch); | |
| 82 | } | |
| 83 | ||
| 84 | pub fn writeMem(task: MachTask, address: u64, buf: []const u8, arch: std.Target.Cpu.Arch) MachError!usize { | |
| 85 | const count = buf.len; | |
| 86 | var total_written: usize = 0; | |
| 87 | var curr_addr = address; | |
| 88 | const page_size = try getPageSize(task); // TODO we probably can assume value here | |
| 89 | var out_buf = buf[0..]; | |
| 90 | ||
| 91 | while (total_written < count) { | |
| 92 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_written); | |
| 93 | switch (os.getKernError(os.mach_vm_write( | |
| 94 | task.port, | |
| 95 | curr_addr, | |
| 96 | @ptrToInt(out_buf.ptr), | |
| 97 | @intCast(os.mach_msg_type_number_t, curr_size), | |
| 98 | ))) { | |
| 99 | .SUCCESS => {}, | |
| 100 | .FAILURE => return error.PermissionDenied, | |
| 101 | else => |err| { | |
| 102 | log.err("mach_vm_write kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 103 | return error.Unexpected; | |
| 104 | }, | |
| 105 | } | |
| 106 | ||
| 107 | switch (arch) { | |
| 108 | .aarch64 => { | |
| 109 | var mattr_value: os.vm_machine_attribute_val_t = os.MATTR_VAL_CACHE_FLUSH; | |
| 110 | switch (os.getKernError(os.vm_machine_attribute( | |
| 111 | task.port, | |
| 112 | curr_addr, | |
| 113 | curr_size, | |
| 114 | os.MATTR_CACHE, | |
| 115 | &mattr_value, | |
| 116 | ))) { | |
| 117 | .SUCCESS => {}, | |
| 118 | .FAILURE => return error.PermissionDenied, | |
| 119 | else => |err| { | |
| 120 | log.err("vm_machine_attribute kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 121 | return error.Unexpected; | |
| 122 | }, | |
| 123 | } | |
| 124 | }, | |
| 125 | .x86_64 => {}, | |
| 126 | else => unreachable, | |
| 127 | } | |
| 128 | ||
| 129 | out_buf = out_buf[curr_size..]; | |
| 130 | total_written += curr_size; | |
| 131 | curr_addr += curr_size; | |
| 132 | } | |
| 133 | ||
| 134 | return total_written; | |
| 135 | } | |
| 136 | ||
| 137 | pub fn readMem(task: MachTask, address: u64, buf: []u8) MachError!usize { | |
| 138 | const count = buf.len; | |
| 139 | var total_read: usize = 0; | |
| 140 | var curr_addr = address; | |
| 141 | const page_size = try getPageSize(task); // TODO we probably can assume value here | |
| 142 | var out_buf = buf[0..]; | |
| 143 | ||
| 144 | while (total_read < count) { | |
| 145 | const curr_size = maxBytesLeftInPage(page_size, curr_addr, count - total_read); | |
| 146 | var curr_bytes_read: os.mach_msg_type_number_t = 0; | |
| 147 | var vm_memory: os.vm_offset_t = undefined; | |
| 148 | switch (os.getKernError(os.mach_vm_read(task.port, curr_addr, curr_size, &vm_memory, &curr_bytes_read))) { | |
| 149 | .SUCCESS => {}, | |
| 150 | .FAILURE => return error.PermissionDenied, | |
| 151 | else => |err| { | |
| 152 | log.err("mach_vm_read kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 153 | return error.Unexpected; | |
| 154 | }, | |
| 155 | } | |
| 156 | ||
| 157 | @memcpy(out_buf[0..].ptr, @intToPtr([*]const u8, vm_memory), curr_bytes_read); | |
| 158 | _ = os.vm_deallocate(os.mach_task_self(), vm_memory, curr_bytes_read); | |
| 159 | ||
| 160 | out_buf = out_buf[curr_bytes_read..]; | |
| 161 | curr_addr += curr_bytes_read; | |
| 162 | total_read += curr_bytes_read; | |
| 163 | } | |
| 164 | ||
| 165 | return total_read; | |
| 166 | } | |
| 167 | ||
| 168 | fn maxBytesLeftInPage(page_size: usize, address: u64, count: usize) usize { | |
| 169 | var left = count; | |
| 170 | if (page_size > 0) { | |
| 171 | const page_offset = address % page_size; | |
| 172 | const bytes_left_in_page = page_size - page_offset; | |
| 173 | if (count > bytes_left_in_page) { | |
| 174 | left = bytes_left_in_page; | |
| 175 | } | |
| 176 | } | |
| 177 | return left; | |
| 178 | } | |
| 179 | ||
| 180 | fn getPageSize(task: MachTask) MachError!usize { | |
| 181 | if (task.isValid()) { | |
| 182 | var info_count = os.TASK_VM_INFO_COUNT; | |
| 183 | var vm_info: os.task_vm_info_data_t = undefined; | |
| 184 | switch (os.getKernError(os.task_info( | |
| 185 | task.port, | |
| 186 | os.TASK_VM_INFO, | |
| 187 | @ptrCast(os.task_info_t, &vm_info), | |
| 188 | &info_count, | |
| 189 | ))) { | |
| 190 | .SUCCESS => return @intCast(usize, vm_info.page_size), | |
| 191 | else => {}, | |
| 192 | } | |
| 193 | } | |
| 194 | var page_size: os.vm_size_t = undefined; | |
| 195 | switch (os.getKernError(os._host_page_size(os.mach_host_self(), &page_size))) { | |
| 196 | .SUCCESS => return page_size, | |
| 197 | else => |err| { | |
| 198 | log.err("_host_page_size kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 199 | return error.Unexpected; | |
| 200 | }, | |
| 201 | } | |
| 202 | } | |
| 203 | }; | |
| 204 | ||
| 205 | pub fn machTaskForPid(pid: os.pid_t) MachError!MachTask { | |
| 206 | var port: os.mach_port_name_t = undefined; | |
| 207 | switch (os.getKernError(os.task_for_pid(os.mach_task_self(), pid, &port))) { | |
| 208 | .SUCCESS => {}, | |
| 209 | .FAILURE => return error.PermissionDenied, | |
| 210 | else => |err| { | |
| 211 | log.err("task_for_pid kernel call failed with error code: {s}", .{@tagName(err)}); | |
| 212 | return error.Unexpected; | |
| 213 | }, | |
| 214 | } | |
| 215 | return MachTask{ .port = port }; | |
| 216 | } |
src/link/MachO.zig+9-8| ... | ... | @@ -4,6 +4,7 @@ const std = @import("std"); |
| 4 | 4 | const build_options = @import("build_options"); |
| 5 | 5 | const builtin = @import("builtin"); |
| 6 | 6 | const assert = std.debug.assert; |
| 7 | const darwin = std.os.darwin; | |
| 7 | 8 | const fmt = std.fmt; |
| 8 | 9 | const fs = std.fs; |
| 9 | 10 | const log = std.log.scoped(.link); |
| ... | ... | @@ -4382,8 +4383,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4382 | 4383 | .vmaddr = pagezero_vmsize, |
| 4383 | 4384 | .vmsize = needed_size, |
| 4384 | 4385 | .filesize = needed_size, |
| 4385 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE, | |
| 4386 | .initprot = macho.VM_PROT_READ | macho.VM_PROT_EXECUTE, | |
| 4386 | .maxprot = darwin.PROT.READ | darwin.PROT.EXEC, | |
| 4387 | .initprot = darwin.PROT.READ | darwin.PROT.EXEC, | |
| 4387 | 4388 | }, |
| 4388 | 4389 | }, |
| 4389 | 4390 | }); |
| ... | ... | @@ -4487,8 +4488,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4487 | 4488 | .vmsize = needed_size, |
| 4488 | 4489 | .fileoff = fileoff, |
| 4489 | 4490 | .filesize = needed_size, |
| 4490 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, | |
| 4491 | .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, | |
| 4491 | .maxprot = darwin.PROT.READ | darwin.PROT.WRITE, | |
| 4492 | .initprot = darwin.PROT.READ | darwin.PROT.WRITE, | |
| 4492 | 4493 | }, |
| 4493 | 4494 | }, |
| 4494 | 4495 | }); |
| ... | ... | @@ -4536,8 +4537,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4536 | 4537 | .vmsize = needed_size, |
| 4537 | 4538 | .fileoff = fileoff, |
| 4538 | 4539 | .filesize = needed_size, |
| 4539 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, | |
| 4540 | .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, | |
| 4540 | .maxprot = darwin.PROT.READ | darwin.PROT.WRITE, | |
| 4541 | .initprot = darwin.PROT.READ | darwin.PROT.WRITE, | |
| 4541 | 4542 | }, |
| 4542 | 4543 | }, |
| 4543 | 4544 | }); |
| ... | ... | @@ -4645,8 +4646,8 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4645 | 4646 | .segname = makeStaticString("__LINKEDIT"), |
| 4646 | 4647 | .vmaddr = vmaddr, |
| 4647 | 4648 | .fileoff = fileoff, |
| 4648 | .maxprot = macho.VM_PROT_READ, | |
| 4649 | .initprot = macho.VM_PROT_READ, | |
| 4649 | .maxprot = darwin.PROT.READ, | |
| 4650 | .initprot = darwin.PROT.READ, | |
| 4650 | 4651 | }, |
| 4651 | 4652 | }, |
| 4652 | 4653 | }); |