PATH lookup #1
@@ -26,6 +26,8 @@ zig build
|
|||||||
Alternatively use something like this to run directly:
|
Alternatively use something like this to run directly:
|
||||||
```sh
|
```sh
|
||||||
zig build run -- /bin/ls
|
zig build run -- /bin/ls
|
||||||
|
# or
|
||||||
|
zig build run -- ls
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs the tests:
|
This runs the tests:
|
||||||
@@ -44,6 +46,10 @@ passed through to the target executable.
|
|||||||
# Run a test executable that prints its arguments
|
# Run a test executable that prints its arguments
|
||||||
./zig-out/bin/loader ./zig-out/bin/test_nolibc_pie_printArgs foo bar baz
|
./zig-out/bin/loader ./zig-out/bin/test_nolibc_pie_printArgs foo bar baz
|
||||||
# Output: ./zig-out/bin/test_nolibc_pie_printArgs foo bar baz
|
# Output: ./zig-out/bin/test_nolibc_pie_printArgs foo bar baz
|
||||||
|
|
||||||
|
# Run echo
|
||||||
|
./zig-out/bin/loader echo Hello There
|
||||||
|
# Output: Hello There
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|||||||
36
src/main.zig
36
src/main.zig
@@ -39,12 +39,8 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe search for the file in PATH
|
|
||||||
// Map file into memory
|
// Map file into memory
|
||||||
const file = try std.fs.cwd().openFile(
|
const file = try lookupFile(mem.sliceTo(std.os.argv[arg_index], 0));
|
||||||
mem.sliceTo(std.os.argv[arg_index], 0),
|
|
||||||
.{ .mode = .read_only },
|
|
||||||
);
|
|
||||||
var buffer: [128]u8 = undefined;
|
var buffer: [128]u8 = undefined;
|
||||||
var file_reader = file.reader(&buffer);
|
var file_reader = file.reader(&buffer);
|
||||||
log.info("--- Loading executable: {s} ---", .{std.os.argv[arg_index]});
|
log.info("--- Loading executable: {s} ---", .{std.os.argv[arg_index]});
|
||||||
@@ -73,13 +69,15 @@ pub fn main() !void {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// We don't need the file anymore. But we reuse the buffer if we need to load the interpreter.
|
// We don't need the file anymore. But we reuse the buffer if we need to load the interpreter.
|
||||||
// Therefore deinit everything.
|
// Therefore deinit everything to make sure we don't use it anymore.
|
||||||
file_reader = undefined;
|
file_reader = undefined;
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
var maybe_interp_base: ?usize = null;
|
var maybe_interp_base: ?usize = null;
|
||||||
var maybe_interp_entry: ?usize = null;
|
var maybe_interp_entry: ?usize = null;
|
||||||
if (maybe_interp) |interp| {
|
if (maybe_interp) |interp| {
|
||||||
|
// TODO: If we have an interpreter we could/should unload the elf file because it will be
|
||||||
|
// loaded by the dynamic linker anyway.
|
||||||
log.info("--- Loading interpreter ---", .{});
|
log.info("--- Loading interpreter ---", .{});
|
||||||
var interp_reader = interp.reader(&buffer);
|
var interp_reader = interp.reader(&buffer);
|
||||||
const interp_ehdr = try elf.Header.read(&interp_reader.interface);
|
const interp_ehdr = try elf.Header.read(&interp_reader.interface);
|
||||||
@@ -221,6 +219,32 @@ fn elfToMmapProt(elf_prot: u64) u32 {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Opens the file by either opening via a (absolute or relative) path or searching through `PATH`
|
||||||
|
/// for a file with the name.
|
||||||
|
fn lookupFile(path_or_name: []const u8) !std.fs.File {
|
||||||
|
// If filename contains a slash ("/"), then it is interpreted as a pathname.
|
||||||
|
if (std.mem.indexOfScalarPos(u8, path_or_name, 0, '/')) |_| {
|
||||||
|
const fd = try posix.open(path_or_name, .{ .ACCMODE = .RDONLY, .CLOEXEC = true }, 0);
|
||||||
|
return .{ .handle = fd };
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it has no slash we need to look it up in PATH.
|
||||||
|
if (posix.getenvZ("PATH")) |env_path| {
|
||||||
|
var paths = std.mem.tokenizeScalar(u8, env_path, ':');
|
||||||
|
while (paths.next()) |p| {
|
||||||
|
var dir = std.fs.openDirAbsolute(p, .{}) catch continue;
|
||||||
|
defer dir.close();
|
||||||
|
const fd = posix.openat(dir.fd, path_or_name, .{
|
||||||
|
.ACCMODE = .RDONLY,
|
||||||
|
.CLOEXEC = true,
|
||||||
|
}, 0) catch continue;
|
||||||
|
return .{ .handle = fd };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.FileNotFound;
|
||||||
|
}
|
||||||
|
|
||||||
/// This function performs the final jump into the loaded program (amd64)
|
/// This function performs the final jump into the loaded program (amd64)
|
||||||
// TODO: support more architectures
|
// TODO: support more architectures
|
||||||
fn trampoline(entry: usize, sp: [*]usize) noreturn {
|
fn trampoline(entry: usize, sp: [*]usize) noreturn {
|
||||||
|
|||||||
Reference in New Issue
Block a user