Commit 6123201f06
Changed files (2)
src-self-hosted
src-self-hosted/link.zig
@@ -33,102 +33,27 @@ pub const Options = struct {
program_code_size_hint: u64 = 256 * 1024,
};
-/// Attempts incremental linking, if the file already exists.
-/// 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 openBinFilePath(
- allocator: *Allocator,
- dir: fs.Dir,
- sub_path: []const u8,
- options: Options,
-) !*File {
- const cbe = options.object_format == .c;
- const file = try dir.createFile(sub_path, .{ .truncate = cbe, .read = true, .mode = determineMode(options) });
- errdefer file.close();
-
- if (cbe) {
- var bin_file = try allocator.create(File.C);
- errdefer allocator.destroy(bin_file);
- bin_file.* = try openCFile(allocator, file, options);
- return &bin_file.base;
- } else {
- var bin_file = try allocator.create(File.Elf);
- errdefer allocator.destroy(bin_file);
- bin_file.* = try openBinFile(allocator, file, options);
- bin_file.owns_file_handle = true;
- return &bin_file.base;
- }
-}
-
-/// Atomically overwrites the old file, if present.
-pub fn writeFilePath(
- allocator: *Allocator,
- dir: fs.Dir,
- sub_path: []const u8,
- module: Module,
- errors: *std.ArrayList(Module.ErrorMsg),
-) !void {
- const options: Options = .{
- .target = module.target,
- .output_mode = module.output_mode,
- .link_mode = module.link_mode,
- .object_format = module.object_format,
- .symbol_count_hint = module.decls.items.len,
- .optimize_mode = module.optimize_mode,
- };
- const af = try dir.atomicFile(sub_path, .{ .mode = determineMode(options) });
- defer af.deinit();
-
- const elf_file = try createElfFile(allocator, af.file, options);
- for (module.decls.items) |decl| {
- try elf_file.updateDecl(module, decl, errors);
- }
- try elf_file.flush();
- if (elf_file.error_flags.no_entry_point_found) {
- try errors.ensureCapacity(errors.items.len + 1);
- errors.appendAssumeCapacity(.{
- .byte_offset = 0,
- .msg = try std.fmt.allocPrint(errors.allocator, "no entry point found", .{}),
- });
- }
- try af.finish();
- return result;
-}
-
-fn openCFile(allocator: *Allocator, file: fs.File, options: Options) !File.C {
- return File.C{
- .base = .{
- .tag = .c,
- .options = options,
- },
- .allocator = allocator,
- .file = file,
- .main = std.ArrayList(u8).init(allocator),
- .header = std.ArrayList(u8).init(allocator),
- .constants = std.ArrayList(u8).init(allocator),
- .called = std.StringHashMap(void).init(allocator),
- };
-}
-
-/// Attempts incremental linking, if the file already exists.
-/// If incremental linking fails, falls back to truncating the file and rewriting it.
-/// 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 openBinFile(allocator: *Allocator, file: fs.File, options: Options) !File.Elf {
- return openBinFileInner(allocator, file, options) catch |err| switch (err) {
- error.IncrFailed => {
- return createElfFile(allocator, file, options);
- },
- else => |e| return e,
- };
-}
-
pub const File = struct {
tag: Tag,
options: Options,
+ /// Attempts incremental linking, if the file already exists. 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 openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
+ switch (options.object_format) {
+ .unknown => unreachable,
+ .coff => return error.TODOImplementCoff,
+ .elf => return Elf.openPath(allocator, dir, sub_path, options),
+ .macho => return error.TODOImplementMacho,
+ .wasm => return error.TODOImplementWasm,
+ .c => return C.openPath(allocator, dir, sub_path, options),
+ .hex => return error.TODOImplementHex,
+ .raw => return error.TODOImplementRaw,
+ }
+ }
+
pub fn cast(base: *File, comptime T: type) ?*T {
if (base.tag != T.base_tag)
return null;
@@ -248,6 +173,31 @@ pub const File = struct {
need_noreturn: bool = false,
error_msg: *Module.ErrorMsg = undefined,
+ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
+ assert(options.object_format == .c);
+
+ const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = determineMode(options) });
+ errdefer file.close();
+
+ var c_file = try allocator.create(C);
+ errdefer allocator.destroy(c_file);
+
+ c_file.* = File.C{
+ .base = .{
+ .tag = .c,
+ .options = options,
+ },
+ .allocator = allocator,
+ .file = file,
+ .main = std.ArrayList(u8).init(allocator),
+ .header = std.ArrayList(u8).init(allocator),
+ .constants = std.ArrayList(u8).init(allocator),
+ .called = std.StringHashMap(void).init(allocator),
+ };
+
+ return &c_file.base;
+ }
+
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) !void {
self.error_msg = try Module.ErrorMsg.create(self.allocator, src, format, args);
return error.CGenFailure;
@@ -452,6 +402,107 @@ pub const File = struct {
sym_index: ?u32 = null,
};
+ pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: Options) !*File {
+ assert(options.object_format == .elf);
+
+ const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
+ errdefer file.close();
+
+ var elf_file = try allocator.create(Elf);
+ errdefer allocator.destroy(elf_file);
+
+ elf_file.* = openFile(allocator, file, options) catch |err| switch (err) {
+ error.IncrFailed => try createFile(allocator, file, options),
+ else => |e| return e,
+ };
+
+ elf_file.owns_file_handle = true;
+ return &elf_file.base;
+ }
+
+ /// Returns error.IncrFailed if incremental update could not be performed.
+ fn openFile(allocator: *Allocator, file: fs.File, options: Options) !Elf {
+ switch (options.output_mode) {
+ .Exe => {},
+ .Obj => {},
+ .Lib => return error.IncrFailed,
+ }
+ var self: Elf = .{
+ .base = .{
+ .tag = .elf,
+ .options = options,
+ },
+ .allocator = allocator,
+ .file = file,
+ .owns_file_handle = false,
+ .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
+ 32 => .p32,
+ 64 => .p64,
+ else => return error.UnsupportedELFArchitecture,
+ },
+ };
+ errdefer self.deinit();
+
+ // TODO implement reading the elf file
+ return error.IncrFailed;
+ //try self.populateMissingMetadata();
+ //return self;
+ }
+
+ /// Truncates the existing file contents and overwrites the contents.
+ /// Returns an error if `file` is not already open with +read +write +seek abilities.
+ fn createFile(allocator: *Allocator, file: fs.File, options: Options) !Elf {
+ switch (options.output_mode) {
+ .Exe => {},
+ .Obj => {},
+ .Lib => return error.TODOImplementWritingLibFiles,
+ }
+ var self: Elf = .{
+ .base = .{
+ .tag = .elf,
+ .options = options,
+ },
+ .allocator = allocator,
+ .file = file,
+ .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
+ 32 => .p32,
+ 64 => .p64,
+ else => return error.UnsupportedELFArchitecture,
+ },
+ .shdr_table_dirty = true,
+ .owns_file_handle = false,
+ };
+ errdefer self.deinit();
+
+ // Index 0 is always a null symbol.
+ try self.local_symbols.append(allocator, .{
+ .st_name = 0,
+ .st_info = 0,
+ .st_other = 0,
+ .st_shndx = 0,
+ .st_value = 0,
+ .st_size = 0,
+ });
+
+ // There must always be a null section in index 0
+ try self.sections.append(allocator, .{
+ .sh_name = 0,
+ .sh_type = elf.SHT_NULL,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = 0,
+ .sh_size = 0,
+ .sh_link = 0,
+ .sh_info = 0,
+ .sh_addralign = 0,
+ .sh_entsize = 0,
+ });
+
+ try self.populateMissingMetadata();
+
+ return self;
+ }
+
pub fn deinit(self: *Elf) void {
self.sections.deinit(self.allocator);
self.program_headers.deinit(self.allocator);
@@ -1939,110 +1990,6 @@ pub const File = 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 createElfFile(allocator: *Allocator, file: fs.File, options: Options) !File.Elf {
- switch (options.output_mode) {
- .Exe => {},
- .Obj => {},
- .Lib => return error.TODOImplementWritingLibFiles,
- }
- switch (options.object_format) {
- .c => unreachable,
- .unknown => unreachable, // TODO remove this tag from the enum
- .coff => return error.TODOImplementWritingCOFF,
- .elf => {},
- .macho => return error.TODOImplementWritingMachO,
- .wasm => return error.TODOImplementWritingWasmObjects,
- .hex => return error.TODOImplementWritingHex,
- .raw => return error.TODOImplementWritingRaw,
- }
-
- var self: File.Elf = .{
- .base = .{
- .tag = .elf,
- .options = options,
- },
- .allocator = allocator,
- .file = file,
- .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
- 32 => .p32,
- 64 => .p64,
- else => return error.UnsupportedELFArchitecture,
- },
- .shdr_table_dirty = true,
- .owns_file_handle = false,
- };
- errdefer self.deinit();
-
- // Index 0 is always a null symbol.
- try self.local_symbols.append(allocator, .{
- .st_name = 0,
- .st_info = 0,
- .st_other = 0,
- .st_shndx = 0,
- .st_value = 0,
- .st_size = 0,
- });
-
- // There must always be a null section in index 0
- try self.sections.append(allocator, .{
- .sh_name = 0,
- .sh_type = elf.SHT_NULL,
- .sh_flags = 0,
- .sh_addr = 0,
- .sh_offset = 0,
- .sh_size = 0,
- .sh_link = 0,
- .sh_info = 0,
- .sh_addralign = 0,
- .sh_entsize = 0,
- });
-
- try self.populateMissingMetadata();
-
- return self;
-}
-
-/// Returns error.IncrFailed if incremental update could not be performed.
-fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !File.Elf {
- switch (options.output_mode) {
- .Exe => {},
- .Obj => {},
- .Lib => return error.IncrFailed,
- }
- switch (options.object_format) {
- .unknown => unreachable, // TODO remove this tag from the enum
- .c => unreachable,
- .coff => return error.IncrFailed,
- .elf => {},
- .macho => return error.IncrFailed,
- .wasm => return error.IncrFailed,
- .hex => return error.IncrFailed,
- .raw => return error.IncrFailed,
- }
- var self: File.Elf = .{
- .base = .{
- .tag = .elf,
- .options = options,
- },
- .allocator = allocator,
- .file = file,
- .owns_file_handle = false,
- .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
- 32 => .p32,
- 64 => .p64,
- else => return error.UnsupportedELFArchitecture,
- },
- };
- errdefer self.deinit();
-
- // TODO implement reading the elf file
- return error.IncrFailed;
- //try self.populateMissingMetadata();
- //return self;
-}
-
/// Saturating multiplication
fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
const T = @TypeOf(a, b);
src-self-hosted/Module.zig
@@ -790,7 +790,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
errdefer gpa.free(root_name);
const bin_file_dir = options.bin_file_dir orelse std.fs.cwd();
- const bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{
+ const bin_file = try link.File.openPath(gpa, bin_file_dir, options.bin_file_path, .{
.root_name = root_name,
.root_src_dir_path = options.root_pkg.root_src_dir_path,
.target = options.target,