authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-16 15:44:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-16 15:44:20-04:00
log017ecc5148da3f3f50f5666d635c22dfb6bfffb2
tree8705593aa531877e839b0aabe963789273c16cd4
parentb0375978ba54bc80c691eaf118f3a78e7f8920a7

self hosted repl: close executables between updates

This allows the executable to be executed

3 files changed, 65 insertions(+), 24 deletions(-)

src-self-hosted/Module.zig+17-1
......@@ -23,6 +23,8 @@ root_pkg: *Package,
2323/// Module owns this resource.
2424root_scope: *Scope.ZIRModule,
2525bin_file: link.ElfFile,
26bin_file_dir: std.fs.Dir,
27bin_file_path: []const u8,
2628/// It's rare for a decl to be exported, so we save memory by having a sparse map of
2729/// Decl pointers to details about them being exported.
2830/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
......@@ -456,6 +458,8 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
456458 .allocator = gpa,
457459 .root_pkg = options.root_pkg,
458460 .root_scope = root_scope,
461 .bin_file_dir = bin_file_dir,
462 .bin_file_path = options.bin_file_path,
459463 .bin_file = bin_file,
460464 .optimize_mode = options.optimize_mode,
461465 .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(gpa),
......@@ -551,6 +555,18 @@ pub fn update(self: *Module) !void {
551555 self.link_error_flags = self.bin_file.error_flags;
552556}
553557
558/// Having the file open for writing is problematic as far as executing the
559/// binary is concerned. This will remove the write flag, or close the file,
560/// or whatever is needed so that it can be executed.
561/// After this, one must call` makeFileWritable` before calling `update`.
562pub fn makeBinFileExecutable(self: *Module) !void {
563 return self.bin_file.makeExecutable();
564}
565
566pub fn makeBinFileWritable(self: *Module) !void {
567 return self.bin_file.makeWritable(self.bin_file_dir, self.bin_file_path);
568}
569
554570pub fn totalErrorCount(self: *Module) usize {
555571 return self.failed_decls.size +
556572 self.failed_files.size +
......@@ -759,7 +775,7 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
759775 const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
760776 if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {
761777 // TODO recursive dependency management
762 std.debug.warn("noticed that '{}' changed\n", .{src_decl.name});
778 //std.debug.warn("noticed that '{}' changed\n", .{src_decl.name});
763779 self.decl_table.removeAssertDiscard(name_hash);
764780 const saved_link = decl.link;
765781 decl.destroy(self.allocator);
src-self-hosted/link.zig+42-23
......@@ -91,7 +91,7 @@ pub fn openBinFile(allocator: *Allocator, file: fs.File, options: Options) !ElfF
9191
9292pub const ElfFile = struct {
9393 allocator: *Allocator,
94 file: fs.File,
94 file: ?fs.File,
9595 owns_file_handle: bool,
9696 options: Options,
9797 ptr_width: enum { p32, p64 },
......@@ -170,8 +170,27 @@ pub const ElfFile = struct {
170170 self.local_symbols.deinit(self.allocator);
171171 self.global_symbols.deinit(self.allocator);
172172 self.offset_table.deinit(self.allocator);
173 if (self.owns_file_handle)
174 self.file.close();
173 if (self.owns_file_handle) {
174 if (self.file) |f| f.close();
175 }
176 }
177
178 pub fn makeExecutable(self: *ElfFile) !void {
179 assert(self.owns_file_handle);
180 if (self.file) |f| {
181 f.close();
182 self.file = null;
183 }
184 }
185
186 pub fn makeWritable(self: *ElfFile, dir: fs.Dir, sub_path: []const u8) !void {
187 assert(self.owns_file_handle);
188 if (self.file != null) return;
189 self.file = try dir.createFile(sub_path, .{
190 .truncate = false,
191 .read = true,
192 .mode = determineMode(self.options),
193 });
175194 }
176195
177196 // `alloc_num / alloc_den` is the factor of padding when allocation
......@@ -467,7 +486,7 @@ pub const ElfFile = struct {
467486 bswapAllFields(elf.Elf32_Phdr, phdr);
468487 }
469488 }
470 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
489 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
471490 },
472491 .p64 => {
473492 const buf = try self.allocator.alloc(elf.Elf64_Phdr, self.program_headers.items.len);
......@@ -479,7 +498,7 @@ pub const ElfFile = struct {
479498 bswapAllFields(elf.Elf64_Phdr, phdr);
480499 }
481500 }
482 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
501 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
483502 },
484503 }
485504 self.phdr_table_dirty = false;
......@@ -498,7 +517,7 @@ pub const ElfFile = struct {
498517 shstrtab_sect.sh_size = needed_size;
499518 //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
500519
501 try self.file.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
520 try self.file.?.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
502521 if (!self.shdr_table_dirty) {
503522 // Then it won't get written with the others and we need to do it.
504523 try self.writeSectHeader(self.shstrtab_index.?);
......@@ -534,7 +553,7 @@ pub const ElfFile = struct {
534553 bswapAllFields(elf.Elf32_Shdr, shdr);
535554 }
536555 }
537 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
556 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
538557 },
539558 .p64 => {
540559 const buf = try self.allocator.alloc(elf.Elf64_Shdr, self.sections.items.len);
......@@ -547,7 +566,7 @@ pub const ElfFile = struct {
547566 bswapAllFields(elf.Elf64_Shdr, shdr);
548567 }
549568 }
550 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
569 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
551570 },
552571 }
553572 self.shdr_table_dirty = false;
......@@ -687,7 +706,7 @@ pub const ElfFile = struct {
687706
688707 assert(index == e_ehsize);
689708
690 try self.file.pwriteAll(hdr_buf[0..index], 0);
709 try self.file.?.pwriteAll(hdr_buf[0..index], 0);
691710 }
692711
693712 const AllocatedBlock = struct {
......@@ -718,7 +737,7 @@ pub const ElfFile = struct {
718737 // Must move the entire text section.
719738 const new_offset = self.findFreeSpace(needed_size, 0x1000);
720739 const text_size = (last_start + last_size) - phdr.p_vaddr;
721 const amt = try self.file.copyRangeAll(shdr.sh_offset, self.file, new_offset, text_size);
740 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);
722741 if (amt != text_size) return error.InputOutput;
723742 shdr.sh_offset = new_offset;
724743 }
......@@ -876,7 +895,7 @@ pub const ElfFile = struct {
876895 }
877896 };
878897
879 try self.file.pwriteAll(code, file_offset);
898 try self.file.?.pwriteAll(code, file_offset);
880899
881900 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
882901 const decl_exports = module.decl_exports.getValue(decl) orelse &[0]*Module.Export{};
......@@ -962,14 +981,14 @@ pub const ElfFile = struct {
962981 if (foreign_endian) {
963982 bswapAllFields(elf.Elf32_Phdr, &phdr[0]);
964983 }
965 return self.file.pwriteAll(mem.sliceAsBytes(&phdr), offset);
984 return self.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
966985 },
967986 64 => {
968987 var phdr = [1]elf.Elf64_Phdr{self.program_headers.items[index]};
969988 if (foreign_endian) {
970989 bswapAllFields(elf.Elf64_Phdr, &phdr[0]);
971990 }
972 return self.file.pwriteAll(mem.sliceAsBytes(&phdr), offset);
991 return self.file.?.pwriteAll(mem.sliceAsBytes(&phdr), offset);
973992 },
974993 else => return error.UnsupportedArchitecture,
975994 }
......@@ -985,14 +1004,14 @@ pub const ElfFile = struct {
9851004 if (foreign_endian) {
9861005 bswapAllFields(elf.Elf32_Shdr, &shdr[0]);
9871006 }
988 return self.file.pwriteAll(mem.sliceAsBytes(&shdr), offset);
1007 return self.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
9891008 },
9901009 64 => {
9911010 var shdr = [1]elf.Elf64_Shdr{self.sections.items[index]};
9921011 if (foreign_endian) {
9931012 bswapAllFields(elf.Elf64_Shdr, &shdr[0]);
9941013 }
995 return self.file.pwriteAll(mem.sliceAsBytes(&shdr), offset);
1014 return self.file.?.pwriteAll(mem.sliceAsBytes(&shdr), offset);
9961015 },
9971016 else => return error.UnsupportedArchitecture,
9981017 }
......@@ -1012,7 +1031,7 @@ pub const ElfFile = struct {
10121031 if (needed_size > allocated_size) {
10131032 // Must move the entire got section.
10141033 const new_offset = self.findFreeSpace(needed_size, entry_size);
1015 const amt = try self.file.copyRangeAll(shdr.sh_offset, self.file, new_offset, shdr.sh_size);
1034 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
10161035 if (amt != shdr.sh_size) return error.InputOutput;
10171036 shdr.sh_offset = new_offset;
10181037 }
......@@ -1031,12 +1050,12 @@ pub const ElfFile = struct {
10311050 .p32 => {
10321051 var buf: [4]u8 = undefined;
10331052 mem.writeInt(u32, &buf, @intCast(u32, self.offset_table.items[index]), endian);
1034 try self.file.pwriteAll(&buf, off);
1053 try self.file.?.pwriteAll(&buf, off);
10351054 },
10361055 .p64 => {
10371056 var buf: [8]u8 = undefined;
10381057 mem.writeInt(u64, &buf, self.offset_table.items[index], endian);
1039 try self.file.pwriteAll(&buf, off);
1058 try self.file.?.pwriteAll(&buf, off);
10401059 },
10411060 }
10421061 }
......@@ -1059,7 +1078,7 @@ pub const ElfFile = struct {
10591078 // Move all the symbols to a new file location.
10601079 const new_offset = self.findFreeSpace(needed_size, sym_align);
10611080 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
1062 const amt = try self.file.copyRangeAll(syms_sect.sh_offset, self.file, new_offset, existing_size);
1081 const amt = try self.file.?.copyRangeAll(syms_sect.sh_offset, self.file.?, new_offset, existing_size);
10631082 if (amt != existing_size) return error.InputOutput;
10641083 syms_sect.sh_offset = new_offset;
10651084 }
......@@ -1084,7 +1103,7 @@ pub const ElfFile = struct {
10841103 bswapAllFields(elf.Elf32_Sym, &sym[0]);
10851104 }
10861105 const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index;
1087 try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
1106 try self.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
10881107 },
10891108 .p64 => {
10901109 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
......@@ -1092,7 +1111,7 @@ pub const ElfFile = struct {
10921111 bswapAllFields(elf.Elf64_Sym, &sym[0]);
10931112 }
10941113 const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index;
1095 try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
1114 try self.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
10961115 },
10971116 }
10981117 }
......@@ -1124,7 +1143,7 @@ pub const ElfFile = struct {
11241143 bswapAllFields(elf.Elf32_Sym, sym);
11251144 }
11261145 }
1127 try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
1146 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
11281147 },
11291148 .p64 => {
11301149 const buf = try self.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
......@@ -1143,7 +1162,7 @@ pub const ElfFile = struct {
11431162 bswapAllFields(elf.Elf64_Sym, sym);
11441163 }
11451164 }
1146 try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
1165 try self.file.?.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
11471166 },
11481167 }
11491168 }
src-self-hosted/main.zig+6
......@@ -447,11 +447,17 @@ fn buildOutputType(
447447
448448 while (watch) {
449449 try stderr.print("🦎 ", .{});
450 if (output_mode == .Exe) {
451 try module.makeBinFileExecutable();
452 }
450453 if (stdin.readUntilDelimiterOrEof(&repl_buf, '\n') catch |err| {
451454 try stderr.print("\nUnable to parse command: {}\n", .{@errorName(err)});
452455 continue;
453456 }) |line| {
454457 if (mem.eql(u8, line, "update")) {
458 if (output_mode == .Exe) {
459 try module.makeBinFileWritable();
460 }
455461 try updateModule(gpa, &module, zir_out_path);
456462 } else if (mem.eql(u8, line, "exit")) {
457463 break;