| ... | ... | @@ -259,12 +259,47 @@ pub fn lowerAnonDecl( |
| 259 | 259 | explicit_alignment: InternPool.Alignment, |
| 260 | 260 | src_loc: Module.SrcLoc, |
| 261 | 261 | ) !codegen.Result { |
| 262 | | _ = self; |
| 263 | | _ = macho_file; |
| 264 | | _ = decl_val; |
| 265 | | _ = explicit_alignment; |
| 266 | | _ = src_loc; |
| 267 | | @panic("TODO lowerAnonDecl"); |
| 262 | const gpa = macho_file.base.comp.gpa; |
| 263 | const mod = macho_file.base.comp.module.?; |
| 264 | const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val)); |
| 265 | const decl_alignment = switch (explicit_alignment) { |
| 266 | .none => ty.abiAlignment(mod), |
| 267 | else => explicit_alignment, |
| 268 | }; |
| 269 | if (self.anon_decls.get(decl_val)) |metadata| { |
| 270 | const existing_alignment = macho_file.getSymbol(metadata.symbol_index).getAtom(macho_file).?.alignment; |
| 271 | if (decl_alignment.order(existing_alignment).compare(.lte)) |
| 272 | return .ok; |
| 273 | } |
| 274 | |
| 275 | const val = Value.fromInterned(decl_val); |
| 276 | const tv = TypedValue{ .ty = ty, .val = val }; |
| 277 | var name_buf: [32]u8 = undefined; |
| 278 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 279 | @intFromEnum(decl_val), |
| 280 | }) catch unreachable; |
| 281 | const res = self.lowerConst( |
| 282 | macho_file, |
| 283 | name, |
| 284 | tv, |
| 285 | decl_alignment, |
| 286 | macho_file.zig_const_section_index.?, |
| 287 | src_loc, |
| 288 | ) catch |err| switch (err) { |
| 289 | error.OutOfMemory => return error.OutOfMemory, |
| 290 | else => |e| return .{ .fail = try Module.ErrorMsg.create( |
| 291 | gpa, |
| 292 | src_loc, |
| 293 | "unable to lower constant value: {s}", |
| 294 | .{@errorName(e)}, |
| 295 | ) }, |
| 296 | }; |
| 297 | const sym_index = switch (res) { |
| 298 | .ok => |sym_index| sym_index, |
| 299 | .fail => |em| return .{ .fail = em }, |
| 300 | }; |
| 301 | try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index }); |
| 302 | return .ok; |
| 268 | 303 | } |
| 269 | 304 | |
| 270 | 305 | fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void { |
| ... | ... | @@ -591,11 +626,100 @@ pub fn lowerUnnamedConst( |
| 591 | 626 | typed_value: TypedValue, |
| 592 | 627 | decl_index: InternPool.DeclIndex, |
| 593 | 628 | ) !u32 { |
| 594 | | _ = self; |
| 595 | | _ = macho_file; |
| 596 | | _ = typed_value; |
| 597 | | _ = decl_index; |
| 598 | | @panic("TODO lowerUnnamedConst"); |
| 629 | const gpa = macho_file.base.comp.gpa; |
| 630 | const mod = macho_file.base.comp.module.?; |
| 631 | const gop = try self.unnamed_consts.getOrPut(gpa, decl_index); |
| 632 | if (!gop.found_existing) { |
| 633 | gop.value_ptr.* = .{}; |
| 634 | } |
| 635 | const unnamed_consts = gop.value_ptr; |
| 636 | const decl = mod.declPtr(decl_index); |
| 637 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 638 | const index = unnamed_consts.items.len; |
| 639 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); |
| 640 | defer gpa.free(name); |
| 641 | const sym_index = switch (try self.lowerConst( |
| 642 | macho_file, |
| 643 | name, |
| 644 | typed_value, |
| 645 | typed_value.ty.abiAlignment(mod), |
| 646 | macho_file.zig_const_section_index.?, |
| 647 | decl.srcLoc(mod), |
| 648 | )) { |
| 649 | .ok => |sym_index| sym_index, |
| 650 | .fail => |em| { |
| 651 | decl.analysis = .codegen_failure; |
| 652 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 653 | log.err("{s}", .{em.msg}); |
| 654 | return error.CodegenFail; |
| 655 | }, |
| 656 | }; |
| 657 | const sym = macho_file.getSymbol(sym_index); |
| 658 | try unnamed_consts.append(gpa, sym.atom); |
| 659 | return sym_index; |
| 660 | } |
| 661 | |
| 662 | const LowerConstResult = union(enum) { |
| 663 | ok: Symbol.Index, |
| 664 | fail: *Module.ErrorMsg, |
| 665 | }; |
| 666 | |
| 667 | fn lowerConst( |
| 668 | self: *ZigObject, |
| 669 | macho_file: *MachO, |
| 670 | name: []const u8, |
| 671 | tv: TypedValue, |
| 672 | required_alignment: InternPool.Alignment, |
| 673 | output_section_index: u8, |
| 674 | src_loc: Module.SrcLoc, |
| 675 | ) !LowerConstResult { |
| 676 | const gpa = macho_file.base.comp.gpa; |
| 677 | |
| 678 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 679 | defer code_buffer.deinit(); |
| 680 | |
| 681 | const sym_index = try self.addAtom(macho_file); |
| 682 | |
| 683 | const res = try codegen.generateSymbol(&macho_file.base, src_loc, tv, &code_buffer, .{ |
| 684 | .none = {}, |
| 685 | }, .{ |
| 686 | .parent_atom_index = sym_index, |
| 687 | }); |
| 688 | const code = switch (res) { |
| 689 | .ok => code_buffer.items, |
| 690 | .fail => |em| return .{ .fail = em }, |
| 691 | }; |
| 692 | |
| 693 | const sym = macho_file.getSymbol(sym_index); |
| 694 | const name_str_index = try macho_file.strings.insert(gpa, name); |
| 695 | sym.name = name_str_index; |
| 696 | sym.out_n_sect = output_section_index; |
| 697 | |
| 698 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 699 | nlist.n_strx = name_str_index; |
| 700 | nlist.n_type = macho.N_SECT; |
| 701 | nlist.n_sect = output_section_index + 1; |
| 702 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| 703 | |
| 704 | const atom = sym.getAtom(macho_file).?; |
| 705 | atom.flags.alive = true; |
| 706 | atom.name = name_str_index; |
| 707 | atom.alignment = required_alignment; |
| 708 | atom.size = code.len; |
| 709 | atom.out_n_sect = output_section_index; |
| 710 | |
| 711 | try atom.allocate(macho_file); |
| 712 | // TODO rename and re-audit this method |
| 713 | errdefer self.freeDeclMetadata(macho_file, sym_index); |
| 714 | |
| 715 | sym.value = 0; |
| 716 | nlist.n_value = 0; |
| 717 | |
| 718 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 719 | const file_offset = sect.offset + atom.value - sect.addr; |
| 720 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 721 | |
| 722 | return .{ .ok = sym_index }; |
| 599 | 723 | } |
| 600 | 724 | |
| 601 | 725 | pub fn updateExports( |
| ... | ... | @@ -692,6 +816,91 @@ pub fn updateExports( |
| 692 | 816 | } |
| 693 | 817 | } |
| 694 | 818 | |
| 819 | fn updateLazySymbol( |
| 820 | self: *ZigObject, |
| 821 | macho_file: *MachO, |
| 822 | lazy_sym: link.File.LazySymbol, |
| 823 | symbol_index: Symbol.Index, |
| 824 | ) !void { |
| 825 | const gpa = macho_file.base.comp.gpa; |
| 826 | const mod = macho_file.base.comp.module.?; |
| 827 | |
| 828 | var required_alignment: InternPool.Alignment = .none; |
| 829 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 830 | defer code_buffer.deinit(); |
| 831 | |
| 832 | const name_str_index = blk: { |
| 833 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{ |
| 834 | @tagName(lazy_sym.kind), |
| 835 | lazy_sym.ty.fmt(mod), |
| 836 | }); |
| 837 | defer gpa.free(name); |
| 838 | break :blk try macho_file.strings.insert(gpa, name); |
| 839 | }; |
| 840 | |
| 841 | const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| 842 | mod.declPtr(owner_decl).srcLoc(mod) |
| 843 | else |
| 844 | Module.SrcLoc{ |
| 845 | .file_scope = undefined, |
| 846 | .parent_decl_node = undefined, |
| 847 | .lazy = .unneeded, |
| 848 | }; |
| 849 | const res = try codegen.generateLazySymbol( |
| 850 | &macho_file.base, |
| 851 | src, |
| 852 | lazy_sym, |
| 853 | &required_alignment, |
| 854 | &code_buffer, |
| 855 | .none, |
| 856 | .{ .parent_atom_index = symbol_index }, |
| 857 | ); |
| 858 | const code = switch (res) { |
| 859 | .ok => code_buffer.items, |
| 860 | .fail => |em| { |
| 861 | log.err("{s}", .{em.msg}); |
| 862 | return error.CodegenFail; |
| 863 | }, |
| 864 | }; |
| 865 | |
| 866 | const output_section_index = switch (lazy_sym.kind) { |
| 867 | .code => macho_file.zig_text_section_index.?, |
| 868 | .const_data => macho_file.zig_const_section_index.?, |
| 869 | }; |
| 870 | const sym = macho_file.getSymbol(symbol_index); |
| 871 | sym.name = name_str_index; |
| 872 | sym.out_n_sect = output_section_index; |
| 873 | |
| 874 | const nlist = &self.symtab.items(.nlist)[sym.nlist_idx]; |
| 875 | nlist.n_strx = name_str_index; |
| 876 | nlist.n_type = macho.N_SECT; |
| 877 | nlist.n_sect = output_section_index + 1; |
| 878 | self.symtab.items(.size)[sym.nlist_idx] = code.len; |
| 879 | |
| 880 | const atom = sym.getAtom(macho_file).?; |
| 881 | atom.flags.alive = true; |
| 882 | atom.name = name_str_index; |
| 883 | atom.alignment = required_alignment; |
| 884 | atom.size = code.len; |
| 885 | atom.out_n_sect = output_section_index; |
| 886 | |
| 887 | try atom.allocate(macho_file); |
| 888 | errdefer self.freeDeclMetadata(macho_file, symbol_index); |
| 889 | |
| 890 | sym.value = 0; |
| 891 | sym.flags.needs_zig_got = true; |
| 892 | nlist.st_value = 0; |
| 893 | |
| 894 | if (!macho_file.base.isRelocatable()) { |
| 895 | const gop = try sym.getOrCreateZigGotEntry(symbol_index, macho_file); |
| 896 | try macho_file.zig_got.writeOne(macho_file, gop.index); |
| 897 | } |
| 898 | |
| 899 | const sect = macho_file.sections.items(.header)[output_section_index]; |
| 900 | const file_offset = sect.offset + atom.value - sect.addr; |
| 901 | try macho_file.base.file.?.pwriteAll(code, file_offset); |
| 902 | } |
| 903 | |
| 695 | 904 | /// Must be called only after a successful call to `updateDecl`. |
| 696 | 905 | pub fn updateDeclLineNumber( |
| 697 | 906 | self: *ZigObject, |
| ... | ... | @@ -701,7 +910,7 @@ pub fn updateDeclLineNumber( |
| 701 | 910 | _ = self; |
| 702 | 911 | _ = mod; |
| 703 | 912 | _ = decl_index; |
| 704 | | @panic("TODO updateDeclLineNumber"); |
| 913 | // TODO: Dwarf |
| 705 | 914 | } |
| 706 | 915 | |
| 707 | 916 | pub fn deleteDeclExport( |
| ... | ... | @@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl( |
| 751 | 960 | return gop.value_ptr.symbol_index; |
| 752 | 961 | } |
| 753 | 962 | |
| 963 | pub fn getOrCreateMetadataForLazySymbol( |
| 964 | self: *ZigObject, |
| 965 | macho_file: *MachO, |
| 966 | lazy_sym: link.File.LazySymbol, |
| 967 | ) !Symbol.Index { |
| 968 | const gpa = macho_file.base.comp.gpa; |
| 969 | const mod = macho_file.base.comp.module.?; |
| 970 | const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod)); |
| 971 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 972 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 973 | const metadata: struct { |
| 974 | symbol_index: *Symbol.Index, |
| 975 | state: *LazySymbolMetadata.State, |
| 976 | } = switch (lazy_sym.kind) { |
| 977 | .code => .{ |
| 978 | .symbol_index = &gop.value_ptr.text_symbol_index, |
| 979 | .state = &gop.value_ptr.text_state, |
| 980 | }, |
| 981 | .const_data => .{ |
| 982 | .symbol_index = &gop.value_ptr.const_symbol_index, |
| 983 | .state = &gop.value_ptr.const_state, |
| 984 | }, |
| 985 | }; |
| 986 | switch (metadata.state.*) { |
| 987 | .unused => { |
| 988 | const symbol_index = try self.addAtom(macho_file); |
| 989 | const sym = macho_file.getSymbol(symbol_index); |
| 990 | sym.flags.needs_zig_got = true; |
| 991 | metadata.symbol_index.* = symbol_index; |
| 992 | }, |
| 993 | .pending_flush => return metadata.symbol_index.*, |
| 994 | .flushed => {}, |
| 995 | } |
| 996 | metadata.state.* = .pending_flush; |
| 997 | const symbol_index = metadata.symbol_index.*; |
| 998 | // anyerror needs to be deferred until flushModule |
| 999 | if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(macho_file, lazy_sym, symbol_index); |
| 1000 | return symbol_index; |
| 1001 | } |
| 1002 | |
| 754 | 1003 | pub fn asFile(self: *ZigObject) File { |
| 755 | 1004 | return .{ .zig_object = self }; |
| 756 | 1005 | } |
| ... | ... | @@ -822,9 +1071,9 @@ const DeclMetadata = struct { |
| 822 | 1071 | const LazySymbolMetadata = struct { |
| 823 | 1072 | const State = enum { unused, pending_flush, flushed }; |
| 824 | 1073 | text_symbol_index: Symbol.Index = undefined, |
| 825 | | data_const_symbol_index: Symbol.Index = undefined, |
| 1074 | const_symbol_index: Symbol.Index = undefined, |
| 826 | 1075 | text_state: State = .unused, |
| 827 | | rodata_state: State = .unused, |
| 1076 | const_state: State = .unused, |
| 828 | 1077 | }; |
| 829 | 1078 | |
| 830 | 1079 | const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata); |