mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #16359 from g-w1/plan9-more-std
Plan 9: more standard library support
This commit is contained in:
commit
f887b02518
@ -8467,9 +8467,10 @@ export fn @"A function name that is a complete sentence."() void {}
|
|||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|
||||||
{#header_open|@extern#}
|
{#header_open|@extern#}
|
||||||
<pre>{#syntax#}@extern(T: type, comptime options: std.builtin.ExternOptions) *T{#endsyntax#}</pre>
|
<pre>{#syntax#}@extern(T: type, comptime options: std.builtin.ExternOptions) T{#endsyntax#}</pre>
|
||||||
<p>
|
<p>
|
||||||
Creates a reference to an external symbol in the output object file.
|
Creates a reference to an external symbol in the output object file.
|
||||||
|
T must be a pointer type.
|
||||||
</p>
|
</p>
|
||||||
{#see_also|@export#}
|
{#see_also|@export#}
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ pub const Watch = @import("fs/watch.zig").Watch;
|
|||||||
/// fit into a UTF-8 encoded array of this length.
|
/// fit into a UTF-8 encoded array of this length.
|
||||||
/// The byte count includes room for a null sentinel byte.
|
/// The byte count includes room for a null sentinel byte.
|
||||||
pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
|
pub const MAX_PATH_BYTES = switch (builtin.os.tag) {
|
||||||
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris => os.PATH_MAX,
|
.linux, .macos, .ios, .freebsd, .openbsd, .netbsd, .dragonfly, .haiku, .solaris, .plan9 => os.PATH_MAX,
|
||||||
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
|
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
|
||||||
// If it would require 4 UTF-8 bytes, then there would be a surrogate
|
// If it would require 4 UTF-8 bytes, then there would be a surrogate
|
||||||
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
|
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
|
||||||
@ -1160,7 +1160,9 @@ pub const Dir = struct {
|
|||||||
return self.openFileW(path_w.span(), flags);
|
return self.openFileW(path_w.span(), flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
var os_flags: u32 = os.O.CLOEXEC;
|
var os_flags: u32 = 0;
|
||||||
|
if (@hasDecl(os.O, "CLOEXEC")) os_flags = os.O.CLOEXEC;
|
||||||
|
|
||||||
// Use the O locking flags if the os supports them to acquire the lock
|
// Use the O locking flags if the os supports them to acquire the lock
|
||||||
// atomically.
|
// atomically.
|
||||||
const has_flock_open_flags = @hasDecl(os.O, "EXLOCK");
|
const has_flock_open_flags = @hasDecl(os.O, "EXLOCK");
|
||||||
@ -1180,7 +1182,7 @@ pub const Dir = struct {
|
|||||||
if (@hasDecl(os.O, "LARGEFILE")) {
|
if (@hasDecl(os.O, "LARGEFILE")) {
|
||||||
os_flags |= os.O.LARGEFILE;
|
os_flags |= os.O.LARGEFILE;
|
||||||
}
|
}
|
||||||
if (!flags.allow_ctty) {
|
if (@hasDecl(os.O, "NOCTTY") and !flags.allow_ctty) {
|
||||||
os_flags |= os.O.NOCTTY;
|
os_flags |= os.O.NOCTTY;
|
||||||
}
|
}
|
||||||
os_flags |= switch (flags.mode) {
|
os_flags |= switch (flags.mode) {
|
||||||
@ -1196,7 +1198,7 @@ pub const Dir = struct {
|
|||||||
|
|
||||||
// WASI doesn't have os.flock so we intetinally check OS prior to the inner if block
|
// WASI doesn't have os.flock so we intetinally check OS prior to the inner if block
|
||||||
// since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
|
// since it is not compiltime-known and we need to avoid undefined symbol in Wasm.
|
||||||
if (builtin.target.os.tag != .wasi) {
|
if (@hasDecl(os.system, "LOCK") and builtin.target.os.tag != .wasi) {
|
||||||
if (!has_flock_open_flags and flags.lock != .none) {
|
if (!has_flock_open_flags and flags.lock != .none) {
|
||||||
// TODO: integrate async I/O
|
// TODO: integrate async I/O
|
||||||
const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0);
|
const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK.NB else @as(i32, 0);
|
||||||
|
|||||||
@ -21,6 +21,7 @@ pub const WasmAllocator = @import("heap/WasmAllocator.zig");
|
|||||||
pub const WasmPageAllocator = @import("heap/WasmPageAllocator.zig");
|
pub const WasmPageAllocator = @import("heap/WasmPageAllocator.zig");
|
||||||
pub const PageAllocator = @import("heap/PageAllocator.zig");
|
pub const PageAllocator = @import("heap/PageAllocator.zig");
|
||||||
pub const ThreadSafeAllocator = @import("heap/ThreadSafeAllocator.zig");
|
pub const ThreadSafeAllocator = @import("heap/ThreadSafeAllocator.zig");
|
||||||
|
pub const SbrkAllocator = @import("heap/sbrk_allocator.zig").SbrkAllocator;
|
||||||
|
|
||||||
const memory_pool = @import("heap/memory_pool.zig");
|
const memory_pool = @import("heap/memory_pool.zig");
|
||||||
pub const MemoryPool = memory_pool.MemoryPool;
|
pub const MemoryPool = memory_pool.MemoryPool;
|
||||||
@ -228,6 +229,11 @@ pub const page_allocator = if (builtin.target.isWasm())
|
|||||||
.ptr = undefined,
|
.ptr = undefined,
|
||||||
.vtable = &WasmPageAllocator.vtable,
|
.vtable = &WasmPageAllocator.vtable,
|
||||||
}
|
}
|
||||||
|
else if (builtin.target.os.tag == .plan9)
|
||||||
|
Allocator{
|
||||||
|
.ptr = undefined,
|
||||||
|
.vtable = &SbrkAllocator(std.os.plan9.sbrk).vtable,
|
||||||
|
}
|
||||||
else if (builtin.target.os.tag == .freestanding)
|
else if (builtin.target.os.tag == .freestanding)
|
||||||
root.os.heap.page_allocator
|
root.os.heap.page_allocator
|
||||||
else
|
else
|
||||||
|
|||||||
161
lib/std/heap/sbrk_allocator.zig
Normal file
161
lib/std/heap/sbrk_allocator.zig
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
const std = @import("../std.zig");
|
||||||
|
const builtin = @import("builtin");
|
||||||
|
const math = std.math;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
|
const mem = std.mem;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
|
pub fn SbrkAllocator(comptime sbrk: *const fn (n: usize) usize) type {
|
||||||
|
return struct {
|
||||||
|
pub const vtable = Allocator.VTable{
|
||||||
|
.alloc = alloc,
|
||||||
|
.resize = resize,
|
||||||
|
.free = free,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Error = Allocator.Error;
|
||||||
|
|
||||||
|
lock: std.Thread.Mutex = .{},
|
||||||
|
|
||||||
|
const max_usize = math.maxInt(usize);
|
||||||
|
const ushift = math.Log2Int(usize);
|
||||||
|
const bigpage_size = 64 * 1024;
|
||||||
|
const pages_per_bigpage = bigpage_size / mem.page_size;
|
||||||
|
const bigpage_count = max_usize / bigpage_size;
|
||||||
|
|
||||||
|
/// Because of storing free list pointers, the minimum size class is 3.
|
||||||
|
const min_class = math.log2(math.ceilPowerOfTwoAssert(usize, 1 + @sizeOf(usize)));
|
||||||
|
const size_class_count = math.log2(bigpage_size) - min_class;
|
||||||
|
/// 0 - 1 bigpage
|
||||||
|
/// 1 - 2 bigpages
|
||||||
|
/// 2 - 4 bigpages
|
||||||
|
/// etc.
|
||||||
|
const big_size_class_count = math.log2(bigpage_count);
|
||||||
|
|
||||||
|
var next_addrs = [1]usize{0} ** size_class_count;
|
||||||
|
/// For each size class, points to the freed pointer.
|
||||||
|
var frees = [1]usize{0} ** size_class_count;
|
||||||
|
/// For each big size class, points to the freed pointer.
|
||||||
|
var big_frees = [1]usize{0} ** big_size_class_count;
|
||||||
|
|
||||||
|
// TODO don't do the naive locking strategy
|
||||||
|
var lock: std.Thread.Mutex = .{};
|
||||||
|
fn alloc(ctx: *anyopaque, len: usize, log2_align: u8, return_address: usize) ?[*]u8 {
|
||||||
|
_ = ctx;
|
||||||
|
_ = return_address;
|
||||||
|
lock.lock();
|
||||||
|
defer lock.unlock();
|
||||||
|
// Make room for the freelist next pointer.
|
||||||
|
const alignment = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_align));
|
||||||
|
const actual_len = @max(len +| @sizeOf(usize), alignment);
|
||||||
|
const slot_size = math.ceilPowerOfTwo(usize, actual_len) catch return null;
|
||||||
|
const class = math.log2(slot_size) - min_class;
|
||||||
|
if (class < size_class_count) {
|
||||||
|
const addr = a: {
|
||||||
|
const top_free_ptr = frees[class];
|
||||||
|
if (top_free_ptr != 0) {
|
||||||
|
const node = @as(*usize, @ptrFromInt(top_free_ptr + (slot_size - @sizeOf(usize))));
|
||||||
|
frees[class] = node.*;
|
||||||
|
break :a top_free_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const next_addr = next_addrs[class];
|
||||||
|
if (next_addr % mem.page_size == 0) {
|
||||||
|
const addr = allocBigPages(1);
|
||||||
|
if (addr == 0) return null;
|
||||||
|
//std.debug.print("allocated fresh slot_size={d} class={d} addr=0x{x}\n", .{
|
||||||
|
// slot_size, class, addr,
|
||||||
|
//});
|
||||||
|
next_addrs[class] = addr + slot_size;
|
||||||
|
break :a addr;
|
||||||
|
} else {
|
||||||
|
next_addrs[class] = next_addr + slot_size;
|
||||||
|
break :a next_addr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return @as([*]u8, @ptrFromInt(addr));
|
||||||
|
}
|
||||||
|
const bigpages_needed = bigPagesNeeded(actual_len);
|
||||||
|
const addr = allocBigPages(bigpages_needed);
|
||||||
|
return @as([*]u8, @ptrFromInt(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resize(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
buf: []u8,
|
||||||
|
log2_buf_align: u8,
|
||||||
|
new_len: usize,
|
||||||
|
return_address: usize,
|
||||||
|
) bool {
|
||||||
|
_ = ctx;
|
||||||
|
_ = return_address;
|
||||||
|
lock.lock();
|
||||||
|
defer lock.unlock();
|
||||||
|
// We don't want to move anything from one size class to another, but we
|
||||||
|
// can recover bytes in between powers of two.
|
||||||
|
const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align));
|
||||||
|
const old_actual_len = @max(buf.len + @sizeOf(usize), buf_align);
|
||||||
|
const new_actual_len = @max(new_len +| @sizeOf(usize), buf_align);
|
||||||
|
const old_small_slot_size = math.ceilPowerOfTwoAssert(usize, old_actual_len);
|
||||||
|
const old_small_class = math.log2(old_small_slot_size) - min_class;
|
||||||
|
if (old_small_class < size_class_count) {
|
||||||
|
const new_small_slot_size = math.ceilPowerOfTwo(usize, new_actual_len) catch return false;
|
||||||
|
return old_small_slot_size == new_small_slot_size;
|
||||||
|
} else {
|
||||||
|
const old_bigpages_needed = bigPagesNeeded(old_actual_len);
|
||||||
|
const old_big_slot_pages = math.ceilPowerOfTwoAssert(usize, old_bigpages_needed);
|
||||||
|
const new_bigpages_needed = bigPagesNeeded(new_actual_len);
|
||||||
|
const new_big_slot_pages = math.ceilPowerOfTwo(usize, new_bigpages_needed) catch return false;
|
||||||
|
return old_big_slot_pages == new_big_slot_pages;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn free(
|
||||||
|
ctx: *anyopaque,
|
||||||
|
buf: []u8,
|
||||||
|
log2_buf_align: u8,
|
||||||
|
return_address: usize,
|
||||||
|
) void {
|
||||||
|
_ = ctx;
|
||||||
|
_ = return_address;
|
||||||
|
lock.lock();
|
||||||
|
defer lock.unlock();
|
||||||
|
const buf_align = @as(usize, 1) << @as(Allocator.Log2Align, @intCast(log2_buf_align));
|
||||||
|
const actual_len = @max(buf.len + @sizeOf(usize), buf_align);
|
||||||
|
const slot_size = math.ceilPowerOfTwoAssert(usize, actual_len);
|
||||||
|
const class = math.log2(slot_size) - min_class;
|
||||||
|
const addr = @intFromPtr(buf.ptr);
|
||||||
|
if (class < size_class_count) {
|
||||||
|
const node = @as(*usize, @ptrFromInt(addr + (slot_size - @sizeOf(usize))));
|
||||||
|
node.* = frees[class];
|
||||||
|
frees[class] = addr;
|
||||||
|
} else {
|
||||||
|
const bigpages_needed = bigPagesNeeded(actual_len);
|
||||||
|
const pow2_pages = math.ceilPowerOfTwoAssert(usize, bigpages_needed);
|
||||||
|
const big_slot_size_bytes = pow2_pages * bigpage_size;
|
||||||
|
const node = @as(*usize, @ptrFromInt(addr + (big_slot_size_bytes - @sizeOf(usize))));
|
||||||
|
const big_class = math.log2(pow2_pages);
|
||||||
|
node.* = big_frees[big_class];
|
||||||
|
big_frees[big_class] = addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn bigPagesNeeded(byte_count: usize) usize {
|
||||||
|
return (byte_count + (bigpage_size + (@sizeOf(usize) - 1))) / bigpage_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocBigPages(n: usize) usize {
|
||||||
|
const pow2_pages = math.ceilPowerOfTwoAssert(usize, n);
|
||||||
|
const slot_size_bytes = pow2_pages * bigpage_size;
|
||||||
|
const class = math.log2(pow2_pages);
|
||||||
|
|
||||||
|
const top_free_ptr = big_frees[class];
|
||||||
|
if (top_free_ptr != 0) {
|
||||||
|
const node = @as(*usize, @ptrFromInt(top_free_ptr + (slot_size_bytes - @sizeOf(usize))));
|
||||||
|
big_frees[class] = node.*;
|
||||||
|
return top_free_ptr;
|
||||||
|
}
|
||||||
|
return sbrk(pow2_pages * pages_per_bigpage * mem.page_size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,6 +1,12 @@
|
|||||||
const std = @import("../std.zig");
|
const std = @import("../std.zig");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
|
pub const fd_t = i32;
|
||||||
|
|
||||||
|
pub const STDIN_FILENO = 0;
|
||||||
|
pub const STDOUT_FILENO = 1;
|
||||||
|
pub const STDERR_FILENO = 2;
|
||||||
|
pub const PATH_MAX = 1023;
|
||||||
pub const syscall_bits = switch (builtin.cpu.arch) {
|
pub const syscall_bits = switch (builtin.cpu.arch) {
|
||||||
.x86_64 => @import("plan9/x86_64.zig"),
|
.x86_64 => @import("plan9/x86_64.zig"),
|
||||||
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
|
else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
|
||||||
@ -12,6 +18,43 @@ pub fn getErrno(r: usize) E {
|
|||||||
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
const int = if (signed_r > -4096 and signed_r < 0) -signed_r else 0;
|
||||||
return @as(E, @enumFromInt(int));
|
return @as(E, @enumFromInt(int));
|
||||||
}
|
}
|
||||||
|
// The max bytes that can be in the errstr buff
|
||||||
|
pub const ERRMAX = 128;
|
||||||
|
var errstr_buf: [ERRMAX]u8 = undefined;
|
||||||
|
/// Gets whatever the last errstr was
|
||||||
|
pub fn errstr() []const u8 {
|
||||||
|
_ = syscall_bits.syscall2(.ERRSTR, @intFromPtr(&errstr_buf), ERRMAX);
|
||||||
|
return std.mem.span(@as([*:0]u8, @ptrCast(&errstr_buf)));
|
||||||
|
}
|
||||||
|
pub const Plink = anyopaque;
|
||||||
|
pub const Tos = extern struct {
|
||||||
|
/// Per process profiling
|
||||||
|
prof: extern struct {
|
||||||
|
/// known to be 0(ptr)
|
||||||
|
pp: *Plink,
|
||||||
|
/// known to be 4(ptr)
|
||||||
|
next: *Plink,
|
||||||
|
last: *Plink,
|
||||||
|
first: *Plink,
|
||||||
|
pid: u32,
|
||||||
|
what: u32,
|
||||||
|
},
|
||||||
|
/// cycle clock frequency if there is one, 0 otherwise
|
||||||
|
cyclefreq: u64,
|
||||||
|
/// cycles spent in kernel
|
||||||
|
kcycles: i64,
|
||||||
|
/// cycles spent in process (kernel + user)
|
||||||
|
pcycles: i64,
|
||||||
|
/// might as well put the pid here
|
||||||
|
pid: u32,
|
||||||
|
clock: u32,
|
||||||
|
// top of stack is here
|
||||||
|
};
|
||||||
|
|
||||||
|
pub var tos: *Tos = undefined; // set in start.zig
|
||||||
|
pub fn getpid() u32 {
|
||||||
|
return tos.pid;
|
||||||
|
}
|
||||||
pub const SIG = struct {
|
pub const SIG = struct {
|
||||||
/// hangup
|
/// hangup
|
||||||
pub const HUP = 1;
|
pub const HUP = 1;
|
||||||
@ -57,7 +100,8 @@ pub const SIG = struct {
|
|||||||
};
|
};
|
||||||
pub const sigset_t = c_long;
|
pub const sigset_t = c_long;
|
||||||
pub const empty_sigset = 0;
|
pub const empty_sigset = 0;
|
||||||
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.
|
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.
|
||||||
pub const Sigaction = extern struct {
|
pub const Sigaction = extern struct {
|
||||||
pub const handler_fn = *const fn (c_int) callconv(.C) void;
|
pub const handler_fn = *const fn (c_int) callconv(.C) void;
|
||||||
pub const sigaction_fn = *const fn (c_int, *const siginfo_t, ?*const anyopaque) callconv(.C) void;
|
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 {
|
|||||||
mask: sigset_t,
|
mask: sigset_t,
|
||||||
flags: c_int,
|
flags: c_int,
|
||||||
};
|
};
|
||||||
|
pub const AT = struct {
|
||||||
|
pub const FDCWD = -100; // we just make up a constant; FDCWD and openat don't actually exist in plan9
|
||||||
|
};
|
||||||
// TODO implement sigaction
|
// TODO implement sigaction
|
||||||
// right now it is just a shim to allow using start.zig code
|
// right now it is just a shim to allow using start.zig code
|
||||||
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigaction) usize {
|
||||||
@ -132,20 +179,48 @@ pub const SYS = enum(usize) {
|
|||||||
_NSEC = 53,
|
_NSEC = 53,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {
|
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
|
||||||
return syscall_bits.syscall4(.PWRITE, fd, @intFromPtr(buf), count, offset);
|
return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1)));
|
||||||
|
}
|
||||||
|
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize {
|
||||||
|
return syscall_bits.syscall4(.PWRITE, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pread(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {
|
pub fn read(fd: i32, buf: [*]const u8, count: usize) usize {
|
||||||
return syscall_bits.syscall4(.PREAD, fd, @intFromPtr(buf), count, offset);
|
return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(@as(isize, -1)));
|
||||||
|
}
|
||||||
|
pub fn pread(fd: i32, buf: [*]const u8, count: usize, offset: isize) usize {
|
||||||
|
return syscall_bits.syscall4(.PREAD, @bitCast(@as(isize, fd)), @intFromPtr(buf), count, @bitCast(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(path: [*:0]const u8, omode: OpenMode) usize {
|
pub fn open(path: [*:0]const u8, flags: u32) usize {
|
||||||
return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @intFromEnum(omode));
|
return syscall_bits.syscall2(.OPEN, @intFromPtr(path), @bitCast(@as(isize, flags)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize {
|
pub fn openat(dirfd: i32, path: [*:0]const u8, flags: u32, _: mode_t) usize {
|
||||||
return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @intFromEnum(omode), perms);
|
// we skip perms because only create supports perms
|
||||||
|
if (dirfd == AT.FDCWD) { // openat(AT_FDCWD, ...) == open(...)
|
||||||
|
return open(path, flags);
|
||||||
|
}
|
||||||
|
var dir_path_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
|
var total_path_buf: [std.fs.MAX_PATH_BYTES + 1]u8 = undefined;
|
||||||
|
const rc = fd2path(dirfd, &dir_path_buf, std.fs.MAX_PATH_BYTES);
|
||||||
|
if (rc != 0) return rc;
|
||||||
|
var fba = std.heap.FixedBufferAllocator.init(&total_path_buf);
|
||||||
|
var alloc = fba.allocator();
|
||||||
|
const dir_path = std.mem.span(@as([*:0]u8, @ptrCast(&dir_path_buf)));
|
||||||
|
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
|
||||||
|
fba.reset();
|
||||||
|
const total_path_z = alloc.dupeZ(u8, total_path) catch unreachable; // should not exceed MAX_PATH_BYTES + 1
|
||||||
|
return open(total_path_z.ptr, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fd2path(fd: i32, buf: [*]u8, nbuf: usize) usize {
|
||||||
|
return syscall_bits.syscall3(.FD2PATH, @bitCast(@as(isize, fd)), @intFromPtr(buf), nbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(path: [*:0]const u8, omode: mode_t, perms: usize) usize {
|
||||||
|
return syscall_bits.syscall3(.CREATE, @intFromPtr(path), @bitCast(@as(isize, omode)), perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(status: u8) noreturn {
|
pub fn exit(status: u8) noreturn {
|
||||||
@ -163,16 +238,53 @@ pub fn exits(status: ?[*:0]const u8) noreturn {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(fd: usize) usize {
|
pub fn close(fd: i32) usize {
|
||||||
return syscall_bits.syscall1(.CLOSE, fd);
|
return syscall_bits.syscall1(.CLOSE, @bitCast(@as(isize, fd)));
|
||||||
}
|
}
|
||||||
pub const OpenMode = enum(usize) {
|
pub const mode_t = i32;
|
||||||
OREAD = 0, //* open for read
|
pub const O = struct {
|
||||||
OWRITE = 1, //* write
|
pub const READ = 0; // open for read
|
||||||
ORDWR = 2, //* read and write
|
pub const RDONLY = 0;
|
||||||
OEXEC = 3, //* execute, == read but check execute permission
|
pub const WRITE = 1; // write
|
||||||
OTRUNC = 16, //* or'ed in (except for exec), truncate file first
|
pub const WRONLY = 1;
|
||||||
OCEXEC = 32, //* or'ed in (per file descriptor), close on exec
|
pub const RDWR = 2; // read and write
|
||||||
ORCLOSE = 64, //* or'ed in, remove on close
|
pub const EXEC = 3; // execute, == read but check execute permission
|
||||||
OEXCL = 0x1000, //* or'ed in, exclusive create
|
pub const TRUNC = 16; // or'ed in (except for exec), truncate file first
|
||||||
|
pub const CEXEC = 32; // or'ed in (per file descriptor), close on exec
|
||||||
|
pub const RCLOSE = 64; // or'ed in, remove on close
|
||||||
|
pub const EXCL = 0x1000; // or'ed in, exclusive create
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ExecData = struct {
|
||||||
|
pub extern const etext: anyopaque;
|
||||||
|
pub extern const edata: anyopaque;
|
||||||
|
pub extern const end: anyopaque;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Brk sets the system's idea of the lowest bss location not
|
||||||
|
/// used by the program (called the break) to addr rounded up to
|
||||||
|
/// the next multiple of 8 bytes. Locations not less than addr
|
||||||
|
/// and below the stack pointer may cause a memory violation if
|
||||||
|
/// accessed. -9front brk(2)
|
||||||
|
pub fn brk_(addr: usize) i32 {
|
||||||
|
return @intCast(syscall_bits.syscall1(.BRK_, addr));
|
||||||
|
}
|
||||||
|
var bloc: usize = 0;
|
||||||
|
var bloc_max: usize = 0;
|
||||||
|
|
||||||
|
pub fn sbrk(n: usize) usize {
|
||||||
|
if (bloc == 0) {
|
||||||
|
// we are at the start
|
||||||
|
bloc = @intFromPtr(&ExecData.end);
|
||||||
|
bloc_max = @intFromPtr(&ExecData.end);
|
||||||
|
}
|
||||||
|
var bl = std.mem.alignForward(usize, bloc, std.mem.page_size);
|
||||||
|
const n_aligned = std.mem.alignForward(usize, n, std.mem.page_size);
|
||||||
|
if (bl + n_aligned > bloc_max) {
|
||||||
|
// we need to allocate
|
||||||
|
if (brk_(bl + n_aligned) < 0) return 0;
|
||||||
|
bloc_max = bl + n_aligned;
|
||||||
|
}
|
||||||
|
bloc = bloc + n_aligned;
|
||||||
|
return bl;
|
||||||
|
}
|
||||||
|
|||||||
@ -73,4 +73,12 @@ pub const E = enum(u16) {
|
|||||||
// These added in 1003.1b-1993
|
// These added in 1003.1b-1993
|
||||||
CANCELED = 61,
|
CANCELED = 61,
|
||||||
INPROGRESS = 62,
|
INPROGRESS = 62,
|
||||||
|
|
||||||
|
// We just add these to be compatible with std.os, which uses them,
|
||||||
|
// They should never get used.
|
||||||
|
DQUOT,
|
||||||
|
CONNRESET,
|
||||||
|
OVERFLOW,
|
||||||
|
LOOP,
|
||||||
|
TXTBSY,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -166,28 +166,7 @@ fn exit2(code: usize) noreturn {
|
|||||||
else => @compileError("TODO"),
|
else => @compileError("TODO"),
|
||||||
},
|
},
|
||||||
// exits(0)
|
// exits(0)
|
||||||
.plan9 => switch (builtin.cpu.arch) {
|
.plan9 => std.os.plan9.exits(null),
|
||||||
.x86_64 => {
|
|
||||||
asm volatile (
|
|
||||||
\\push $0
|
|
||||||
\\push $0
|
|
||||||
\\syscall
|
|
||||||
:
|
|
||||||
: [syscall_number] "{rbp}" (8),
|
|
||||||
: "rcx", "r11", "memory"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// TODO once we get stack setting with assembly on
|
|
||||||
// arm, exit with 0 instead of stack garbage
|
|
||||||
.aarch64 => {
|
|
||||||
asm volatile ("svc #0"
|
|
||||||
:
|
|
||||||
: [exit] "{x0}" (0x08),
|
|
||||||
: "memory", "cc"
|
|
||||||
);
|
|
||||||
},
|
|
||||||
else => @compileError("TODO"),
|
|
||||||
},
|
|
||||||
.windows => {
|
.windows => {
|
||||||
ExitProcess(@as(u32, @truncate(code)));
|
ExitProcess(@as(u32, @truncate(code)));
|
||||||
},
|
},
|
||||||
@ -254,6 +233,13 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _start() callconv(.Naked) noreturn {
|
fn _start() callconv(.Naked) noreturn {
|
||||||
|
// TODO set Top of Stack on non x86_64-plan9
|
||||||
|
if (native_os == .plan9 and native_arch == .x86_64) {
|
||||||
|
// from /sys/src/libc/amd64/main9.s
|
||||||
|
std.os.plan9.tos = asm volatile (""
|
||||||
|
: [tos] "={rax}" (-> *std.os.plan9.Tos),
|
||||||
|
);
|
||||||
|
}
|
||||||
asm volatile (switch (native_arch) {
|
asm volatile (switch (native_arch) {
|
||||||
.x86_64 =>
|
.x86_64 =>
|
||||||
\\ xorl %%ebp, %%ebp
|
\\ xorl %%ebp, %%ebp
|
||||||
|
|||||||
@ -124,7 +124,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
.target = symbol.sym_index, // we set sym_index to just be the atom index
|
.target = symbol.sym_index, // we set sym_index to just be the atom index
|
||||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||||
.addend = 0,
|
.addend = 0,
|
||||||
.pcrel = true,
|
.type = .pcrel,
|
||||||
});
|
});
|
||||||
} else return emit.fail("TODO implement linker reloc for {s}", .{
|
} else return emit.fail("TODO implement linker reloc for {s}", .{
|
||||||
@tagName(emit.bin_file.tag),
|
@tagName(emit.bin_file.tag),
|
||||||
|
|||||||
@ -100,11 +100,23 @@ syms_index_free_list: std.ArrayListUnmanaged(usize) = .{},
|
|||||||
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
||||||
decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
||||||
|
|
||||||
|
/// Indices of the three "special" symbols into atoms
|
||||||
|
etext_edata_end_atom_indices: [3]?Atom.Index = .{ null, null, null },
|
||||||
|
|
||||||
const Reloc = struct {
|
const Reloc = struct {
|
||||||
target: Atom.Index,
|
target: Atom.Index,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
addend: u32,
|
addend: u32,
|
||||||
pcrel: bool = false,
|
type: enum {
|
||||||
|
pcrel,
|
||||||
|
nonpcrel,
|
||||||
|
// for getting the value of the etext symbol; we ignore target
|
||||||
|
special_etext,
|
||||||
|
// for getting the value of the edata symbol; we ignore target
|
||||||
|
special_edata,
|
||||||
|
// for getting the value of the end symbol; we ignore target
|
||||||
|
special_end,
|
||||||
|
} = .nonpcrel,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Bases = struct {
|
const Bases = struct {
|
||||||
@ -467,15 +479,10 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
|
|||||||
pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {
|
pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !void {
|
||||||
const decl = mod.declPtr(decl_index);
|
const decl = mod.declPtr(decl_index);
|
||||||
|
|
||||||
if (decl.val.getExternFunc(mod)) |_| {
|
if (decl.isExtern(mod)) {
|
||||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
log.debug("found extern decl: {s}", .{mod.intern_pool.stringToSlice(decl.name)});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (decl.val.getVariable(mod)) |variable| {
|
|
||||||
if (variable.is_extern) {
|
|
||||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const atom_idx = try self.seeDecl(decl_index);
|
const atom_idx = try self.seeDecl(decl_index);
|
||||||
|
|
||||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn externCount(self: *Plan9) usize {
|
||||||
|
var extern_atom_count: usize = 0;
|
||||||
|
for (self.etext_edata_end_atom_indices) |idx| {
|
||||||
|
if (idx != null) extern_atom_count += 1;
|
||||||
|
}
|
||||||
|
return extern_atom_count;
|
||||||
|
}
|
||||||
// counts decls, unnamed consts, and lazy syms
|
// counts decls, unnamed consts, and lazy syms
|
||||||
fn atomCount(self: *Plan9) usize {
|
fn atomCount(self: *Plan9) usize {
|
||||||
var fn_decl_count: usize = 0;
|
var fn_decl_count: usize = 0;
|
||||||
@ -594,7 +608,8 @@ fn atomCount(self: *Plan9) usize {
|
|||||||
while (it_lazy.next()) |kv| {
|
while (it_lazy.next()) |kv| {
|
||||||
lazy_atom_count += kv.value_ptr.numberOfAtoms();
|
lazy_atom_count += kv.value_ptr.numberOfAtoms();
|
||||||
}
|
}
|
||||||
return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count;
|
const extern_atom_count = self.externCount();
|
||||||
|
return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
|
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
|
|||||||
defer self.base.allocator.free(got_table);
|
defer self.base.allocator.free(got_table);
|
||||||
|
|
||||||
// + 4 for header, got, symbols, linecountinfo
|
// + 4 for header, got, symbols, linecountinfo
|
||||||
var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4);
|
var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.atomCount() + 4 - self.externCount());
|
||||||
defer self.base.allocator.free(iovecs);
|
defer self.base.allocator.free(iovecs);
|
||||||
|
|
||||||
const file = self.base.file.?;
|
const file = self.base.file.?;
|
||||||
@ -729,8 +744,17 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
|
|||||||
self.syms.items[text_atom.sym_index.?].value = off;
|
self.syms.items[text_atom.sym_index.?].value = off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// etext symbol
|
// fix the sym for etext
|
||||||
self.syms.items[2].value = self.getAddr(text_i, .t);
|
if (self.etext_edata_end_atom_indices[0]) |etext_atom_idx| {
|
||||||
|
const etext_atom = self.getAtom(etext_atom_idx);
|
||||||
|
const val = self.getAddr(text_i, .t);
|
||||||
|
self.syms.items[etext_atom.sym_index.?].value = val;
|
||||||
|
if (!self.sixtyfour_bit) {
|
||||||
|
mem.writeInt(u32, got_table[etext_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian());
|
||||||
|
} else {
|
||||||
|
mem.writeInt(u64, got_table[etext_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian());
|
||||||
|
}
|
||||||
|
}
|
||||||
// global offset table is in data
|
// global offset table is in data
|
||||||
iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
|
iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
|
||||||
iovecs_i += 1;
|
iovecs_i += 1;
|
||||||
@ -800,15 +824,34 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
|
|||||||
self.syms.items[data_atom.sym_index.?].value = off;
|
self.syms.items[data_atom.sym_index.?].value = off;
|
||||||
}
|
}
|
||||||
// edata symbol
|
// edata symbol
|
||||||
self.syms.items[0].value = self.getAddr(data_i, .b);
|
if (self.etext_edata_end_atom_indices[1]) |edata_atom_idx| {
|
||||||
// end
|
const edata_atom = self.getAtom(edata_atom_idx);
|
||||||
self.syms.items[1].value = self.getAddr(data_i, .b);
|
const val = self.getAddr(data_i, .b);
|
||||||
|
self.syms.items[edata_atom.sym_index.?].value = val;
|
||||||
|
if (!self.sixtyfour_bit) {
|
||||||
|
mem.writeInt(u32, got_table[edata_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian());
|
||||||
|
} else {
|
||||||
|
mem.writeInt(u64, got_table[edata_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// end symbol (same as edata because native backends don't do .bss yet)
|
||||||
|
if (self.etext_edata_end_atom_indices[2]) |end_atom_idx| {
|
||||||
|
const end_atom = self.getAtom(end_atom_idx);
|
||||||
|
const val = self.getAddr(data_i, .b);
|
||||||
|
self.syms.items[end_atom.sym_index.?].value = val;
|
||||||
|
if (!self.sixtyfour_bit) {
|
||||||
|
mem.writeInt(u32, got_table[end_atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(val)), self.base.options.target.cpu.arch.endian());
|
||||||
|
} else {
|
||||||
|
log.debug("write end (got_table[0x{x}] = 0x{x})", .{ end_atom.got_index.? * 8, val });
|
||||||
|
mem.writeInt(u64, got_table[end_atom.got_index.? * 8 ..][0..8], val, self.base.options.target.cpu.arch.endian());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var sym_buf = std.ArrayList(u8).init(self.base.allocator);
|
var sym_buf = std.ArrayList(u8).init(self.base.allocator);
|
||||||
try self.writeSyms(&sym_buf);
|
try self.writeSyms(&sym_buf);
|
||||||
const syms = try sym_buf.toOwnedSlice();
|
const syms = try sym_buf.toOwnedSlice();
|
||||||
defer self.base.allocator.free(syms);
|
defer self.base.allocator.free(syms);
|
||||||
assert(2 + self.atomCount() == iovecs_i); // we didn't write all the decls
|
assert(2 + self.atomCount() - self.externCount() == iovecs_i); // we didn't write all the decls
|
||||||
iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
|
iovecs[iovecs_i] = .{ .iov_base = syms.ptr, .iov_len = syms.len };
|
||||||
iovecs_i += 1;
|
iovecs_i += 1;
|
||||||
iovecs[iovecs_i] = .{ .iov_base = linecountinfo.items.ptr, .iov_len = linecountinfo.items.len };
|
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
|
|||||||
const source_atom_index = kv.key_ptr.*;
|
const source_atom_index = kv.key_ptr.*;
|
||||||
const source_atom = self.getAtom(source_atom_index);
|
const source_atom = self.getAtom(source_atom_index);
|
||||||
const source_atom_symbol = self.syms.items[source_atom.sym_index.?];
|
const source_atom_symbol = self.syms.items[source_atom.sym_index.?];
|
||||||
|
const code = source_atom.code.getCode(self);
|
||||||
|
const endian = self.base.options.target.cpu.arch.endian();
|
||||||
for (kv.value_ptr.items) |reloc| {
|
for (kv.value_ptr.items) |reloc| {
|
||||||
|
const offset = reloc.offset;
|
||||||
|
const addend = reloc.addend;
|
||||||
|
if (reloc.type == .pcrel or reloc.type == .nonpcrel) {
|
||||||
const target_atom_index = reloc.target;
|
const target_atom_index = reloc.target;
|
||||||
const target_atom = self.getAtomPtr(target_atom_index);
|
const target_atom = self.getAtomPtr(target_atom_index);
|
||||||
const target_symbol = self.syms.items[target_atom.sym_index.?];
|
const target_symbol = self.syms.items[target_atom.sym_index.?];
|
||||||
const target_offset = target_atom.offset.?;
|
const target_offset = target_atom.offset.?;
|
||||||
|
|
||||||
const offset = reloc.offset;
|
switch (reloc.type) {
|
||||||
const addend = reloc.addend;
|
.pcrel => {
|
||||||
|
|
||||||
const code = source_atom.code.getCode(self);
|
|
||||||
|
|
||||||
if (reloc.pcrel) {
|
|
||||||
const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset));
|
const disp = @as(i32, @intCast(target_offset)) - @as(i32, @intCast(source_atom.offset.?)) - 4 - @as(i32, @intCast(offset));
|
||||||
mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), self.base.options.target.cpu.arch.endian());
|
mem.writeInt(i32, code[@as(usize, @intCast(offset))..][0..4], @as(i32, @intCast(disp)), endian);
|
||||||
} else {
|
},
|
||||||
|
.nonpcrel => {
|
||||||
if (!self.sixtyfour_bit) {
|
if (!self.sixtyfour_bit) {
|
||||||
mem.writeInt(u32, code[@as(usize, @intCast(offset))..][0..4], @as(u32, @intCast(target_offset + addend)), self.base.options.target.cpu.arch.endian());
|
mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(target_offset + addend)), endian);
|
||||||
} else {
|
} else {
|
||||||
mem.writeInt(u64, code[@as(usize, @intCast(offset))..][0..8], target_offset + addend, self.base.options.target.cpu.arch.endian());
|
mem.writeInt(u64, code[@intCast(offset)..][0..8], target_offset + addend, endian);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
else => unreachable,
|
||||||
}
|
}
|
||||||
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 });
|
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 });
|
||||||
|
} else {
|
||||||
|
const addr = switch (reloc.type) {
|
||||||
|
.special_etext => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[0].?).sym_index.?].value,
|
||||||
|
.special_edata => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[1].?).sym_index.?].value,
|
||||||
|
.special_end => self.syms.items[self.getAtom(self.etext_edata_end_atom_indices[2].?).sym_index.?].value,
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
if (!self.sixtyfour_bit) {
|
||||||
|
mem.writeInt(u32, code[@intCast(offset)..][0..4], @as(u32, @intCast(addr + addend)), endian);
|
||||||
|
} else {
|
||||||
|
mem.writeInt(u64, code[@intCast(offset)..][0..8], addr + addend, endian);
|
||||||
|
}
|
||||||
|
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 });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -983,7 +1044,24 @@ pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index {
|
|||||||
.exports = .{},
|
.exports = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return gop.value_ptr.index;
|
const atom_idx = gop.value_ptr.index;
|
||||||
|
// handle externs here because they might not get updateDecl called on them
|
||||||
|
const mod = self.base.options.module.?;
|
||||||
|
const decl = mod.declPtr(decl_index);
|
||||||
|
const name = mod.intern_pool.stringToSlice(decl.name);
|
||||||
|
if (decl.isExtern(mod)) {
|
||||||
|
// this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
|
||||||
|
if (std.mem.eql(u8, name, "etext")) {
|
||||||
|
self.etext_edata_end_atom_indices[0] = atom_idx;
|
||||||
|
} else if (std.mem.eql(u8, name, "edata")) {
|
||||||
|
self.etext_edata_end_atom_indices[1] = atom_idx;
|
||||||
|
} else if (std.mem.eql(u8, name, "end")) {
|
||||||
|
self.etext_edata_end_atom_indices[2] = atom_idx;
|
||||||
|
}
|
||||||
|
try self.updateFinish(decl_index);
|
||||||
|
log.debug("seeDecl(extern) for {s} (got_addr=0x{x})", .{ name, self.getAtom(atom_idx).getOffsetTableAddress(self) });
|
||||||
|
} else log.debug("seeDecl for {s}", .{name});
|
||||||
|
return atom_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn updateDeclExports(
|
pub fn updateDeclExports(
|
||||||
@ -1157,23 +1235,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
|
|||||||
|
|
||||||
self.bases = defaultBaseAddrs(options.target.cpu.arch);
|
self.bases = defaultBaseAddrs(options.target.cpu.arch);
|
||||||
|
|
||||||
// first 4 symbols in our table are edata, end, etext, and got
|
|
||||||
try self.syms.appendSlice(self.base.allocator, &.{
|
try self.syms.appendSlice(self.base.allocator, &.{
|
||||||
.{
|
|
||||||
.value = 0xcafebabe,
|
|
||||||
.type = .B,
|
|
||||||
.name = "edata",
|
|
||||||
},
|
|
||||||
.{
|
|
||||||
.value = 0xcafebabe,
|
|
||||||
.type = .B,
|
|
||||||
.name = "end",
|
|
||||||
},
|
|
||||||
.{
|
|
||||||
.value = 0xcafebabe,
|
|
||||||
.type = .T,
|
|
||||||
.name = "etext",
|
|
||||||
},
|
|
||||||
// we include the global offset table to make it easier for debugging
|
// we include the global offset table to make it easier for debugging
|
||||||
.{
|
.{
|
||||||
.value = self.getAddr(0, .d), // the global offset table starts at 0
|
.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 {
|
|||||||
const mod = self.base.options.module.?;
|
const mod = self.base.options.module.?;
|
||||||
const ip = &mod.intern_pool;
|
const ip = &mod.intern_pool;
|
||||||
const writer = buf.writer();
|
const writer = buf.writer();
|
||||||
// write the first four symbols (edata, etext, end, __GOT)
|
// write __GOT
|
||||||
try self.writeSym(writer, self.syms.items[0]);
|
try self.writeSym(writer, self.syms.items[0]);
|
||||||
try self.writeSym(writer, self.syms.items[1]);
|
|
||||||
try self.writeSym(writer, self.syms.items[2]);
|
|
||||||
try self.writeSym(writer, self.syms.items[3]);
|
|
||||||
// write the f symbols
|
// write the f symbols
|
||||||
{
|
{
|
||||||
var it = self.file_segments.iterator();
|
var it = self.file_segments.iterator();
|
||||||
@ -1296,6 +1355,14 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// special symbols
|
||||||
|
for (self.etext_edata_end_atom_indices) |idx| {
|
||||||
|
if (idx) |atom_idx| {
|
||||||
|
const atom = self.getAtom(atom_idx);
|
||||||
|
const sym = self.syms.items[atom.sym_index.?];
|
||||||
|
try self.writeSym(writer, sym);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Must be called only after a successful call to `updateDecl`.
|
/// Must be called only after a successful call to `updateDecl`.
|
||||||
@ -1312,26 +1379,35 @@ pub fn getDeclVAddr(
|
|||||||
) !u64 {
|
) !u64 {
|
||||||
const mod = self.base.options.module.?;
|
const mod = self.base.options.module.?;
|
||||||
const decl = mod.declPtr(decl_index);
|
const decl = mod.declPtr(decl_index);
|
||||||
// we might already know the vaddr
|
log.debug("getDeclVAddr for {s}", .{mod.intern_pool.stringToSlice(decl.name)});
|
||||||
if (decl.ty.zigTypeTag(mod) == .Fn) {
|
if (decl.isExtern(mod)) {
|
||||||
var start = self.bases.text;
|
const extern_name = mod.intern_pool.stringToSlice(decl.name);
|
||||||
var it_file = self.fn_decl_table.iterator();
|
if (std.mem.eql(u8, extern_name, "etext")) {
|
||||||
while (it_file.next()) |fentry| {
|
try self.addReloc(reloc_info.parent_atom_index, .{
|
||||||
var symidx_and_submap = fentry.value_ptr;
|
.target = undefined,
|
||||||
var submap_it = symidx_and_submap.functions.iterator();
|
.offset = reloc_info.offset,
|
||||||
while (submap_it.next()) |entry| {
|
.addend = reloc_info.addend,
|
||||||
if (entry.key_ptr.* == decl_index) return start;
|
.type = .special_etext,
|
||||||
start += entry.value_ptr.code.len;
|
});
|
||||||
}
|
} else if (std.mem.eql(u8, extern_name, "edata")) {
|
||||||
}
|
try self.addReloc(reloc_info.parent_atom_index, .{
|
||||||
} else {
|
.target = undefined,
|
||||||
var start = self.bases.data + self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
|
.offset = reloc_info.offset,
|
||||||
var it = self.data_decl_table.iterator();
|
.addend = reloc_info.addend,
|
||||||
while (it.next()) |kv| {
|
.type = .special_edata,
|
||||||
if (decl_index == kv.key_ptr.*) return start;
|
});
|
||||||
start += kv.value_ptr.len;
|
} else if (std.mem.eql(u8, extern_name, "end")) {
|
||||||
|
try self.addReloc(reloc_info.parent_atom_index, .{
|
||||||
|
.target = undefined,
|
||||||
|
.offset = reloc_info.offset,
|
||||||
|
.addend = reloc_info.addend,
|
||||||
|
.type = .special_end,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
// TODO handle other extern variables and functions
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
// otherwise, we just add a relocation
|
||||||
const atom_index = try self.seeDecl(decl_index);
|
const atom_index = try self.seeDecl(decl_index);
|
||||||
// the parent_atom_index in this case is just the decl_index of the parent
|
// the parent_atom_index in this case is just the decl_index of the parent
|
||||||
try self.addReloc(reloc_info.parent_atom_index, .{
|
try self.addReloc(reloc_info.parent_atom_index, .{
|
||||||
@ -1339,7 +1415,7 @@ pub fn getDeclVAddr(
|
|||||||
.offset = reloc_info.offset,
|
.offset = reloc_info.offset,
|
||||||
.addend = reloc_info.addend,
|
.addend = reloc_info.addend,
|
||||||
});
|
});
|
||||||
return 0xcafebabe;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {
|
pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user