authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-18 17:13:19+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-24 12:34:41+01:00
logc98d229844e4b12ba2c61291fdf7fa0376f4e087
treef2396b11084f064d6601138b4fe0e847506010b1
parent6cd4c7612f7d0c1bf21695c29432296823875c46

macho: fill in more blanks in ZigObject


1 files changed, 263 insertions(+), 14 deletions(-)

src/link/MachO/ZigObject.zig+263-14
...@@ -259,12 +259,47 @@ pub fn lowerAnonDecl(...@@ -259,12 +259,47 @@ pub fn lowerAnonDecl(
259 explicit_alignment: InternPool.Alignment,259 explicit_alignment: InternPool.Alignment,
260 src_loc: Module.SrcLoc,260 src_loc: Module.SrcLoc,
261) !codegen.Result {261) !codegen.Result {
262 _ = self;262 const gpa = macho_file.base.comp.gpa;
263 _ = macho_file;263 const mod = macho_file.base.comp.module.?;
264 _ = decl_val;264 const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
265 _ = explicit_alignment;265 const decl_alignment = switch (explicit_alignment) {
266 _ = src_loc;266 .none => ty.abiAlignment(mod),
267 @panic("TODO lowerAnonDecl");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}
269304
270fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {305fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
...@@ -591,11 +626,100 @@ pub fn lowerUnnamedConst(...@@ -591,11 +626,100 @@ pub fn lowerUnnamedConst(
591 typed_value: TypedValue,626 typed_value: TypedValue,
592 decl_index: InternPool.DeclIndex,627 decl_index: InternPool.DeclIndex,
593) !u32 {628) !u32 {
594 _ = self;629 const gpa = macho_file.base.comp.gpa;
595 _ = macho_file;630 const mod = macho_file.base.comp.module.?;
596 _ = typed_value;631 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
597 _ = decl_index;632 if (!gop.found_existing) {
598 @panic("TODO lowerUnnamedConst");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
662const LowerConstResult = union(enum) {
663 ok: Symbol.Index,
664 fail: *Module.ErrorMsg,
665};
666
667fn 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}
600724
601pub fn updateExports(725pub fn updateExports(
...@@ -692,6 +816,91 @@ pub fn updateExports(...@@ -692,6 +816,91 @@ pub fn updateExports(
692 }816 }
693}817}
694818
819fn 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/// Must be called only after a successful call to `updateDecl`.904/// Must be called only after a successful call to `updateDecl`.
696pub fn updateDeclLineNumber(905pub fn updateDeclLineNumber(
697 self: *ZigObject,906 self: *ZigObject,
...@@ -701,7 +910,7 @@ pub fn updateDeclLineNumber(...@@ -701,7 +910,7 @@ pub fn updateDeclLineNumber(
701 _ = self;910 _ = self;
702 _ = mod;911 _ = mod;
703 _ = decl_index;912 _ = decl_index;
704 @panic("TODO updateDeclLineNumber");913 // TODO: Dwarf
705}914}
706915
707pub fn deleteDeclExport(916pub fn deleteDeclExport(
...@@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl(...@@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl(
751 return gop.value_ptr.symbol_index;960 return gop.value_ptr.symbol_index;
752}961}
753962
963pub 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
754pub fn asFile(self: *ZigObject) File {1003pub fn asFile(self: *ZigObject) File {
755 return .{ .zig_object = self };1004 return .{ .zig_object = self };
756}1005}
...@@ -822,9 +1071,9 @@ const DeclMetadata = struct {...@@ -822,9 +1071,9 @@ const DeclMetadata = struct {
822const LazySymbolMetadata = struct {1071const LazySymbolMetadata = struct {
823 const State = enum { unused, pending_flush, flushed };1072 const State = enum { unused, pending_flush, flushed };
824 text_symbol_index: Symbol.Index = undefined,1073 text_symbol_index: Symbol.Index = undefined,
825 data_const_symbol_index: Symbol.Index = undefined,1074 const_symbol_index: Symbol.Index = undefined,
826 text_state: State = .unused,1075 text_state: State = .unused,
827 rodata_state: State = .unused,1076 const_state: State = .unused,
828};1077};
8291078
830const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);1079const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);