aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted/link.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2020-05-01 17:35:52 -0400
committerGitHub <noreply@github.com>2020-05-01 17:35:52 -0400
commit3386bb896d071eef4ff571fac399e18b2270a382 (patch)
treec3e597506a6f5a41269acdd386fd87bd473cdaa9 /src-self-hosted/link.zig
parent94b0d0e80242563f4ad7ad41e3c0f5193a60b70c (diff)
parentec6ef86219578822fd32bbe2e5eb83b24ddfdca6 (diff)
downloadzig-3386bb896d071eef4ff571fac399e18b2270a382.tar.gz
zig-3386bb896d071eef4ff571fac399e18b2270a382.zip
Merge pull request #5192 from ziglang/stage2-tests
add ZIR compare output test case to test suite
Diffstat (limited to 'src-self-hosted/link.zig')
-rw-r--r--src-self-hosted/link.zig75
1 files changed, 54 insertions, 21 deletions
diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig
index cb6aa40afe..504c374ca7 100644
--- a/src-self-hosted/link.zig
+++ b/src-self-hosted/link.zig
@@ -7,11 +7,6 @@ const fs = std.fs;
const elf = std.elf;
const codegen = @import("codegen.zig");
-/// On common systems with a 0o022 umask, 0o777 will still result in a file created
-/// with 0o755 permissions, but it works appropriately if the system is configured
-/// more leniently. As another data point, C's fopen seems to open files with the
-/// 666 mode.
-const executable_mode = 0o777;
const default_entry_addr = 0x8000000;
pub const ErrorMsg = struct {
@@ -35,29 +30,29 @@ pub const Result = struct {
/// If incremental linking fails, falls back to truncating the file and rewriting it.
/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.
/// This operation is not atomic.
-pub fn updateExecutableFilePath(
+pub fn updateFilePath(
allocator: *Allocator,
module: ir.Module,
dir: fs.Dir,
sub_path: []const u8,
) !Result {
- const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = executable_mode });
+ const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(module) });
defer file.close();
- return updateExecutableFile(allocator, module, file);
+ return updateFile(allocator, module, file);
}
/// Atomically overwrites the old file, if present.
-pub fn writeExecutableFilePath(
+pub fn writeFilePath(
allocator: *Allocator,
module: ir.Module,
dir: fs.Dir,
sub_path: []const u8,
) !Result {
- const af = try dir.atomicFile(sub_path, .{ .mode = executable_mode });
+ const af = try dir.atomicFile(sub_path, .{ .mode = determineMode(module) });
defer af.deinit();
- const result = try writeExecutableFile(allocator, module, af.file);
+ const result = try writeFile(allocator, module, af.file);
try af.finish();
return result;
}
@@ -67,10 +62,10 @@ pub fn writeExecutableFilePath(
/// Returns an error if `file` is not already open with +read +write +seek abilities.
/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.
/// This operation is not atomic.
-pub fn updateExecutableFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
- return updateExecutableFileInner(allocator, module, file) catch |err| switch (err) {
+pub fn updateFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
+ return updateFileInner(allocator, module, file) catch |err| switch (err) {
error.IncrFailed => {
- return writeExecutableFile(allocator, module, file);
+ return writeFile(allocator, module, file);
},
else => |e| return e,
};
@@ -436,7 +431,7 @@ const Update = struct {
},
}
}
- if (self.entry_addr == null) {
+ if (self.entry_addr == null and self.module.output_mode == .Exe) {
const msg = try std.fmt.allocPrint(self.errors.allocator, "no entry point found", .{});
errdefer self.errors.allocator.free(msg);
try self.errors.append(.{
@@ -485,7 +480,15 @@ const Update = struct {
assert(index == 16);
- mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf.ET.EXEC), endian);
+ const elf_type = switch (self.module.output_mode) {
+ .Exe => elf.ET.EXEC,
+ .Obj => elf.ET.REL,
+ .Lib => switch (self.module.link_mode) {
+ .Static => elf.ET.REL,
+ .Dynamic => elf.ET.DYN,
+ },
+ };
+ mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
index += 2;
const machine = self.module.target.cpu.arch.toElfMachine();
@@ -496,10 +499,11 @@ const Update = struct {
mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
index += 4;
+ const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
+
switch (ptr_width) {
.p32 => {
- // e_entry
- mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, self.entry_addr.?), endian);
+ mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
index += 4;
// e_phoff
@@ -512,7 +516,7 @@ const Update = struct {
},
.p64 => {
// e_entry
- mem.writeInt(u64, hdr_buf[index..][0..8], self.entry_addr.?, endian);
+ mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
index += 8;
// e_phoff
@@ -750,7 +754,20 @@ const Update = struct {
/// Truncates the existing file contents and overwrites the contents.
/// Returns an error if `file` is not already open with +read +write +seek abilities.
-pub fn writeExecutableFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
+pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
+ switch (module.output_mode) {
+ .Exe => {},
+ .Obj => {},
+ .Lib => return error.TODOImplementWritingLibFiles,
+ }
+ switch (module.object_format) {
+ .unknown => unreachable, // TODO remove this tag from the enum
+ .coff => return error.TODOImplementWritingCOFF,
+ .elf => {},
+ .macho => return error.TODOImplementWritingMachO,
+ .wasm => return error.TODOImplementWritingWasmObjects,
+ }
+
var update = Update{
.file = file,
.module = &module,
@@ -778,7 +795,7 @@ pub fn writeExecutableFile(allocator: *Allocator, module: ir.Module, file: fs.Fi
}
/// Returns error.IncrFailed if incremental update could not be performed.
-fn updateExecutableFileInner(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
+fn updateFileInner(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {
//var ehdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
// TODO implement incremental linking
@@ -822,3 +839,19 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
.sh_entsize = @intCast(u32, shdr.sh_entsize),
};
}
+
+fn determineMode(module: ir.Module) fs.File.Mode {
+ // On common systems with a 0o022 umask, 0o777 will still result in a file created
+ // with 0o755 permissions, but it works appropriately if the system is configured
+ // more leniently. As another data point, C's fopen seems to open files with the
+ // 666 mode.
+ const executable_mode = if (std.Target.current.os.tag == .windows) 0 else 0o777;
+ switch (module.output_mode) {
+ .Lib => return switch (module.link_mode) {
+ .Dynamic => executable_mode,
+ .Static => fs.File.default_mode,
+ },
+ .Exe => return executable_mode,
+ .Obj => return fs.File.default_mode,
+ }
+}