authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-15 01:22:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-15 01:22:04-04:00
logebb81ebe59d56a2ccb104e100b9c96df82eedc97
treeb58694f89da99e9a78c7e470bd2affb4f141fdf5
parent81a01bd4815779ebeb5898a825bf91628b75ff47

fix the global offset table code and updating decl exports


4 files changed, 249 insertions(+), 61 deletions(-)

src-self-hosted/codegen.zig+57-21
...@@ -33,6 +33,7 @@ pub fn generateSymbol(...@@ -33,6 +33,7 @@ pub fn generateSymbol(
3333
34 var function = Function{34 var function = Function{
35 .target = &bin_file.options.target,35 .target = &bin_file.options.target,
36 .bin_file = bin_file,
36 .mod_fn = module_fn,37 .mod_fn = module_fn,
37 .code = code,38 .code = code,
38 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),39 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),
...@@ -144,6 +145,7 @@ pub fn generateSymbol(...@@ -144,6 +145,7 @@ pub fn generateSymbol(
144}145}
145146
146const Function = struct {147const Function = struct {
148 bin_file: *link.ElfFile,
147 target: *const std.Target,149 target: *const std.Target,
148 mod_fn: *const ir.Module.Fn,150 mod_fn: *const ir.Module.Fn,
149 code: *std.ArrayList(u8),151 code: *std.ArrayList(u8),
...@@ -160,6 +162,8 @@ const Function = struct {...@@ -160,6 +162,8 @@ const Function = struct {
160 /// The value is in a target-specific register. The value can162 /// The value is in a target-specific register. The value can
161 /// be @intToEnum casted to the respective Reg enum.163 /// be @intToEnum casted to the respective Reg enum.
162 register: usize,164 register: usize,
165 /// The value is in memory at a hard-coded address.
166 memory: u64,
163 };167 };
164168
165 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {169 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
...@@ -375,6 +379,7 @@ const Function = struct {...@@ -375,6 +379,7 @@ const Function = struct {
375 },379 },
376 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rax = embedded_in_code", .{}),380 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rax = embedded_in_code", .{}),
377 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rax = register", .{}),381 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rax = register", .{}),
382 .memory => return self.fail(src, "TODO implement x86_64 genSetReg %rax = memory", .{}),
378 },383 },
379 .rdx => switch (mcv) {384 .rdx => switch (mcv) {
380 .none, .unreach => unreachable,385 .none, .unreach => unreachable,
...@@ -406,6 +411,7 @@ const Function = struct {...@@ -406,6 +411,7 @@ const Function = struct {
406 },411 },
407 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = embedded_in_code", .{}),412 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = embedded_in_code", .{}),
408 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = register", .{}),413 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = register", .{}),
414 .memory => return self.fail(src, "TODO implement x86_64 genSetReg %rdx = memory", .{}),
409 },415 },
410 .rdi => switch (mcv) {416 .rdi => switch (mcv) {
411 .none, .unreach => unreachable,417 .none, .unreach => unreachable,
...@@ -437,10 +443,37 @@ const Function = struct {...@@ -437,10 +443,37 @@ const Function = struct {
437 },443 },
438 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = embedded_in_code", .{}),444 .embedded_in_code => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = embedded_in_code", .{}),
439 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = register", .{}),445 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = register", .{}),
446 .memory => return self.fail(src, "TODO implement x86_64 genSetReg %rdi = memory", .{}),
440 },447 },
441 .rsi => switch (mcv) {448 .rsi => switch (mcv) {
442 .none, .unreach => unreachable,449 .none, .unreach => unreachable,
443 .immediate => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = immediate", .{}),450 .immediate => |x| {
451 // Setting the edi register zeroes the upper part of rdi, so if the number is small
452 // enough, that is preferable.
453 // Best case: zero
454 // 31 f6 xor esi,esi
455 if (x == 0) {
456 return self.code.appendSlice(&[_]u8{ 0x31, 0xf6 });
457 }
458 // Next best case: set esi with 4 bytes
459 // be 40 30 20 10 mov esi,0x10203040
460 if (x <= std.math.maxInt(u32)) {
461 try self.code.resize(self.code.items.len + 5);
462 self.code.items[self.code.items.len - 5] = 0xbe;
463 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
464 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));
465 return;
466 }
467 // Worst case: set rsi with 8 bytes
468 // 48 be 80 70 60 50 40 30 20 10 movabs rsi,0x1020304050607080
469
470 try self.code.resize(self.code.items.len + 10);
471 self.code.items[self.code.items.len - 10] = 0x48;
472 self.code.items[self.code.items.len - 9] = 0xbe;
473 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];
474 mem.writeIntLittle(u64, imm_ptr, x);
475 return;
476 },
444 .embedded_in_code => |code_offset| {477 .embedded_in_code => |code_offset| {
445 // Examples:478 // Examples:
446 // lea rsi, [rip + 0x01020304]479 // lea rsi, [rip + 0x01020304]
...@@ -462,6 +495,21 @@ const Function = struct {...@@ -462,6 +495,21 @@ const Function = struct {
462 return;495 return;
463 },496 },
464 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}),497 .register => return self.fail(src, "TODO implement x86_64 genSetReg %rsi = register", .{}),
498 .memory => |x| {
499 if (x <= std.math.maxInt(u32)) {
500 // 48 8b 34 25 40 30 20 10 mov rsi,QWORD PTR ds:0x10203040
501 try self.code.resize(self.code.items.len + 8);
502 self.code.items[self.code.items.len - 8] = 0x48;
503 self.code.items[self.code.items.len - 7] = 0x8b;
504 self.code.items[self.code.items.len - 6] = 0x34;
505 self.code.items[self.code.items.len - 5] = 0x25;
506 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];
507 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));
508 return;
509 } else {
510 return self.fail(src, "TODO implement genSetReg for x86_64 setting rsi to 64-bit memory", .{});
511 }
512 },
465 },513 },
466 else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),514 else => return self.fail(src, "TODO implement genSetReg for x86_64 '{}'", .{@tagName(reg)}),
467 },515 },
...@@ -493,33 +541,21 @@ const Function = struct {...@@ -493,33 +541,21 @@ const Function = struct {
493 }541 }
494542
495 fn genTypedValue(self: *Function, src: usize, typed_value: TypedValue) !MCValue {543 fn genTypedValue(self: *Function, src: usize, typed_value: TypedValue) !MCValue {
544 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
545 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
496 const allocator = self.code.allocator;546 const allocator = self.code.allocator;
497 switch (typed_value.ty.zigTypeTag()) {547 switch (typed_value.ty.zigTypeTag()) {
498 .Pointer => {548 .Pointer => {
499 const ptr_elem_type = typed_value.ty.elemType();549 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
500 switch (ptr_elem_type.zigTypeTag()) {550 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
501 .Array => {551 const decl = payload.decl;
502 // TODO more checks to make sure this can be emitted as a string literal552 const got_addr = got.p_vaddr + decl.link.offset_table_index * ptr_bytes;
503 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {553 return MCValue{ .memory = got_addr };
504 error.AnalysisFail => unreachable,
505 else => |e| return e,
506 };
507 defer allocator.free(bytes);
508 const smaller_len = std.math.cast(u32, bytes.len) catch
509 return self.fail(src, "TODO handle a larger string constant", .{});
510
511 // Emit the string literal directly into the code; jump over it.
512 try self.genRelativeFwdJump(src, smaller_len);
513 const offset = self.code.items.len;
514 try self.code.appendSlice(bytes);
515 return MCValue{ .embedded_in_code = offset };
516 },
517 else => |t| return self.fail(src, "TODO implement emitTypedValue for pointer to '{}'", .{@tagName(t)}),
518 }554 }
555 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
519 },556 },
520 .Int => {557 .Int => {
521 const info = typed_value.ty.intInfo(self.target.*);558 const info = typed_value.ty.intInfo(self.target.*);
522 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
523 if (info.bits > ptr_bits or info.signed) {559 if (info.bits > ptr_bits or info.signed) {
524 return self.fail(src, "TODO const int bigger than ptr and signed int", .{});560 return self.fail(src, "TODO const int bigger than ptr and signed int", .{});
525 }561 }
src-self-hosted/ir.zig+136-36
...@@ -292,6 +292,8 @@ pub const Module = struct {...@@ -292,6 +292,8 @@ pub const Module = struct {
292 /// TODO look into using a lightweight map/set data structure rather than a linear array.292 /// TODO look into using a lightweight map/set data structure rather than a linear array.
293 dependants: ArrayListUnmanaged(*Decl) = ArrayListUnmanaged(*Decl){},293 dependants: ArrayListUnmanaged(*Decl) = ArrayListUnmanaged(*Decl){},
294294
295 contents_hash: Hash,
296
295 pub fn destroy(self: *Decl, allocator: *Allocator) void {297 pub fn destroy(self: *Decl, allocator: *Allocator) void {
296 allocator.free(mem.spanZ(self.name));298 allocator.free(mem.spanZ(self.name));
297 if (self.typedValueManaged()) |tvm| {299 if (self.typedValueManaged()) |tvm| {
...@@ -465,26 +467,42 @@ pub const Module = struct {...@@ -465,26 +467,42 @@ pub const Module = struct {
465 module: *text.Module,467 module: *text.Module,
466 },468 },
467 status: enum {469 status: enum {
468 unloaded,470 never_loaded,
471 unloaded_success,
469 unloaded_parse_failure,472 unloaded_parse_failure,
473 unloaded_sema_failure,
470 loaded_parse_failure,474 loaded_parse_failure,
471 loaded_sema_failure,475 loaded_sema_failure,
472 loaded_success,476 loaded_success,
473 },477 },
474478
475 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {479 pub fn unload(self: *ZIRModule, allocator: *Allocator) void {
476 switch (self.status) {480 switch (self.status) {
477 .unloaded,481 .never_loaded,
478 .unloaded_parse_failure,482 .unloaded_parse_failure,
483 .unloaded_sema_failure,
484 .unloaded_success,
479 => {},485 => {},
480 .loaded_success, .loaded_sema_failure => {486
487 .loaded_success => {
488 allocator.free(self.source.bytes);
489 self.contents.module.deinit(allocator);
490 self.status = .unloaded_success;
491 },
492 .loaded_sema_failure => {
481 allocator.free(self.source.bytes);493 allocator.free(self.source.bytes);
482 self.contents.module.deinit(allocator);494 self.contents.module.deinit(allocator);
495 self.status = .unloaded_sema_failure;
483 },496 },
484 .loaded_parse_failure => {497 .loaded_parse_failure => {
485 allocator.free(self.source.bytes);498 allocator.free(self.source.bytes);
499 self.status = .unloaded_parse_failure;
486 },500 },
487 }501 }
502 }
503
504 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {
505 self.unload(allocator);
488 self.* = undefined;506 self.* = undefined;
489 }507 }
490508
...@@ -623,7 +641,8 @@ pub const Module = struct {...@@ -623,7 +641,8 @@ pub const Module = struct {
623641
624 try self.performAllTheWork();642 try self.performAllTheWork();
625643
626 // TODO unload all the source files from memory644 // Unload all the source files from memory.
645 self.root_scope.unload(self.allocator);
627646
628 try self.bin_file.flush();647 try self.bin_file.flush();
629 self.link_error_flags = self.bin_file.error_flags;648 self.link_error_flags = self.bin_file.error_flags;
...@@ -722,8 +741,8 @@ pub const Module = struct {...@@ -722,8 +741,8 @@ pub const Module = struct {
722 .success => {},741 .success => {},
723 }742 }
724 }743 }
725 if (!decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits())744
726 continue;745 assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());
727746
728 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {747 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {
729 error.OutOfMemory => return error.OutOfMemory,748 error.OutOfMemory => return error.OutOfMemory,
...@@ -748,7 +767,7 @@ pub const Module = struct {...@@ -748,7 +767,7 @@ pub const Module = struct {
748767
749 fn getTextModule(self: *Module, root_scope: *Scope.ZIRModule) !*text.Module {768 fn getTextModule(self: *Module, root_scope: *Scope.ZIRModule) !*text.Module {
750 switch (root_scope.status) {769 switch (root_scope.status) {
751 .unloaded => {770 .never_loaded, .unloaded_success => {
752 try self.failed_files.ensureCapacity(self.failed_files.size + 1);771 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
753772
754 var keep_source = false;773 var keep_source = false;
...@@ -789,6 +808,7 @@ pub const Module = struct {...@@ -789,6 +808,7 @@ pub const Module = struct {
789 },808 },
790809
791 .unloaded_parse_failure,810 .unloaded_parse_failure,
811 .unloaded_sema_failure,
792 .loaded_parse_failure,812 .loaded_parse_failure,
793 .loaded_sema_failure,813 .loaded_sema_failure,
794 => return error.AnalysisFail,814 => return error.AnalysisFail,
...@@ -804,16 +824,62 @@ pub const Module = struct {...@@ -804,16 +824,62 @@ pub const Module = struct {
804 // Here we simulate adding a source file which was previously not part of the compilation,824 // Here we simulate adding a source file which was previously not part of the compilation,
805 // which means scanning the decls looking for exports.825 // which means scanning the decls looking for exports.
806 // TODO also identify decls that need to be deleted.826 // TODO also identify decls that need to be deleted.
807 const src_module = try self.getTextModule(root_scope);827 switch (root_scope.status) {
828 .never_loaded => {
829 const src_module = try self.getTextModule(root_scope);
808830
809 // Here we ensure enough queue capacity to store all the decls, so that later we can use831 // Here we ensure enough queue capacity to store all the decls, so that later we can use
810 // appendAssumeCapacity.832 // appendAssumeCapacity.
811 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);833 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
812834
813 for (src_module.decls) |decl| {835 for (src_module.decls) |decl| {
814 if (decl.cast(text.Inst.Export)) |export_inst| {836 if (decl.cast(text.Inst.Export)) |export_inst| {
815 _ = try self.resolveDecl(&root_scope.base, &export_inst.base);837 _ = try self.resolveDecl(&root_scope.base, &export_inst.base, link.ElfFile.Decl.empty);
816 }838 }
839 }
840 },
841
842 .unloaded_parse_failure,
843 .unloaded_sema_failure,
844 .loaded_parse_failure,
845 .loaded_sema_failure,
846 .loaded_success,
847 .unloaded_success,
848 => {
849 const src_module = try self.getTextModule(root_scope);
850
851 // Look for changed decls.
852 for (src_module.decls) |src_decl| {
853 const name_hash = Decl.hashSimpleName(src_decl.name);
854 if (self.decl_table.get(name_hash)) |kv| {
855 const decl = kv.value;
856 const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
857 if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {
858 // TODO recursive dependency management
859 std.debug.warn("noticed that '{}' changed\n", .{src_decl.name});
860 self.decl_table.removeAssertDiscard(name_hash);
861 const saved_link = decl.link;
862 decl.destroy(self.allocator);
863 if (self.export_owners.getValue(decl)) |exports| {
864 @panic("TODO handle updating a decl that does an export");
865 }
866 const new_decl = self.resolveDecl(
867 &root_scope.base,
868 src_decl,
869 saved_link,
870 ) catch |err| switch (err) {
871 error.OutOfMemory => return error.OutOfMemory,
872 error.AnalysisFail => continue,
873 };
874 if (self.decl_exports.remove(decl)) |entry| {
875 self.decl_exports.putAssumeCapacityNoClobber(new_decl, entry.value);
876 }
877 }
878 } else if (src_decl.cast(text.Inst.Export)) |export_inst| {
879 _ = try self.resolveDecl(&root_scope.base, &export_inst.base, link.ElfFile.Decl.empty);
880 }
881 }
882 },
817 }883 }
818 }884 }
819885
...@@ -846,11 +912,17 @@ pub const Module = struct {...@@ -846,11 +912,17 @@ pub const Module = struct {
846 };912 };
847 }913 }
848914
849 fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl {915 fn resolveDecl(
916 self: *Module,
917 scope: *Scope,
918 old_inst: *text.Inst,
919 bin_file_link: link.ElfFile.Decl,
920 ) InnerError!*Decl {
850 const hash = Decl.hashSimpleName(old_inst.name);921 const hash = Decl.hashSimpleName(old_inst.name);
851 if (self.decl_table.get(hash)) |kv| {922 if (self.decl_table.get(hash)) |kv| {
852 return kv.value;923 return kv.value;
853 } else {924 } else {
925 std.debug.warn("creating new decl for {}\n", .{old_inst.name});
854 const new_decl = blk: {926 const new_decl = blk: {
855 try self.decl_table.ensureCapacity(self.decl_table.size + 1);927 try self.decl_table.ensureCapacity(self.decl_table.size + 1);
856 const new_decl = try self.allocator.create(Decl);928 const new_decl = try self.allocator.create(Decl);
...@@ -863,6 +935,8 @@ pub const Module = struct {...@@ -863,6 +935,8 @@ pub const Module = struct {
863 .src = old_inst.src,935 .src = old_inst.src,
864 .typed_value = .{ .never_succeeded = {} },936 .typed_value = .{ .never_succeeded = {} },
865 .analysis = .initial_in_progress,937 .analysis = .initial_in_progress,
938 .contents_hash = Decl.hashSimpleName(old_inst.contents),
939 .link = bin_file_link,
866 };940 };
867 self.decl_table.putAssumeCapacityNoClobber(hash, new_decl);941 self.decl_table.putAssumeCapacityNoClobber(hash, new_decl);
868 break :blk new_decl;942 break :blk new_decl;
...@@ -887,6 +961,14 @@ pub const Module = struct {...@@ -887,6 +961,14 @@ pub const Module = struct {
887 };961 };
888 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);962 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
889963
964 const has_codegen_bits = typed_value.ty.hasCodeGenBits();
965 if (has_codegen_bits) {
966 // We don't fully codegen the decl until later, but we do need to reserve a global
967 // offset table index for it. This allows us to codegen decls out of dependency order,
968 // increasing how many computations can be done in parallel.
969 try self.bin_file.allocateDeclIndexes(new_decl);
970 }
971
890 arena_state.* = decl_scope.arena.state;972 arena_state.* = decl_scope.arena.state;
891973
892 new_decl.typed_value = .{974 new_decl.typed_value = .{
...@@ -896,14 +978,16 @@ pub const Module = struct {...@@ -896,14 +978,16 @@ pub const Module = struct {
896 },978 },
897 };979 };
898 new_decl.analysis = .complete;980 new_decl.analysis = .complete;
899 // We ensureCapacity when scanning for decls.981 if (has_codegen_bits) {
900 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });982 // We ensureCapacity when scanning for decls.
983 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
984 }
901 return new_decl;985 return new_decl;
902 }986 }
903 }987 }
904988
905 fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl {989 fn resolveCompleteDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl {
906 const decl = try self.resolveDecl(scope, old_inst);990 const decl = try self.resolveDecl(scope, old_inst, link.ElfFile.Decl.empty);
907 switch (decl.analysis) {991 switch (decl.analysis) {
908 .initial_in_progress => unreachable,992 .initial_in_progress => unreachable,
909 .repeat_in_progress => unreachable,993 .repeat_in_progress => unreachable,
...@@ -2088,8 +2172,8 @@ pub fn main() anyerror!void {...@@ -2088,8 +2172,8 @@ pub fn main() anyerror!void {
20882172
2089 const src_path = args[1];2173 const src_path = args[1];
2090 const bin_path = args[2];2174 const bin_path = args[2];
2091 const debug_error_trace = true;2175 const debug_error_trace = false;
2092 const output_zir = true;2176 const output_zir = false;
2093 const object_format: ?std.builtin.ObjectFormat = null;2177 const object_format: ?std.builtin.ObjectFormat = null;
20942178
2095 const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});2179 const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
...@@ -2112,7 +2196,7 @@ pub fn main() anyerror!void {...@@ -2112,7 +2196,7 @@ pub fn main() anyerror!void {
2112 .sub_file_path = root_pkg.root_src_path,2196 .sub_file_path = root_pkg.root_src_path,
2113 .source = .{ .unloaded = {} },2197 .source = .{ .unloaded = {} },
2114 .contents = .{ .not_available = {} },2198 .contents = .{ .not_available = {} },
2115 .status = .unloaded,2199 .status = .never_loaded,
2116 };2200 };
21172201
2118 break :blk Module{2202 break :blk Module{
...@@ -2132,22 +2216,38 @@ pub fn main() anyerror!void {...@@ -2132,22 +2216,38 @@ pub fn main() anyerror!void {
2132 };2216 };
2133 defer module.deinit();2217 defer module.deinit();
21342218
2135 try module.update();2219 const stdin = std.io.getStdIn().inStream();
2220 const stderr = std.io.getStdErr().outStream();
2221 var repl_buf: [1024]u8 = undefined;
21362222
2137 var errors = try module.getAllErrorsAlloc();2223 while (true) {
2138 defer errors.deinit(allocator);2224 try module.update();
21392225
2140 if (errors.list.len != 0) {2226 var errors = try module.getAllErrorsAlloc();
2141 for (errors.list) |full_err_msg| {2227 defer errors.deinit(allocator);
2142 std.debug.warn("{}:{}:{}: error: {}\n", .{2228
2143 full_err_msg.src_path,2229 if (errors.list.len != 0) {
2144 full_err_msg.line + 1,2230 for (errors.list) |full_err_msg| {
2145 full_err_msg.column + 1,2231 std.debug.warn("{}:{}:{}: error: {}\n", .{
2146 full_err_msg.msg,2232 full_err_msg.src_path,
2147 });2233 full_err_msg.line + 1,
2234 full_err_msg.column + 1,
2235 full_err_msg.msg,
2236 });
2237 }
2238 if (debug_error_trace) return error.AnalysisFail;
2239 }
2240
2241 try stderr.print("🦎 ", .{});
2242 if (try stdin.readUntilDelimiterOrEof(&repl_buf, '\n')) |line| {
2243 if (mem.eql(u8, line, "update")) {
2244 continue;
2245 } else {
2246 try stderr.print("unknown command: {}\n", .{line});
2247 }
2248 } else {
2249 break;
2148 }2250 }
2149 if (debug_error_trace) return error.AnalysisFail;
2150 std.process.exit(1);
2151 }2251 }
21522252
2153 if (output_zir) {2253 if (output_zir) {
src-self-hosted/ir/text.zig+11-1
...@@ -19,6 +19,9 @@ pub const Inst = struct {...@@ -19,6 +19,9 @@ pub const Inst = struct {
19 src: usize,19 src: usize,
20 name: []const u8,20 name: []const u8,
2121
22 /// Slice into the source of the part after the = and before the next instruction.
23 contents: []const u8,
24
22 /// These names are used directly as the instruction names in the text format.25 /// These names are used directly as the instruction names in the text format.
23 pub const Tag = enum {26 pub const Tag = enum {
24 breakpoint,27 breakpoint,
...@@ -798,11 +801,12 @@ const Parser = struct {...@@ -798,11 +801,12 @@ const Parser = struct {
798 }801 }
799802
800 fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Inst {803 fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Inst {
804 const contents_start = self.i;
801 const fn_name = try skipToAndOver(self, '(');805 const fn_name = try skipToAndOver(self, '(');
802 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {806 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {
803 if (mem.eql(u8, field.name, fn_name)) {807 if (mem.eql(u8, field.name, fn_name)) {
804 const tag = @field(Inst.Tag, field.name);808 const tag = @field(Inst.Tag, field.name);
805 return parseInstructionGeneric(self, field.name, Inst.TagToType(tag), body_ctx, name);809 return parseInstructionGeneric(self, field.name, Inst.TagToType(tag), body_ctx, name, contents_start);
806 }810 }
807 }811 }
808 return self.fail("unknown instruction '{}'", .{fn_name});812 return self.fail("unknown instruction '{}'", .{fn_name});
...@@ -814,12 +818,14 @@ const Parser = struct {...@@ -814,12 +818,14 @@ const Parser = struct {
814 comptime InstType: type,818 comptime InstType: type,
815 body_ctx: ?*Body,819 body_ctx: ?*Body,
816 inst_name: []const u8,820 inst_name: []const u8,
821 contents_start: usize,
817 ) InnerError!*Inst {822 ) InnerError!*Inst {
818 const inst_specific = try self.arena.allocator.create(InstType);823 const inst_specific = try self.arena.allocator.create(InstType);
819 inst_specific.base = .{824 inst_specific.base = .{
820 .name = inst_name,825 .name = inst_name,
821 .src = self.i,826 .src = self.i,
822 .tag = InstType.base_tag,827 .tag = InstType.base_tag,
828 .contents = undefined,
823 };829 };
824830
825 if (@hasField(InstType, "ty")) {831 if (@hasField(InstType, "ty")) {
...@@ -867,6 +873,8 @@ const Parser = struct {...@@ -867,6 +873,8 @@ const Parser = struct {
867 }873 }
868 try requireEatBytes(self, ")");874 try requireEatBytes(self, ")");
869875
876 inst_specific.base.contents = self.source[contents_start..self.i];
877
870 return &inst_specific.base;878 return &inst_specific.base;
871 }879 }
872880
...@@ -952,6 +960,7 @@ const Parser = struct {...@@ -952,6 +960,7 @@ const Parser = struct {
952 .name = try self.generateName(),960 .name = try self.generateName(),
953 .src = src,961 .src = src,
954 .tag = Inst.Str.base_tag,962 .tag = Inst.Str.base_tag,
963 .contents = undefined,
955 },964 },
956 .positionals = .{ .bytes = ident },965 .positionals = .{ .bytes = ident },
957 .kw_args = .{},966 .kw_args = .{},
...@@ -962,6 +971,7 @@ const Parser = struct {...@@ -962,6 +971,7 @@ const Parser = struct {
962 .name = try self.generateName(),971 .name = try self.generateName(),
963 .src = src,972 .src = src,
964 .tag = Inst.DeclRef.base_tag,973 .tag = Inst.DeclRef.base_tag,
974 .contents = undefined,
965 },975 },
966 .positionals = .{ .name = &name.base },976 .positionals = .{ .name = &name.base },
967 .kw_args = .{},977 .kw_args = .{},
src-self-hosted/link.zig+45-3
...@@ -310,7 +310,7 @@ pub const ElfFile = struct {...@@ -310,7 +310,7 @@ pub const ElfFile = struct {
310 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.310 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
311 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something311 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
312 // else in virtual memory.312 // else in virtual memory.
313 const default_got_addr = 0x80000000;313 const default_got_addr = 0x4000000;
314 try self.program_headers.append(self.allocator, .{314 try self.program_headers.append(self.allocator, .{
315 .p_type = elf.PT_LOAD,315 .p_type = elf.PT_LOAD,
316 .p_offset = off,316 .p_offset = off,
...@@ -755,6 +755,35 @@ pub const ElfFile = struct {...@@ -755,6 +755,35 @@ pub const ElfFile = struct {
755 };755 };
756 }756 }
757757
758 pub fn allocateDeclIndexes(self: *ElfFile, decl: *ir.Module.Decl) !void {
759 if (decl.link.local_sym_index != 0) return;
760
761 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
762 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
763 const local_sym_index = self.local_symbols.items.len;
764 const offset_table_index = self.offset_table.items.len;
765 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
766
767 self.local_symbols.appendAssumeCapacity(.{
768 .st_name = 0,
769 .st_info = 0,
770 .st_other = 0,
771 .st_shndx = 0,
772 .st_value = phdr.p_vaddr,
773 .st_size = 0,
774 });
775 errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1);
776 self.offset_table.appendAssumeCapacity(0);
777 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);
778
779 self.offset_table_count_dirty = true;
780
781 decl.link = .{
782 .local_sym_index = @intCast(u32, local_sym_index),
783 .offset_table_index = @intCast(u32, offset_table_index),
784 };
785 }
786
758 pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void {787 pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void {
759 var code_buffer = std.ArrayList(u8).init(self.allocator);788 var code_buffer = std.ArrayList(u8).init(self.allocator);
760 defer code_buffer.deinit();789 defer code_buffer.deinit();
...@@ -781,21 +810,33 @@ pub const ElfFile = struct {...@@ -781,21 +810,33 @@ pub const ElfFile = struct {
781 if (decl.link.local_sym_index != 0) {810 if (decl.link.local_sym_index != 0) {
782 const local_sym = &self.local_symbols.items[decl.link.local_sym_index];811 const local_sym = &self.local_symbols.items[decl.link.local_sym_index];
783 const existing_block = self.findAllocatedTextBlock(local_sym.*);812 const existing_block = self.findAllocatedTextBlock(local_sym.*);
784 const need_realloc = code.len > existing_block.size_capacity or813 const need_realloc = local_sym.st_size == 0 or
814 code.len > existing_block.size_capacity or
785 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);815 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
816 // TODO check for collision with another symbol
786 const file_offset = if (need_realloc) fo: {817 const file_offset = if (need_realloc) fo: {
787 const new_block = try self.allocateTextBlock(code.len, required_alignment);818 const new_block = try self.allocateTextBlock(code.len, required_alignment);
788 local_sym.st_value = new_block.vaddr;819 local_sym.st_value = new_block.vaddr;
789 local_sym.st_size = code.len;820 self.offset_table.items[decl.link.offset_table_index] = new_block.vaddr;
790821
822 //std.debug.warn("{}: writing got index {}=0x{x}\n", .{
823 // decl.name,
824 // decl.link.offset_table_index,
825 // self.offset_table.items[decl.link.offset_table_index],
826 //});
791 try self.writeOffsetTableEntry(decl.link.offset_table_index);827 try self.writeOffsetTableEntry(decl.link.offset_table_index);
792828
793 break :fo new_block.file_offset;829 break :fo new_block.file_offset;
794 } else existing_block.file_offset;830 } else existing_block.file_offset;
831 local_sym.st_size = code.len;
795 local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));832 local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));
796 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;833 local_sym.st_info = (elf.STB_LOCAL << 4) | stt_bits;
834 local_sym.st_other = 0;
835 local_sym.st_shndx = self.text_section_index.?;
797 // TODO this write could be avoided if no fields of the symbol were changed.836 // TODO this write could be avoided if no fields of the symbol were changed.
798 try self.writeSymbol(decl.link.local_sym_index);837 try self.writeSymbol(decl.link.local_sym_index);
838
839 //std.debug.warn("updating {} at vaddr 0x{x}\n", .{ decl.name, local_sym.st_value });
799 break :blk file_offset;840 break :blk file_offset;
800 } else {841 } else {
801 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);842 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
...@@ -829,6 +870,7 @@ pub const ElfFile = struct {...@@ -829,6 +870,7 @@ pub const ElfFile = struct {
829 .offset_table_index = @intCast(u32, offset_table_index),870 .offset_table_index = @intCast(u32, offset_table_index),
830 };871 };
831872
873 //std.debug.warn("writing new {} at vaddr 0x{x}\n", .{ decl.name, new_block.vaddr });
832 break :blk new_block.file_offset;874 break :blk new_block.file_offset;
833 }875 }
834 };876 };