| author | |
| committer | |
| log | f887b0251822f75dc4a3e24ca5337cb681c1eb1f |
| tree | 3746b4716751f53029dd73f4f2f541ef48de138c |
| parent | 31979b10065b6ab1d00413648daea5907639819e |
| parent | d0fbfd3c9f419ceb7112d06d4a3500e9c13f6044 |
| signature |
Plan 9: more standard library support9 files changed, 471 insertions(+), 119 deletions(-)
doc/langref.html.in+2-1| ... | ... | @@ -8467,9 +8467,10 @@ export fn @"A function name that is a complete sentence."() void {} |
| 8467 | 8467 | {#header_close#} |
| 8468 | 8468 | |
| 8469 | 8469 | {#header_open|@extern#} |
| 8470 | <pre>{#syntax#}@extern(T: type, comptime options: std.builtin.ExternOptions) *T{#endsyntax#}</pre> | |
| 8470 | <pre>{#syntax#}@extern(T: type, comptime options: std.builtin.ExternOptions) T{#endsyntax#}</pre> | |
| 8471 | 8471 | <p> |
| 8472 | 8472 | Creates a reference to an external symbol in the output object file. |
| 8473 | T must be a pointer type. | |
| 8473 | 8474 | </p> |
| 8474 | 8475 | {#see_also|@export#} |
| 8475 | 8476 | {#header_close#} |
lib/std/fs.zig+6-4| ... | ... | @@ -39,7 +39,7 @@ pub const Watch = @import("fs/watch.zig").Watch; |
| 39 | 39 | /// fit into a UTF-8 encoded array of this length. |
| 40 | 40 | /// The byte count includes room for a null sentinel byte. |
| 41 | 41 | pub const MAX_PATH_BYTES = switch (builtin.os.tag) { |
| 42 | .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris => os.PATH_MAX, | |
| 42 | .linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .plan9 => os.PATH_MAX, | |
| 43 | 43 | // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. |
| 44 | 44 | // If it would require 4 UTF-8 bytes, then there would be a surrogate |
| 45 | 45 | // pair in the UTF-16LE, and we (over)account 3 bytes for it that way. |
| ... | ... | @@ -1160,7 +1160,9 @@ pub const Dir = struct { |
| 1160 | 1160 | return self.openFileW(path_w.span(), flags); |
| 1161 | 1161 | } |
| 1162 | 1162 | |
| 1163 | var os_flags: u32 = os.O.CLOEXEC; | |
| 1163 | var os_flags: u32 = 0; | |
| 1164 | if (@hasDecl(os.O, "CLOEXEC")) os_flags = os.O.CLOEXEC; | |
| 1165 | ||
| 1164 | 1166 | // Use the O locking flags if the os supports them to acquire the lock |
| 1165 | 1167 | // atomically. |
| 1166 | 1168 | const has_flock_open_flags = @hasDecl(os.O, "EXLOCK"); |
| ... | ... | @@ -1180,7 +1182,7 @@ pub const Dir = struct { |
| 1180 | 1182 | if (@hasDecl(os.O, "LARGEFILE")) { |
| 1181 | 1183 | os_flags |= os.O.LARGEFILE; |
| 1182 | 1184 | } |
| 1183 | if (!flags.allow_ctty) { | |
| 1185 | if (@hasDecl(os.O, "NOCTTY") and !flags.allow_ctty) { | |
| 1184 | 1186 | os_flags |= os.O.NOCTTY; |
| 1185 | 1187 | } |
| 1186 | 1188 | os_flags |= switch (flags.mode) { |
| ... | ... | @@ -1196,7 +1198,7 @@ pub const Dir = struct { |
| 1196 | 1198 | |
| 1197 | 1199 | // WASI doesn't have os.flock so we intetinally check OS prior to the inner if block |
| 1198 | 1200 | // since it is not compiltime-known and we need to avoid undefined symbol in Wasm. |
| 1199 | if (builtin.target.os.tag != .wasi) { | |
| 1201 | if (@hasDecl(os.system, "LOCK") and builtin.target.os.tag != .wasi) { | |
| 1200 | 1202 | if (!has_flock_open_flags and flags.lock != .none) { |
| 1201 | 1203 | // TODO: integrate async I/O |
| 1202 | 1204 | const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0); |
lib/std/heap.zig+6| ... | ... | @@ -21,6 +21,7 @@ pub const WasmAllocator = @import("heap/WasmAllocator.zig"); |
| 21 | 21 | pub const WasmPageAllocator = @import("heap/WasmPageAllocator.zig"); |
| 22 | 22 | pub const PageAllocator = @import("heap/PageAllocator.zig"); |
| 23 | 23 | pub const ThreadSafeAllocator = @import("heap/ThreadSafeAllocator.zig"); |
| 24 | pub const SbrkAllocator = @import("heap/sbrk_allocator.zig").SbrkAllocator; | |
| 24 | 25 | |
| 25 | 26 | const memory_pool = @import("heap/memory_pool.zig"); |
| 26 | 27 | pub const MemoryPool = memory_pool.MemoryPool; |
| ... | ... | @@ -228,6 +229,11 @@ pub const page_allocator = if (builtin.target.isWasm()) |
| 228 | 229 | .ptr = undefined, |
| 229 | 230 | .vtable = &WasmPageAllocator.vtable, |
| 230 | 231 | } |
| 232 | else if (builtin.target.os.tag == .plan9) | |
| 233 | Allocator{ | |
| 234 | .ptr = undefined, | |
| 235 | .vtable = &SbrkAllocator(std.os.plan9.sbrk).vtable, | |
| 236 | } | |
| 231 | 237 | else if (builtin.target.os.tag == .freestanding) |
| 232 | 238 | root.os.heap.page_allocator |
| 233 | 239 | else |
lib/std/heap/sbrk_allocator.zig created+161| ... | ... | @@ -0,0 +1,161 @@ |
| 1 | const std = @import("../std.zig"); | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const math = std.math; | |
| 4 | const Allocator = std.mem.Allocator; | |
| 5 | const mem = std.mem; | |
| 6 | const assert = std.debug.assert; | |
| 7 | ||
| 8 | pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type { | |
| 9 | return struct { | |
| 10 | pub const vtable = Allocator.VTable{ | |
| 11 | .alloc = alloc, | |
| 12 | .resize = resize, | |
| 13 | .free = free, | |
| 14 | }; | |
| 15 | ||
| 16 | pub const Error = Allocator.Error; | |
| 17 | ||
| 18 | lock: std.Thread.Mutex = .{}, | |
| 19 | ||
| 20 | const max_usize = math.maxInt(usize); | |
| 21 | const ushift = math.Log2Int(usize); | |
| 22 | const bigpage_size = 64 * 1024; | |
| 23 | const pages_per_bigpage = bigpage_size / mem.page_size; | |
| 24 | const bigpage_count = max_usize / bigpage_size; | |
| 25 | ||
| 26 | /// Because of storing free list pointers, the minimum size class is 3. | |
| 27 | const min_class = math.log2(math.ceilPowerOfTwoAssert(usize, 1 + @sizeOf(usize))); | |
| 28 | const size_class_count = math.log2(bigpage_size) - min_class; | |
| 29 | /// 0 - 1 bigpage | |
| 30 | /// 1 - 2 bigpages | |
| 31 | /// 2 - 4 bigpages | |
| 32 | /// etc. | |
| 33 | const big_size_class_count = math.log2(bigpage_count); | |
| 34 | ||
| 35 | var next_addrs = [1]usize{0} ** size_class_count; | |
| 36 | /// For each size class, points to the freed pointer. | |
| 37 | var frees = [1]usize{0} ** size_class_count; | |
| 38 | /// For each big size class, points to the freed pointer. | |
| 39 | var big_frees = [1]usize{0} ** big_size_class_count; | |
| 40 | ||
| 41 | // TODO don't do the naive locking strategy | |
| 42 | var lock: std.Thread.Mutex = .{}; | |
| 43 | fn alloc(ctx: *anyopaque, len: usize, log2_align: u8, return_address: usize) ?[*]u8 { | |
| 44 | _ = ctx; | |
| 45 | _ = return_address; | |
| 46 | lock.lock(); | |
| 47 | defer lock.unlock(); | |
| 48 | // Make room for the freelist next pointer. | |
| 49 | const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align)); | |
| 50 | const actual_len = @max(len +| @sizeOf(usize), alignment); | |
| 51 | const slot_size = math.ceilPowerOfTwo(usize, actual_len) catch return null; | |
| 52 | const class = math.log2(slot_size) - min_class; | |
| 53 | if (class < size_class_count) { | |
| 54 | const addr = a: { | |
| 55 | const top_free_ptr = frees[class]; | |
| 56 | if (top_free_ptr != 0) { | |
| 57 | const node = @as(*usize, @ptrFromInt(top_free_ptr + (slot_size - @sizeOf(usize)))); | |
| 58 | frees[class] = node.*; | |
| 59 | break :a top_free_ptr; | |
| 60 | } | |
| 61 | ||
| 62 | const next_addr = next_addrs[class]; | |
| 63 | if (next_addr % mem.page_size == 0) { | |
| 64 | const addr = allocBigPages(1); | |
| 65 | if (addr == 0) return null; | |
| 66 | //std.debug.print("allocated fresh slot_size={d} class={d} addr=0x{x}\n", .{ | |
| 67 | // slot_size, class, addr, | |
| 68 | //}); | |
| 69 | next_addrs[class] = addr + slot_size; | |
| 70 | break :a addr; | |
| 71 | } else { | |
| 72 | next_addrs[class] = next_addr + slot_size; | |
| 73 | break :a next_addr; | |
| 74 | } | |
| 75 | }; | |
| 76 | return @as([*]u8, @ptrFromInt(addr)); | |
| 77 | } | |
| 78 | const bigpages_needed = bigPagesNeeded(actual_len); | |
| 79 | const addr = allocBigPages(bigpages_needed); | |
| 80 | return @as([*]u8, @ptrFromInt(addr)); | |
| 81 | } | |
| 82 | ||
| 83 | fn resize( | |
| 84 | ctx: *anyopaque, | |
| 85 | buf: []u8, | |
| 86 | log2_buf_align: u8, | |
| 87 | new_len: usize, | |
| 88 | return_address: usize, | |
| 89 | ) bool { | |
| 90 | _ = ctx; | |
| 91 | _ = return_address; | |
| 92 | lock.lock(); | |
| 93 | defer lock.unlock(); | |
| 94 | // We don't want to move anything from one size class to another, but we | |
| 95 | // can recover bytes in between powers of two. | |
| 96 | const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align)); | |
| 97 | const old_actual_len = @max(buf.len + @sizeOf(usize), buf_align); | |
| 98 | const new_actual_len = @max(new_len +| @sizeOf(usize), buf_align); | |
| 99 | const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_actual_len); | |
| 100 | const old_small_class = math.log2(old_small_slot_size) - min_class; | |
| 101 | if (old_small_class < size_class_count) { | |
| 102 | const new_small_slot_size = math.ceilPowerOfTwo(usize, new_actual_len) catch return false; | |
| 103 | return old_small_slot_size == new_small_slot_size; | |
| 104 | } else { | |
| 105 | const old_bigpages_needed = bigPagesNeeded(old_actual_len); | |
| 106 | const old_big_slot_pages = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed); | |
| 107 | const new_bigpages_needed = bigPagesNeeded(new_actual_len); | |
| 108 | const new_big_slot_pages = math.ceilPowerOfTwo(usize, new_bigpages_needed) catch return false; | |
| 109 | return old_big_slot_pages == new_big_slot_pages; | |
| 110 | } | |
| 111 | } | |
| 112 | ||
| 113 | fn free( | |
| 114 | ctx: *anyopaque, | |
| 115 | buf: []u8, | |
| 116 | log2_buf_align: u8, | |
| 117 | return_address: usize, | |
| 118 | ) void { | |
| 119 | _ = ctx; | |
| 120 | _ = return_address; | |
| 121 | lock.lock(); | |
| 122 | defer lock.unlock(); | |
| 123 | const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align)); | |
| 124 | const actual_len = @max(buf.len + @sizeOf(usize), buf_align); | |
| 125 | const slot_size = math.ceilPowerOfTwoAssert(usize, actual_len); | |
| 126 | const class = math.log2(slot_size) - min_class; | |
| 127 | const addr = @intFromPtr(buf.ptr); | |
| 128 | if (class < size_class_count) { | |
| 129 | const node = @as(*usize, @ptrFromInt(addr + (slot_size - @sizeOf(usize)))); | |
| 130 | node.* = frees[class]; | |
| 131 | frees[class] = addr; | |
| 132 | } else { | |
| 133 | const bigpages_needed = bigPagesNeeded(actual_len); | |
| 134 | const pow2_pages = math.ceilPowerOfTwoAssert(usize, bigpages_needed); | |
| 135 | const big_slot_size_bytes = pow2_pages * bigpage_size; | |
| 136 | const node = @as(*usize, @ptrFromInt(addr + (big_slot_size_bytes - @sizeOf(usize)))); | |
| 137 | const big_class = math.log2(pow2_pages); | |
| 138 | node.* = big_frees[big_class]; | |
| 139 | big_frees[big_class] = addr; | |
| 140 | } | |
| 141 | } | |
| 142 | ||
| 143 | inline fn bigPagesNeeded(byte_count: usize) usize { | |
| 144 | return (byte_count + (bigpage_size + (@sizeOf(usize) - 1))) / bigpage_size; | |
| 145 | } | |
| 146 | ||
| 147 | fn allocBigPages(n: usize) usize { | |
| 148 | const pow2_pages = math.ceilPowerOfTwoAssert(usize, n); | |
| 149 | const slot_size_bytes = pow2_pages * bigpage_size; | |
| 150 | const class = math.log2(pow2_pages); | |
| 151 | ||
| 152 | const top_free_ptr = big_frees[class]; | |
| 153 | if (top_free_ptr != 0) { | |
| 154 | const node = @as(*usize, @ptrFromInt(top_free_ptr + (slot_size_bytes - @sizeOf(usize)))); | |
| 155 | big_frees[class] = node.*; | |
| 156 | return top_free_ptr; | |
| 157 | } | |
| 158 | return sbrk(pow2_pages * pages_per_bigpage * mem.page_size); | |
| 159 | } | |
| 160 | }; | |
| 161 | } |
lib/std/os/plan9.zig+132-20| ... | ... | @@ -1,6 +1,12 @@ |
| 1 | 1 | const std = @import("../std.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | pub const fd_t = i32; | |
| 5 | ||
| 6 | pub const STDIN_FILENO = 0; | |
| 7 | pub const STDOUT_FILENO = 1; | |
| 8 | pub const STDERR_FILENO = 2; | |
| 9 | pub const PATH_MAX = 1023; | |
| 4 | 10 | pub const syscall_bits = switch (builtin.cpu.arch) { |
| 5 | 11 | .x86_64 => @import("plan9/x86_64.zig"), |
| 6 | 12 | else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"), |
| ... | ... | @@ -12,6 +18,43 @@ pub fn getErrno(r: usize) E { |
| 12 | 18 | const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0; |
| 13 | 19 | return @as(E, @enumFromInt(int)); |
| 14 | 20 | } |
| 21 | // The max bytes that can be in the errstr buff | |
| 22 | pub const ERRMAX = 128; | |
| 23 | var errstr_buf: [ERRMAX]u8 = undefined; | |
| 24 | /// Gets whatever the last errstr was | |
| 25 | pub fn errstr() []const u8 { | |
| 26 | _ = syscall_bits.syscall2(.ERRSTR, @intFromPtr(&errstr_buf), ERRMAX); | |
| 27 | return std.mem.span(@as([*:0]u8, @ptrCast(&errstr_buf))); | |
| 28 | } | |
| 29 | pub const Plink = anyopaque; | |
| 30 | pub const Tos = extern struct { | |
| 31 | /// Per process profiling | |
| 32 | prof: extern struct { | |
| 33 | /// known to be 0(ptr) | |
| 34 | pp: *Plink, | |
| 35 | /// known to be 4(ptr) | |
| 36 | next: *Plink, | |
| 37 | last: *Plink, | |
| 38 | first: *Plink, | |
| 39 | pid: u32, | |
| 40 | what: u32, | |
| 41 | }, | |
| 42 | /// cycle clock frequency if there is one, 0 otherwise | |
| 43 | cyclefreq: u64, | |
| 44 | /// cycles spent in kernel | |
| 45 | kcycles: i64, | |
| 46 | /// cycles spent in process (kernel + user) | |
| 47 | pcycles: i64, | |
| 48 | /// might as well put the pid here | |
| 49 | pid: u32, | |
| 50 | clock: u32, | |
| 51 | // top of stack is here | |
| 52 | }; | |
| 53 | ||
| 54 | pub var tos: *Tos = undefined; // set in start.zig | |
| 55 | pub fn getpid() u32 { | |
| 56 | return tos.pid; | |
| 57 | } | |
| 15 | 58 | pub const SIG = struct { |
| 16 | 59 | /// hangup |
| 17 | 60 | pub const HUP = 1; |
| ... | ... | @@ -57,7 +100,8 @@ pub const SIG = struct { |
| 57 | 100 | }; |
| 58 | 101 | pub const sigset_t = c_long; |
| 59 | 102 | pub const empty_sigset = 0; |
| 60 | pub const siginfo_t = c_long; // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible. | |
| 103 | pub const siginfo_t = c_long; | |
| 104 | // TODO plan9 doesn't have sigaction_fn. Sigaction is not a union, but we incude it here to be compatible. | |
| 61 | 105 | pub const Sigaction = extern struct { |
| 62 | 106 | pub const handler_fn = *const fn (c_int) callconv(.C) void; |
| 63 | 107 | pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void; |
| ... | ... | @@ -69,6 +113,9 @@ pub const Sigaction = extern struct { |
| 69 | 113 | mask: sigset_t, |
| 70 | 114 | flags: c_int, |
| 71 | 115 | }; |
| 116 | pub const AT = struct { | |
| 117 | pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9 | |
| 118 | }; | |
| 72 | 119 | // TODO implement sigaction |
| 73 | 120 | // right now it is just a shim to allow using start.zig code |
| 74 | 121 | pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize { |
| ... | ... | @@ -132,20 +179,48 @@ pub const SYS = enum(usize) { |
| 132 | 179 | _NSEC = 53, |
| 133 | 180 | }; |
| 134 | 181 | |
| 135 | pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize { | |
| 136 | return syscall_bits.syscall4(.PWRITE, fd, @intFromPtr(buf), count, offset); | |
| 182 | pub fn write(fd: i32, buf: [*]const u8, count: usize) usize { | |
| 183 | return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1))); | |
| 184 | } | |
| 185 | pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize { | |
| 186 | return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset)); | |
| 187 | } | |
| 188 | ||
| 189 | pub fn read(fd: i32, buf: [*]const u8, count: usize) usize { | |
| 190 | return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1))); | |
| 191 | } | |
| 192 | pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize { | |
| 193 | return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset)); | |
| 194 | } | |
| 195 | ||
| 196 | pub fn open(path: [*:0]const u8, flags: u32) usize { | |
| 197 | return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, flags))); | |
| 137 | 198 | } |
| 138 | 199 | |
| 139 | pub fn pread(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize { | |
| 140 | return syscall_bits.syscall4(.PREAD, fd, @intFromPtr(buf), count, offset); | |
| 200 | pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, _: mode_t) usize { | |
| 201 | // we skip perms because only create supports perms | |
| 202 | if (dirfd == AT.FDCWD) { // openat(AT_FDCWD, ...) == open(...) | |
| 203 | return open(path, flags); | |
| 204 | } | |
| 205 | var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; | |
| 206 | var total_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined; | |
| 207 | const rc = fd2path(dirfd, &dir_path_buf, std.fs.MAX_PATH_BYTES); | |
| 208 | if (rc != 0) return rc; | |
| 209 | var fba = std.heap.FixedBufferAllocator.init(&total_path_buf); | |
| 210 | var alloc = fba.allocator(); | |
| 211 | const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf))); | |
| 212 | const total_path = std.fs.path.join(alloc, &.{ dir_path, std.mem.span(path) }) catch unreachable; // the allocation shouldn't fail because it should not exceed MAX_PATH_BYTES | |
| 213 | fba.reset(); | |
| 214 | const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed MAX_PATH_BYTES + 1 | |
| 215 | return open(total_path_z.ptr, flags); | |
| 141 | 216 | } |
| 142 | 217 | |
| 143 | pub fn open(path: [*:0]const u8, omode: OpenMode) usize { | |
| 144 | return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @intFromEnum(omode)); | |
| 218 | pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize { | |
| 219 | return syscall_bits.syscall3(.FD2PATH, @bitCast(@as(isize, fd)), @intFromPtr(buf), nbuf); | |
| 145 | 220 | } |
| 146 | 221 | |
| 147 | pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize { | |
| 148 | return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @intFromEnum(omode), perms); | |
| 222 | pub fn create(path: [*:0]const u8, omode: mode_t, perms: usize) usize { | |
| 223 | return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @bitCast(@as(isize, omode)), perms); | |
| 149 | 224 | } |
| 150 | 225 | |
| 151 | 226 | pub fn exit(status: u8) noreturn { |
| ... | ... | @@ -163,16 +238,53 @@ pub fn exits(status: ?[*:0]const u8) noreturn { |
| 163 | 238 | unreachable; |
| 164 | 239 | } |
| 165 | 240 | |
| 166 | pub fn close(fd: usize) usize { | |
| 167 | return syscall_bits.syscall1(.CLOSE, fd); | |
| 241 | pub fn close(fd: i32) usize { | |
| 242 | return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd))); | |
| 168 | 243 | } |
| 169 | pub const OpenMode = enum(usize) { | |
| 170 | OREAD = 0, //* open for read | |
| 171 | OWRITE = 1, //* write | |
| 172 | ORDWR = 2, //* read and write | |
| 173 | OEXEC = 3, //* execute, == read but check execute permission | |
| 174 | OTRUNC = 16, //* or'ed in (except for exec), truncate file first | |
| 175 | OCEXEC = 32, //* or'ed in (per file descriptor), close on exec | |
| 176 | ORCLOSE = 64, //* or'ed in, remove on close | |
| 177 | OEXCL = 0x1000, //* or'ed in, exclusive create | |
| 244 | pub const mode_t = i32; | |
| 245 | pub const O = struct { | |
| 246 | pub const READ = 0; // open for read | |
| 247 | pub const RDONLY = 0; | |
| 248 | pub const WRITE = 1; // write | |
| 249 | pub const WRONLY = 1; | |
| 250 | pub const RDWR = 2; // read and write | |
| 251 | pub const EXEC = 3; // execute, == read but check execute permission | |
| 252 | pub const TRUNC = 16; // or'ed in (except for exec), truncate file first | |
| 253 | pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec | |
| 254 | pub const RCLOSE = 64; // or'ed in, remove on close | |
| 255 | pub const EXCL = 0x1000; // or'ed in, exclusive create | |
| 178 | 256 | }; |
| 257 | ||
| 258 | pub const ExecData = struct { | |
| 259 | pub extern const etext: anyopaque; | |
| 260 | pub extern const edata: anyopaque; | |
| 261 | pub extern const end: anyopaque; | |
| 262 | }; | |
| 263 | ||
| 264 | /// Brk sets the system's idea of the lowest bss location not | |
| 265 | /// used by the program (called the break) to addr rounded up to | |
| 266 | /// the next multiple of 8 bytes. Locations not less than addr | |
| 267 | /// and below the stack pointer may cause a memory violation if | |
| 268 | /// accessed. -9front brk(2) | |
| 269 | pub fn brk_(addr: usize) i32 { | |
| 270 | return @intCast(syscall_bits.syscall1(.BRK_, addr)); | |
| 271 | } | |
| 272 | var bloc: usize = 0; | |
| 273 | var bloc_max: usize = 0; | |
| 274 | ||
| 275 | pub fn sbrk(n: usize) usize { | |
| 276 | if (bloc == 0) { | |
| 277 | // we are at the start | |
| 278 | bloc = @intFromPtr(&ExecData.end); | |
| 279 | bloc_max = @intFromPtr(&ExecData.end); | |
| 280 | } | |
| 281 | var bl = std.mem.alignForward(usize, bloc, std.mem.page_size); | |
| 282 | const n_aligned = std.mem.alignForward(usize, n, std.mem.page_size); | |
| 283 | if (bl + n_aligned > bloc_max) { | |
| 284 | // we need to allocate | |
| 285 | if (brk_(bl + n_aligned) < 0) return 0; | |
| 286 | bloc_max = bl + n_aligned; | |
| 287 | } | |
| 288 | bloc = bloc + n_aligned; | |
| 289 | return bl; | |
| 290 | } |
lib/std/os/plan9/errno.zig+8| ... | ... | @@ -73,4 +73,12 @@ pub const E = enum(u16) { |
| 73 | 73 | // These added in 1003.1b-1993 |
| 74 | 74 | CANCELED = 61, |
| 75 | 75 | INPROGRESS = 62, |
| 76 | ||
| 77 | // We just add these to be compatible with std.os, which uses them, | |
| 78 | // They should never get used. | |
| 79 | DQUOT, | |
| 80 | CONNRESET, | |
| 81 | OVERFLOW, | |
| 82 | LOOP, | |
| 83 | TXTBSY, | |
| 76 | 84 | }; |
lib/std/start.zig+8-22| ... | ... | @@ -166,28 +166,7 @@ fn exit2(code: usize) noreturn { |
| 166 | 166 | else => @compileError("TODO"), |
| 167 | 167 | }, |
| 168 | 168 | // exits(0) |
| 169 | .plan9 => switch (builtin.cpu.arch) { | |
| 170 | .x86_64 => { | |
| 171 | asm volatile ( | |
| 172 | \\push $0 | |
| 173 | \\push $0 | |
| 174 | \\syscall | |
| 175 | : | |
| 176 | : [syscall_number] "{rbp}" (8), | |
| 177 | : "rcx", "r11", "memory" | |
| 178 | ); | |
| 179 | }, | |
| 180 | // TODO once we get stack setting with assembly on | |
| 181 | // arm, exit with 0 instead of stack garbage | |
| 182 | .aarch64 => { | |
| 183 | asm volatile ("svc #0" | |
| 184 | : | |
| 185 | : [exit] "{x0}" (0x08), | |
| 186 | : "memory", "cc" | |
| 187 | ); | |
| 188 | }, | |
| 189 | else => @compileError("TODO"), | |
| 190 | }, | |
| 169 | .plan9 => std.os.plan9.exits(null), | |
| 191 | 170 | .windows => { |
| 192 | 171 | ExitProcess(@as(u32, @truncate(code))); |
| 193 | 172 | }, |
| ... | ... | @@ -254,6 +233,13 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv |
| 254 | 233 | } |
| 255 | 234 | |
| 256 | 235 | fn _start() callconv(.Naked) noreturn { |
| 236 | // TODO set Top of Stack on non x86_64-plan9 | |
| 237 | if (native_os == .plan9 and native_arch == .x86_64) { | |
| 238 | // from /sys/src/libc/amd64/main9.s | |
| 239 | std.os.plan9.tos = asm volatile ("" | |
| 240 | : [tos] "={rax}" (-> *std.os.plan9.Tos), | |
| 241 | ); | |
| 242 | } | |
| 257 | 243 | asm volatile (switch (native_arch) { |
| 258 | 244 | .x86_64 => |
| 259 | 245 | \\ xorl %%ebp, %%ebp |
src/arch/x86_64/Emit.zig+1-1| ... | ... | @@ -124,7 +124,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 124 | 124 | .target = symbol.sym_index, // we set sym_index to just be the atom index |
| 125 | 125 | .offset = @as(u32, @intCast(end_offset - 4)), |
| 126 | 126 | .addend = 0, |
| 127 | .pcrel = true, | |
| 127 | .type = .pcrel, | |
| 128 | 128 | }); |
| 129 | 129 | } else return emit.fail("TODO implement linker reloc for {s}", .{ |
| 130 | 130 | @tagName(emit.bin_file.tag), |
src/link/Plan9.zig+147-71| ... | ... | @@ -100,11 +100,23 @@ syms_index_free_list: std.ArrayListUnmanaged(usize) = .{}, |
| 100 | 100 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 101 | 101 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, |
| 102 | 102 | |
| 103 | /// Indices of the three "special" symbols into atoms | |
| 104 | etext_edata_end_atom_indices: [3]?Atom.Index = .{ null, null, null }, | |
| 105 | ||
| 103 | 106 | const Reloc = struct { |
| 104 | 107 | target: Atom.Index, |
| 105 | 108 | offset: u64, |
| 106 | 109 | addend: u32, |
| 107 | pcrel: bool = false, | |
| 110 | type: enum { | |
| 111 | pcrel, | |
| 112 | nonpcrel, | |
| 113 | // for getting the value of the etext symbol; we ignore target | |
| 114 | special_etext, | |
| 115 | // for getting the value of the edata symbol; we ignore target | |
| 116 | special_edata, | |
| 117 | // for getting the value of the end symbol; we ignore target | |
| 118 | special_end, | |
| 119 | } = .nonpcrel, | |
| 108 | 120 | }; |
| 109 | 121 | |
| 110 | 122 | const Bases = struct { |
| ... | ... | @@ -467,15 +479,10 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 467 | 479 | pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void { |
| 468 | 480 | const decl = mod.declPtr(decl_index); |
| 469 | 481 | |
| 470 | if (decl.val.getExternFunc(mod)) |_| { | |
| 471 | return; // TODO Should we do more when front-end analyzed extern decl? | |
| 472 | } | |
| 473 | if (decl.val.getVariable(mod)) |variable| { | |
| 474 | if (variable.is_extern) { | |
| 475 | return; // TODO Should we do more when front-end analyzed extern decl? | |
| 476 | } | |
| 482 | if (decl.isExtern(mod)) { | |
| 483 | log.debug("found extern decl: {s}", .{mod.intern_pool.stringToSlice(decl.name)}); | |
| 484 | return; | |
| 477 | 485 | } |
| 478 | ||
| 479 | 486 | const atom_idx = try self.seeDecl(decl_index); |
| 480 | 487 | |
| 481 | 488 | var code_buffer = std.ArrayList(u8).init(self.base.allocator); |
| ... | ... | @@ -574,6 +581,13 @@ pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { |
| 574 | 581 | } |
| 575 | 582 | } |
| 576 | 583 | |
| 584 | fn externCount(self: *Plan9) usize { | |
| 585 | var extern_atom_count: usize = 0; | |
| 586 | for (self.etext_edata_end_atom_indices) |idx| { | |
| 587 | if (idx != null) extern_atom_count += 1; | |
| 588 | } | |
| 589 | return extern_atom_count; | |
| 590 | } | |
| 577 | 591 | // counts decls, unnamed consts, and lazy syms |
| 578 | 592 | fn atomCount(self: *Plan9) usize { |
| 579 | 593 | var fn_decl_count: usize = 0; |
| ... | ... | @@ -594,7 +608,8 @@ fn atomCount(self: *Plan9) usize { |
| 594 | 608 | while (it_lazy.next()) |kv| { |
| 595 | 609 | lazy_atom_count += kv.value_ptr.numberOfAtoms(); |
| 596 | 610 | } |
| 597 | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count; | |
| 611 | const extern_atom_count = self.externCount(); | |
| 612 | return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count; | |
| 598 | 613 | } |
| 599 | 614 | |
| 600 | 615 | pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void { |
| ... | ... | @@ -647,7 +662,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 647 | 662 | defer self.base.allocator.free(got_table); |
| 648 | 663 | |
| 649 | 664 | // + 4 for header, got, symbols, linecountinfo |
| 650 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4); | |
| 665 | var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount()); | |
| 651 | 666 | defer self.base.allocator.free(iovecs); |
| 652 | 667 | |
| 653 | 668 | const file = self.base.file.?; |
| ... | ... | @@ -729,8 +744,17 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 729 | 744 | self.syms.items[text_atom.sym_index.?].value = off; |
| 730 | 745 | } |
| 731 | 746 | } |
| 732 | // etext symbol | |
| 733 | self.syms.items[2].value = self.getAddr(text_i, .t); | |
| 747 | // fix the sym for etext | |
| 748 | if (self.etext_edata_end_atom_indices[0]) |etext_atom_idx| { | |
| 749 | const etext_atom = self.getAtom(etext_atom_idx); | |
| 750 | const val = self.getAddr(text_i, .t); | |
| 751 | self.syms.items[etext_atom.sym_index.?].value = val; | |
| 752 | if (!self.sixtyfour_bit) { | |
| 753 | mem.writeInt(u32, got_table[etext_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); | |
| 754 | } else { | |
| 755 | mem.writeInt(u64, got_table[etext_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); | |
| 756 | } | |
| 757 | } | |
| 734 | 758 | // global offset table is in data |
| 735 | 759 | iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len }; |
| 736 | 760 | iovecs_i += 1; |
| ... | ... | @@ -800,15 +824,34 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 800 | 824 | self.syms.items[data_atom.sym_index.?].value = off; |
| 801 | 825 | } |
| 802 | 826 | // edata symbol |
| 803 | self.syms.items[0].value = self.getAddr(data_i, .b); | |
| 804 | // end | |
| 805 | self.syms.items[1].value = self.getAddr(data_i, .b); | |
| 827 | if (self.etext_edata_end_atom_indices[1]) |edata_atom_idx| { | |
| 828 | const edata_atom = self.getAtom(edata_atom_idx); | |
| 829 | const val = self.getAddr(data_i, .b); | |
| 830 | self.syms.items[edata_atom.sym_index.?].value = val; | |
| 831 | if (!self.sixtyfour_bit) { | |
| 832 | mem.writeInt(u32, got_table[edata_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); | |
| 833 | } else { | |
| 834 | mem.writeInt(u64, got_table[edata_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); | |
| 835 | } | |
| 836 | } | |
| 837 | // end symbol (same as edata because native backends don't do .bss yet) | |
| 838 | if (self.etext_edata_end_atom_indices[2]) |end_atom_idx| { | |
| 839 | const end_atom = self.getAtom(end_atom_idx); | |
| 840 | const val = self.getAddr(data_i, .b); | |
| 841 | self.syms.items[end_atom.sym_index.?].value = val; | |
| 842 | if (!self.sixtyfour_bit) { | |
| 843 | mem.writeInt(u32, got_table[end_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian()); | |
| 844 | } else { | |
| 845 | log.debug("write end (got_table[0x{x}] = 0x{x})", .{ end_atom.got_index.? * 8, val }); | |
| 846 | mem.writeInt(u64, got_table[end_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian()); | |
| 847 | } | |
| 848 | } | |
| 806 | 849 | } |
| 807 | 850 | var sym_buf = std.ArrayList(u8).init(self.base.allocator); |
| 808 | 851 | try self.writeSyms(&sym_buf); |
| 809 | 852 | const syms = try sym_buf.toOwnedSlice(); |
| 810 | 853 | defer self.base.allocator.free(syms); |
| 811 | assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls | |
| 854 | assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls | |
| 812 | 855 | iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len }; |
| 813 | 856 | iovecs_i += 1; |
| 814 | 857 | iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len }; |
| ... | ... | @@ -836,28 +879,46 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No |
| 836 | 879 | const source_atom_index = kv.key_ptr.*; |
| 837 | 880 | const source_atom = self.getAtom(source_atom_index); |
| 838 | 881 | const source_atom_symbol = self.syms.items[source_atom.sym_index.?]; |
| 882 | const code = source_atom.code.getCode(self); | |
| 883 | const endian = self.base.options.target.cpu.arch.endian(); | |
| 839 | 884 | for (kv.value_ptr.items) |reloc| { |
| 840 | const target_atom_index = reloc.target; | |
| 841 | const target_atom = self.getAtomPtr(target_atom_index); | |
| 842 | const target_symbol = self.syms.items[target_atom.sym_index.?]; | |
| 843 | const target_offset = target_atom.offset.?; | |
| 844 | ||
| 845 | 885 | const offset = reloc.offset; |
| 846 | 886 | const addend = reloc.addend; |
| 847 | ||
| 848 | const code = source_atom.code.getCode(self); | |
| 849 | ||
| 850 | if (reloc.pcrel) { | |
| 851 | const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset)); | |
| 852 | mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), self.base.options.target.cpu.arch.endian()); | |
| 887 | if (reloc.type == .pcrel or reloc.type == .nonpcrel) { | |
| 888 | const target_atom_index = reloc.target; | |
| 889 | const target_atom = self.getAtomPtr(target_atom_index); | |
| 890 | const target_symbol = self.syms.items[target_atom.sym_index.?]; | |
| 891 | const target_offset = target_atom.offset.?; | |
| 892 | ||
| 893 | switch (reloc.type) { | |
| 894 | .pcrel => { | |
| 895 | const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset)); | |
| 896 | mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), endian); | |
| 897 | }, | |
| 898 | .nonpcrel => { | |
| 899 | if (!self.sixtyfour_bit) { | |
| 900 | mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(target_offset + addend)), endian); | |
| 901 | } else { | |
| 902 | mem.writeInt(u64, code[@intCast(offset)..][0..8], target_offset + addend, endian); | |
| 903 | } | |
| 904 | }, | |
| 905 | else => unreachable, | |
| 906 | } | |
| 907 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ target_symbol.name, addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, target_offset, addend }); | |
| 853 | 908 | } else { |
| 909 | const addr = switch (reloc.type) { | |
| 910 | .special_etext => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[0].?).sym_index.?].value, | |
| 911 | .special_edata => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[1].?).sym_index.?].value, | |
| 912 | .special_end => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[2].?).sym_index.?].value, | |
| 913 | else => unreachable, | |
| 914 | }; | |
| 854 | 915 | if (!self.sixtyfour_bit) { |
| 855 | mem.writeInt(u32, code[@as(usize, @intCast(offset))..][0..4], @as(u32, @intCast(target_offset + addend)), self.base.options.target.cpu.arch.endian()); | |
| 916 | mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(addr + addend)), endian); | |
| 856 | 917 | } else { |
| 857 | mem.writeInt(u64, code[@as(usize, @intCast(offset))..][0..8], target_offset + addend, self.base.options.target.cpu.arch.endian()); | |
| 918 | mem.writeInt(u64, code[@intCast(offset)..][0..8], addr + addend, endian); | |
| 858 | 919 | } |
| 920 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ @tagName(reloc.type), addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, addr, addend }); | |
| 859 | 921 | } |
| 860 | log.debug("relocating the address of '{s}' + {d} into '{s}' + {d} (({s}[{d}] = 0x{x} + 0x{x})", .{ target_symbol.name, addend, source_atom_symbol.name, offset, source_atom_symbol.name, offset, target_offset, addend }); | |
| 861 | 922 | } |
| 862 | 923 | } |
| 863 | 924 | } |
| ... | ... | @@ -983,7 +1044,24 @@ pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index { |
| 983 | 1044 | .exports = .{}, |
| 984 | 1045 | }; |
| 985 | 1046 | } |
| 986 | return gop.value_ptr.index; | |
| 1047 | const atom_idx = gop.value_ptr.index; | |
| 1048 | // handle externs here because they might not get updateDecl called on them | |
| 1049 | const mod = self.base.options.module.?; | |
| 1050 | const decl = mod.declPtr(decl_index); | |
| 1051 | const name = mod.intern_pool.stringToSlice(decl.name); | |
| 1052 | if (decl.isExtern(mod)) { | |
| 1053 | // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs | |
| 1054 | if (std.mem.eql(u8, name, "etext")) { | |
| 1055 | self.etext_edata_end_atom_indices[0] = atom_idx; | |
| 1056 | } else if (std.mem.eql(u8, name, "edata")) { | |
| 1057 | self.etext_edata_end_atom_indices[1] = atom_idx; | |
| 1058 | } else if (std.mem.eql(u8, name, "end")) { | |
| 1059 | self.etext_edata_end_atom_indices[2] = atom_idx; | |
| 1060 | } | |
| 1061 | try self.updateFinish(decl_index); | |
| 1062 | log.debug("seeDecl(extern) for {s} (got_addr=0x{x})", .{ name, self.getAtom(atom_idx).getOffsetTableAddress(self) }); | |
| 1063 | } else log.debug("seeDecl for {s}", .{name}); | |
| 1064 | return atom_idx; | |
| 987 | 1065 | } |
| 988 | 1066 | |
| 989 | 1067 | pub fn updateDeclExports( |
| ... | ... | @@ -1157,23 +1235,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 1157 | 1235 | |
| 1158 | 1236 | self.bases = defaultBaseAddrs(options.target.cpu.arch); |
| 1159 | 1237 | |
| 1160 | // first 4 symbols in our table are edata, end, etext, and got | |
| 1161 | 1238 | try self.syms.appendSlice(self.base.allocator, &.{ |
| 1162 | .{ | |
| 1163 | .value = 0xcafebabe, | |
| 1164 | .type = .B, | |
| 1165 | .name = "edata", | |
| 1166 | }, | |
| 1167 | .{ | |
| 1168 | .value = 0xcafebabe, | |
| 1169 | .type = .B, | |
| 1170 | .name = "end", | |
| 1171 | }, | |
| 1172 | .{ | |
| 1173 | .value = 0xcafebabe, | |
| 1174 | .type = .T, | |
| 1175 | .name = "etext", | |
| 1176 | }, | |
| 1177 | 1239 | // we include the global offset table to make it easier for debugging |
| 1178 | 1240 | .{ |
| 1179 | 1241 | .value = self.getAddr(0, .d), // the global offset table starts at 0 |
| ... | ... | @@ -1202,11 +1264,8 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1202 | 1264 | const mod = self.base.options.module.?; |
| 1203 | 1265 | const ip = &mod.intern_pool; |
| 1204 | 1266 | const writer = buf.writer(); |
| 1205 | // write the first four symbols (edata, etext, end, __GOT) | |
| 1267 | // write __GOT | |
| 1206 | 1268 | try self.writeSym(writer, self.syms.items[0]); |
| 1207 | try self.writeSym(writer, self.syms.items[1]); | |
| 1208 | try self.writeSym(writer, self.syms.items[2]); | |
| 1209 | try self.writeSym(writer, self.syms.items[3]); | |
| 1210 | 1269 | // write the f symbols |
| 1211 | 1270 | { |
| 1212 | 1271 | var it = self.file_segments.iterator(); |
| ... | ... | @@ -1296,6 +1355,14 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { |
| 1296 | 1355 | } |
| 1297 | 1356 | } |
| 1298 | 1357 | } |
| 1358 | // special symbols | |
| 1359 | for (self.etext_edata_end_atom_indices) |idx| { | |
| 1360 | if (idx) |atom_idx| { | |
| 1361 | const atom = self.getAtom(atom_idx); | |
| 1362 | const sym = self.syms.items[atom.sym_index.?]; | |
| 1363 | try self.writeSym(writer, sym); | |
| 1364 | } | |
| 1365 | } | |
| 1299 | 1366 | } |
| 1300 | 1367 | |
| 1301 | 1368 | /// Must be called only after a successful call to `updateDecl`. |
| ... | ... | @@ -1312,26 +1379,35 @@ pub fn getDeclVAddr( |
| 1312 | 1379 | ) !u64 { |
| 1313 | 1380 | const mod = self.base.options.module.?; |
| 1314 | 1381 | const decl = mod.declPtr(decl_index); |
| 1315 | // we might already know the vaddr | |
| 1316 | if (decl.ty.zigTypeTag(mod) == .Fn) { | |
| 1317 | var start = self.bases.text; | |
| 1318 | var it_file = self.fn_decl_table.iterator(); | |
| 1319 | while (it_file.next()) |fentry| { | |
| 1320 | var symidx_and_submap = fentry.value_ptr; | |
| 1321 | var submap_it = symidx_and_submap.functions.iterator(); | |
| 1322 | while (submap_it.next()) |entry| { | |
| 1323 | if (entry.key_ptr.* == decl_index) return start; | |
| 1324 | start += entry.value_ptr.code.len; | |
| 1325 | } | |
| 1326 | } | |
| 1327 | } else { | |
| 1328 | var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8; | |
| 1329 | var it = self.data_decl_table.iterator(); | |
| 1330 | while (it.next()) |kv| { | |
| 1331 | if (decl_index == kv.key_ptr.*) return start; | |
| 1332 | start += kv.value_ptr.len; | |
| 1382 | log.debug("getDeclVAddr for {s}", .{mod.intern_pool.stringToSlice(decl.name)}); | |
| 1383 | if (decl.isExtern(mod)) { | |
| 1384 | const extern_name = mod.intern_pool.stringToSlice(decl.name); | |
| 1385 | if (std.mem.eql(u8, extern_name, "etext")) { | |
| 1386 | try self.addReloc(reloc_info.parent_atom_index, .{ | |
| 1387 | .target = undefined, | |
| 1388 | .offset = reloc_info.offset, | |
| 1389 | .addend = reloc_info.addend, | |
| 1390 | .type = .special_etext, | |
| 1391 | }); | |
| 1392 | } else if (std.mem.eql(u8, extern_name, "edata")) { | |
| 1393 | try self.addReloc(reloc_info.parent_atom_index, .{ | |
| 1394 | .target = undefined, | |
| 1395 | .offset = reloc_info.offset, | |
| 1396 | .addend = reloc_info.addend, | |
| 1397 | .type = .special_edata, | |
| 1398 | }); | |
| 1399 | } else if (std.mem.eql(u8, extern_name, "end")) { | |
| 1400 | try self.addReloc(reloc_info.parent_atom_index, .{ | |
| 1401 | .target = undefined, | |
| 1402 | .offset = reloc_info.offset, | |
| 1403 | .addend = reloc_info.addend, | |
| 1404 | .type = .special_end, | |
| 1405 | }); | |
| 1333 | 1406 | } |
| 1407 | // TODO handle other extern variables and functions | |
| 1408 | return undefined; | |
| 1334 | 1409 | } |
| 1410 | // otherwise, we just add a relocation | |
| 1335 | 1411 | const atom_index = try self.seeDecl(decl_index); |
| 1336 | 1412 | // the parent_atom_index in this case is just the decl_index of the parent |
| 1337 | 1413 | try self.addReloc(reloc_info.parent_atom_index, .{ |
| ... | ... | @@ -1339,7 +1415,7 @@ pub fn getDeclVAddr( |
| 1339 | 1415 | .offset = reloc_info.offset, |
| 1340 | 1416 | .addend = reloc_info.addend, |
| 1341 | 1417 | }); |
| 1342 | return 0xcafebabe; | |
| 1418 | return undefined; | |
| 1343 | 1419 | } |
| 1344 | 1420 | |
| 1345 | 1421 | pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { |