authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-11 10:18:43+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-06-11 10:18:43+02:00
log961d556570e19c2fca1ba5ad1aadd843f012b7ed
tree9e3a45acecd9abde440ce8313e87234ebcfc7622
parent138afd5cbfbe17829082efa3084f63de88aa1c90
parenta8116dcc2727e83a4c0049ca37046e05fe9de0c5
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9069 from ziglang/zld-common-syms

zig ld: add common (tentative) symbols support

8 files changed, 337 insertions(+), 128 deletions(-)

src/link/MachO/Object.zig+20-8
...@@ -54,6 +54,11 @@ pub const Section = struct {...@@ -54,6 +54,11 @@ pub const Section = struct {
54 inner: macho.section_64,54 inner: macho.section_64,
55 code: []u8,55 code: []u8,
56 relocs: ?[]*Relocation,56 relocs: ?[]*Relocation,
57 target_map: ?struct {
58 segment_id: u16,
59 section_id: u16,
60 offset: u32,
61 } = null,
5762
58 pub fn deinit(self: *Section, allocator: *Allocator) void {63 pub fn deinit(self: *Section, allocator: *Allocator) void {
59 allocator.free(self.code);64 allocator.free(self.code);
...@@ -346,15 +351,15 @@ pub fn parseSymbols(self: *Object) !void {...@@ -346,15 +351,15 @@ pub fn parseSymbols(self: *Object) !void {
346 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));351 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
347352
348 if (Symbol.isStab(sym)) {353 if (Symbol.isStab(sym)) {
349 log.err("stab {s} in {s}", .{ sym_name, self.name.? });354 log.err("unhandled symbol type: stab {s} in {s}", .{ sym_name, self.name.? });
350 return error.UnhandledSymbolType;355 return error.UnhandledSymbolType;
351 }356 }
352 if (Symbol.isIndr(sym)) {357 if (Symbol.isIndr(sym)) {
353 log.err("indirect symbol {s} in {s}", .{ sym_name, self.name.? });358 log.err("unhandled symbol type: indirect {s} in {s}", .{ sym_name, self.name.? });
354 return error.UnhandledSymbolType;359 return error.UnhandledSymbolType;
355 }360 }
356 if (Symbol.isAbs(sym)) {361 if (Symbol.isAbs(sym)) {
357 log.err("absolute symbol {s} in {s}", .{ sym_name, self.name.? });362 log.err("unhandled symbol type: absolute {s} in {s}", .{ sym_name, self.name.? });
358 return error.UnhandledSymbolType;363 return error.UnhandledSymbolType;
359 }364 }
360365
...@@ -383,11 +388,18 @@ pub fn parseSymbols(self: *Object) !void {...@@ -383,11 +388,18 @@ pub fn parseSymbols(self: *Object) !void {
383 }388 }
384389
385 if (sym.n_value != 0) {390 if (sym.n_value != 0) {
386 log.err("common symbol {s} in {s}", .{ sym_name, self.name.? });391 const tentative = try self.allocator.create(Symbol.Tentative);
387 return error.UnhandledSymbolType;392 errdefer self.allocator.destroy(tentative);
388 // const comm_size = sym.n_value;393 tentative.* = .{
389 // const comm_align = (sym.n_desc >> 8) & 0x0f;394 .base = .{
390 // log.warn("Common symbol: size 0x{x}, align 0x{x}", .{ comm_size, comm_align });395 .@"type" = .tentative,
396 .name = name,
397 },
398 .size = sym.n_value,
399 .alignment = (sym.n_desc >> 8) & 0x0f,
400 .file = self,
401 };
402 break :symbol &tentative.base;
391 }403 }
392404
393 const undef = try self.allocator.create(Symbol.Unresolved);405 const undef = try self.allocator.create(Symbol.Unresolved);
src/link/MachO/Symbol.zig+20
...@@ -12,6 +12,7 @@ pub const Type = enum {...@@ -12,6 +12,7 @@ pub const Type = enum {
12 regular,12 regular,
13 proxy,13 proxy,
14 unresolved,14 unresolved,
15 tentative,
15};16};
1617
17/// Symbol type.18/// Symbol type.
...@@ -60,6 +61,10 @@ pub const Regular = struct {...@@ -60,6 +61,10 @@ pub const Regular = struct {
60 size: u64,61 size: u64,
61 } = null,62 } = null,
6263
64 /// True if symbol was already committed into the final
65 /// symbol table.
66 visited: bool = false,
67
63 pub const base_type: Symbol.Type = .regular;68 pub const base_type: Symbol.Type = .regular;
6469
65 pub const Linkage = enum {70 pub const Linkage = enum {
...@@ -94,6 +99,21 @@ pub const Unresolved = struct {...@@ -94,6 +99,21 @@ pub const Unresolved = struct {
94 pub const base_type: Symbol.Type = .unresolved;99 pub const base_type: Symbol.Type = .unresolved;
95};100};
96101
102pub const Tentative = struct {
103 base: Symbol,
104
105 /// Symbol size.
106 size: u64,
107
108 /// Symbol alignment as power of two.
109 alignment: u16,
110
111 /// File where this symbol was referenced.
112 file: *Object,
113
114 pub const base_type: Symbol.Type = .tentative;
115};
116
97pub fn deinit(base: *Symbol, allocator: *Allocator) void {117pub fn deinit(base: *Symbol, allocator: *Allocator) void {
98 allocator.free(base.name);118 allocator.free(base.name);
99}119}
src/link/MachO/Zld.zig+257-120
...@@ -84,6 +84,11 @@ common_section_index: ?u16 = null,...@@ -84,6 +84,11 @@ common_section_index: ?u16 = null,
84globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},84globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
85imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},85imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
86unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},86unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
87tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
88
89/// Offset into __DATA,__common section.
90/// Set if the linker found tentative definitions in any of the objects.
91tentative_defs_offset: u64 = 0,
8792
88strtab: std.ArrayListUnmanaged(u8) = .{},93strtab: std.ArrayListUnmanaged(u8) = .{},
89strtab_dir: std.StringHashMapUnmanaged(u32) = .{},94strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
...@@ -95,9 +100,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},...@@ -95,9 +100,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
95100
96stub_helper_stubs_start_off: ?u64 = null,101stub_helper_stubs_start_off: ?u64 = null,
97102
98mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
99unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
100
101const TlvOffset = struct {103const TlvOffset = struct {
102 source_addr: u64,104 source_addr: u64,
103 offset: u64,105 offset: u64,
...@@ -107,18 +109,6 @@ const TlvOffset = struct {...@@ -107,18 +109,6 @@ const TlvOffset = struct {
107 }109 }
108};110};
109111
110const MappingKey = struct {
111 object_id: u16,
112 source_sect_id: u16,
113};
114
115pub const SectionMapping = struct {
116 source_sect_id: u16,
117 target_seg_id: u16,
118 target_sect_id: u16,
119 offset: u32,
120};
121
122/// Default path to dyld112/// Default path to dyld
123const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";113const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
124114
...@@ -159,9 +149,7 @@ pub fn deinit(self: *Zld) void {...@@ -159,9 +149,7 @@ pub fn deinit(self: *Zld) void {
159 }149 }
160 self.dylibs.deinit(self.allocator);150 self.dylibs.deinit(self.allocator);
161151
162 self.mappings.deinit(self.allocator);152 self.tentatives.deinit(self.allocator);
163 self.unhandled_sections.deinit(self.allocator);
164
165 self.globals.deinit(self.allocator);153 self.globals.deinit(self.allocator);
166 self.imports.deinit(self.allocator);154 self.imports.deinit(self.allocator);
167 self.unresolved.deinit(self.allocator);155 self.unresolved.deinit(self.allocator);
...@@ -239,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L...@@ -239,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
239 try self.allocateDataSegment();227 try self.allocateDataSegment();
240 self.allocateLinkeditSegment();228 self.allocateLinkeditSegment();
241 try self.allocateSymbols();229 try self.allocateSymbols();
230 try self.allocateTentativeSymbols();
242 try self.flush();231 try self.flush();
243}232}
244233
...@@ -407,46 +396,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {...@@ -407,46 +396,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
407396
408fn mapAndUpdateSections(397fn mapAndUpdateSections(
409 self: *Zld,398 self: *Zld,
410 object_id: u16,399 object: *Object,
411 source_sect_id: u16,400 source_sect_id: u16,
412 target_seg_id: u16,401 target_seg_id: u16,
413 target_sect_id: u16,402 target_sect_id: u16,
414) !void {403) !void {
415 const object = self.objects.items[object_id];404 const source_sect = &object.sections.items[source_sect_id];
416 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
417 const source_sect = source_seg.sections.items[source_sect_id];
418 const target_seg = &self.load_commands.items[target_seg_id].Segment;405 const target_seg = &self.load_commands.items[target_seg_id].Segment;
419 const target_sect = &target_seg.sections.items[target_sect_id];406 const target_sect = &target_seg.sections.items[target_sect_id];
420407
421 const alignment = try math.powi(u32, 2, target_sect.@"align");408 const alignment = try math.powi(u32, 2, target_sect.@"align");
422 const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);409 const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);
423 const size = mem.alignForwardGeneric(u64, source_sect.size, alignment);410 const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment);
424 const key = MappingKey{411
425 .object_id = object_id,412 log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
426 .source_sect_id = source_sect_id,413 object.name.?,
427 };414 parseName(&source_sect.inner.segname),
428 try self.mappings.putNoClobber(self.allocator, key, .{415 parseName(&source_sect.inner.sectname),
429 .source_sect_id = source_sect_id,
430 .target_seg_id = target_seg_id,
431 .target_sect_id = target_sect_id,
432 .offset = @intCast(u32, offset),
433 });
434 log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{
435 object.name,
436 parseName(&source_sect.segname),
437 parseName(&source_sect.sectname),
438 parseName(&target_sect.segname),416 parseName(&target_sect.segname),
439 parseName(&target_sect.sectname),417 parseName(&target_sect.sectname),
440 offset,418 offset,
441 offset + size,419 offset + size,
442 });420 });
443421
422 source_sect.target_map = .{
423 .segment_id = target_seg_id,
424 .section_id = target_sect_id,
425 .offset = @intCast(u32, offset),
426 };
444 target_sect.size = offset + size;427 target_sect.size = offset + size;
445}428}
446429
447fn updateMetadata(self: *Zld) !void {430fn updateMetadata(self: *Zld) !void {
448 for (self.objects.items) |object, id| {431 for (self.objects.items) |object| {
449 const object_id = @intCast(u16, id);
450 const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;432 const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
451 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;433 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
452 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;434 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
...@@ -699,20 +681,57 @@ fn updateMetadata(self: *Zld) !void {...@@ -699,20 +681,57 @@ fn updateMetadata(self: *Zld) !void {
699 for (object_seg.sections.items) |source_sect, sect_id| {681 for (object_seg.sections.items) |source_sect, sect_id| {
700 const source_sect_id = @intCast(u16, sect_id);682 const source_sect_id = @intCast(u16, sect_id);
701 if (self.getMatchingSection(source_sect)) |res| {683 if (self.getMatchingSection(source_sect)) |res| {
702 try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect);684 try self.mapAndUpdateSections(object, source_sect_id, res.seg, res.sect);
703 continue;685 continue;
704 }686 }
705687
706 const segname = parseName(&source_sect.segname);688 log.debug("section '{s},{s}' will be unmapped", .{
707 const sectname = parseName(&source_sect.sectname);689 parseName(&source_sect.segname),
708690 parseName(&source_sect.sectname),
709 log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });691 });
692 }
693 }
710694
711 try self.unhandled_sections.putNoClobber(self.allocator, .{695 // Ensure we have __DATA,__common section if we have tentative definitions.
712 .object_id = object_id,696 // Update size and alignment of __DATA,__common section.
713 .source_sect_id = source_sect_id,697 if (self.tentatives.values().len > 0) {
714 }, 0);698 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
699 const common_section_index = self.common_section_index orelse ind: {
700 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
701 try data_seg.addSection(self.allocator, .{
702 .sectname = makeStaticString("__common"),
703 .segname = makeStaticString("__DATA"),
704 .addr = 0,
705 .size = 0,
706 .offset = 0,
707 .@"align" = 0,
708 .reloff = 0,
709 .nreloc = 0,
710 .flags = macho.S_ZEROFILL,
711 .reserved1 = 0,
712 .reserved2 = 0,
713 .reserved3 = 0,
714 });
715 break :ind self.common_section_index.?;
716 };
717 const common_sect = &data_seg.sections.items[common_section_index];
718
719 var max_align: u16 = 0;
720 var added_size: u64 = 0;
721 for (self.tentatives.values()) |sym| {
722 const tent = sym.cast(Symbol.Tentative) orelse unreachable;
723 max_align = math.max(max_align, tent.alignment);
724 added_size += tent.size;
715 }725 }
726
727 common_sect.@"align" = math.max(common_sect.@"align", max_align);
728
729 const alignment = try math.powi(u32, 2, common_sect.@"align");
730 const offset = mem.alignForwardGeneric(u64, common_sect.size, alignment);
731 const size = mem.alignForwardGeneric(u64, added_size, alignment);
732
733 common_sect.size = offset + size;
734 self.tentative_defs_offset = offset;
716 }735 }
717736
718 tlv_align: {737 tlv_align: {
...@@ -954,18 +973,34 @@ fn sortSections(self: *Zld) !void {...@@ -954,18 +973,34 @@ fn sortSections(self: *Zld) !void {
954 }973 }
955 }974 }
956975
957 var it = self.mappings.valueIterator();976 for (self.objects.items) |object| {
958 while (it.next()) |mapping| {977 for (object.sections.items) |*sect| {
959 if (self.text_segment_cmd_index.? == mapping.target_seg_id) {978 const target_map = sect.target_map orelse continue;
960 const new_index = text_index_mapping.get(mapping.target_sect_id) orelse unreachable;979
961 mapping.target_sect_id = new_index;980 const new_index = blk: {
962 } else if (self.data_const_segment_cmd_index.? == mapping.target_seg_id) {981 if (self.text_segment_cmd_index.? == target_map.segment_id) {
963 const new_index = data_const_index_mapping.get(mapping.target_sect_id) orelse unreachable;982 break :blk text_index_mapping.get(target_map.section_id) orelse unreachable;
964 mapping.target_sect_id = new_index;983 } else if (self.data_const_segment_cmd_index.? == target_map.segment_id) {
965 } else if (self.data_segment_cmd_index.? == mapping.target_seg_id) {984 break :blk data_const_index_mapping.get(target_map.section_id) orelse unreachable;
966 const new_index = data_index_mapping.get(mapping.target_sect_id) orelse unreachable;985 } else if (self.data_segment_cmd_index.? == target_map.segment_id) {
967 mapping.target_sect_id = new_index;986 break :blk data_index_mapping.get(target_map.section_id) orelse unreachable;
968 } else unreachable;987 } else unreachable;
988 };
989
990 log.debug("remapping in {s}: '{s},{s}': {} => {}", .{
991 object.name.?,
992 parseName(&sect.inner.segname),
993 parseName(&sect.inner.sectname),
994 target_map.section_id,
995 new_index,
996 });
997
998 sect.target_map = .{
999 .segment_id = target_map.segment_id,
1000 .section_id = new_index,
1001 .offset = target_map.offset,
1002 };
1003 }
969 }1004 }
970}1005}
9711006
...@@ -1080,30 +1115,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {...@@ -1080,30 +1115,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
1080}1115}
10811116
1082fn allocateSymbols(self: *Zld) !void {1117fn allocateSymbols(self: *Zld) !void {
1083 for (self.objects.items) |object, object_id| {1118 for (self.objects.items) |object| {
1084 for (object.symbols.items) |sym| {1119 for (object.symbols.items) |sym| {
1085 const reg = sym.cast(Symbol.Regular) orelse continue;1120 const reg = sym.cast(Symbol.Regular) orelse continue;
10861121
1087 // TODO I am more and more convinced we should store the mapping as part of the Object struct.1122 const source_sect = &object.sections.items[reg.section];
1088 const target_mapping = self.mappings.get(.{1123 const target_map = source_sect.target_map orelse {
1089 .object_id = @intCast(u16, object_id),1124 log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{
1090 .source_sect_id = reg.section,1125 parseName(&source_sect.inner.segname),
1091 }) orelse {1126 parseName(&source_sect.inner.sectname),
1092 if (self.unhandled_sections.get(.{1127 sym.name,
1093 .object_id = @intCast(u16, object_id),1128 });
1094 .source_sect_id = reg.section,1129 continue;
1095 }) != null) continue;
1096
1097 log.err("section not mapped for symbol '{s}'", .{sym.name});
1098 return error.SectionNotMappedForSymbol;
1099 };1130 };
11001131
1101 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;1132 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1102 const source_sect = source_seg.sections.items[reg.section];1133 const target_sect = target_seg.sections.items[target_map.section_id];
1103 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;1134 const target_addr = target_sect.addr + target_map.offset;
1104 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];1135 const address = reg.address - source_sect.inner.addr + target_addr;
1105 const target_addr = target_sect.addr + target_mapping.offset;
1106 const address = reg.address - source_sect.addr + target_addr;
11071136
1108 log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address });1137 log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address });
11091138
...@@ -1111,8 +1140,8 @@ fn allocateSymbols(self: *Zld) !void {...@@ -1111,8 +1140,8 @@ fn allocateSymbols(self: *Zld) !void {
1111 var section: u8 = 0;1140 var section: u8 = 0;
1112 for (self.load_commands.items) |cmd, cmd_id| {1141 for (self.load_commands.items) |cmd, cmd_id| {
1113 if (cmd != .Segment) break;1142 if (cmd != .Segment) break;
1114 if (cmd_id == target_mapping.target_seg_id) {1143 if (cmd_id == target_map.segment_id) {
1115 section += @intCast(u8, target_mapping.target_sect_id) + 1;1144 section += @intCast(u8, target_map.section_id) + 1;
1116 break;1145 break;
1117 }1146 }
1118 section += @intCast(u8, cmd.Segment.sections.items.len);1147 section += @intCast(u8, cmd.Segment.sections.items.len);
...@@ -1124,6 +1153,74 @@ fn allocateSymbols(self: *Zld) !void {...@@ -1124,6 +1153,74 @@ fn allocateSymbols(self: *Zld) !void {
1124 }1153 }
1125}1154}
11261155
1156fn allocateTentativeSymbols(self: *Zld) !void {
1157 if (self.tentatives.values().len == 0) return;
1158
1159 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1160 const common_sect = &data_seg.sections.items[self.common_section_index.?];
1161
1162 const alignment = try math.powi(u32, 2, common_sect.@"align");
1163 var base_address: u64 = common_sect.addr + self.tentative_defs_offset;
1164
1165 log.debug("base address for tentative definitions 0x{x}", .{base_address});
1166
1167 // TODO there might be a more generic way of doing this.
1168 var section: u8 = 0;
1169 for (self.load_commands.items) |cmd, cmd_id| {
1170 if (cmd != .Segment) break;
1171 if (cmd_id == self.data_segment_cmd_index.?) {
1172 section += @intCast(u8, self.common_section_index.?) + 1;
1173 break;
1174 }
1175 section += @intCast(u8, cmd.Segment.sections.items.len);
1176 }
1177
1178 // Convert tentative definitions into regular symbols.
1179 for (self.tentatives.values()) |sym, i| {
1180 const tent = sym.cast(Symbol.Tentative) orelse unreachable;
1181 const reg = try self.allocator.create(Symbol.Regular);
1182 errdefer self.allocator.destroy(reg);
1183
1184 reg.* = .{
1185 .base = .{
1186 .@"type" = .regular,
1187 .name = try self.allocator.dupe(u8, tent.base.name),
1188 .got_index = tent.base.got_index,
1189 .stubs_index = tent.base.stubs_index,
1190 },
1191 .linkage = .global,
1192 .address = base_address,
1193 .section = section,
1194 .weak_ref = false,
1195 .file = tent.file,
1196 .stab = .{
1197 .kind = .global,
1198 .size = 0,
1199 },
1200 };
1201
1202 try self.globals.putNoClobber(self.allocator, reg.base.name, &reg.base);
1203 tent.base.alias = &reg.base;
1204
1205 if (tent.base.got_index) |idx| {
1206 self.got_entries.items[idx] = &reg.base;
1207 }
1208 if (tent.base.stubs_index) |idx| {
1209 self.stubs.items[idx] = &reg.base;
1210 }
1211
1212 const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);
1213
1214 log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{
1215 tent.base.name,
1216 base_address,
1217 address,
1218 });
1219
1220 base_address = address;
1221 }
1222}
1223
1127fn writeStubHelperCommon(self: *Zld) !void {1224fn writeStubHelperCommon(self: *Zld) !void {
1128 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1225 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1129 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];1226 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
...@@ -1399,6 +1496,10 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {...@@ -1399,6 +1496,10 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
1399 if (sym.cast(Symbol.Regular)) |reg| {1496 if (sym.cast(Symbol.Regular)) |reg| {
1400 if (reg.linkage == .translation_unit) continue; // Symbol local to TU.1497 if (reg.linkage == .translation_unit) continue; // Symbol local to TU.
14011498
1499 if (self.tentatives.fetchSwapRemove(sym.name)) |kv| {
1500 // Create link to the global.
1501 kv.value.alias = sym;
1502 }
1402 if (self.unresolved.fetchSwapRemove(sym.name)) |kv| {1503 if (self.unresolved.fetchSwapRemove(sym.name)) |kv| {
1403 // Create link to the global.1504 // Create link to the global.
1404 kv.value.alias = sym;1505 kv.value.alias = sym;
...@@ -1432,15 +1533,49 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {...@@ -1432,15 +1533,49 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
14321533
1433 g_sym.alias = sym;1534 g_sym.alias = sym;
1434 sym_ptr.* = sym;1535 sym_ptr.* = sym;
1536 } else if (sym.cast(Symbol.Tentative)) |tent| {
1537 if (self.globals.get(sym.name)) |g_sym| {
1538 sym.alias = g_sym;
1539 continue;
1540 }
1541
1542 if (self.unresolved.fetchSwapRemove(sym.name)) |kv| {
1543 kv.value.alias = sym;
1544 }
1545
1546 const sym_ptr = self.tentatives.getPtr(sym.name) orelse {
1547 // Put new tentative definition symbol into symbol table.
1548 try self.tentatives.putNoClobber(self.allocator, sym.name, sym);
1549 continue;
1550 };
1551
1552 // Compare by size and pick the largest tentative definition.
1553 // We model this like a heap where the tentative definition with the
1554 // largest size always washes up on top.
1555 const t_sym = sym_ptr.*;
1556 const t_tent = t_sym.cast(Symbol.Tentative) orelse unreachable;
1557
1558 if (tent.size < t_tent.size) {
1559 sym.alias = t_sym;
1560 continue;
1561 }
1562
1563 t_sym.alias = sym;
1564 sym_ptr.* = sym;
1435 } else if (sym.cast(Symbol.Unresolved)) |und| {1565 } else if (sym.cast(Symbol.Unresolved)) |und| {
1436 if (self.globals.get(sym.name)) |g_sym| {1566 if (self.globals.get(sym.name)) |g_sym| {
1437 sym.alias = g_sym;1567 sym.alias = g_sym;
1438 continue;1568 continue;
1439 }1569 }
1570 if (self.tentatives.get(sym.name)) |t_sym| {
1571 sym.alias = t_sym;
1572 continue;
1573 }
1440 if (self.unresolved.get(sym.name)) |u_sym| {1574 if (self.unresolved.get(sym.name)) |u_sym| {
1441 sym.alias = u_sym;1575 sym.alias = u_sym;
1442 continue;1576 continue;
1443 }1577 }
1578
1444 try self.unresolved.putNoClobber(self.allocator, sym.name, sym);1579 try self.unresolved.putNoClobber(self.allocator, sym.name, sym);
1445 } else unreachable;1580 } else unreachable;
1446 }1581 }
...@@ -1482,7 +1617,6 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1482,7 +1617,6 @@ fn resolveSymbols(self: *Zld) !void {
1482 next_sym += 1;1617 next_sym += 1;
1483 }1618 }
1484 }1619 }
1485
1486 // Third pass, resolve symbols in dynamic libraries.1620 // Third pass, resolve symbols in dynamic libraries.
1487 // TODO Implement libSystem as a hard-coded library, or ship with1621 // TODO Implement libSystem as a hard-coded library, or ship with
1488 // a libSystem.B.tbd definition file?1622 // a libSystem.B.tbd definition file?
...@@ -1602,10 +1736,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {...@@ -1602,10 +1736,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
1602}1736}
16031737
1604fn resolveRelocsAndWriteSections(self: *Zld) !void {1738fn resolveRelocsAndWriteSections(self: *Zld) !void {
1605 for (self.objects.items) |object, object_id| {1739 for (self.objects.items) |object| {
1606 log.debug("relocating object {s}", .{object.name});1740 log.debug("relocating object {s}", .{object.name});
16071741
1608 for (object.sections.items) |sect, source_sect_id| {1742 for (object.sections.items) |sect| {
1609 if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or1743 if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or
1610 sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue;1744 sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue;
16111745
...@@ -1614,18 +1748,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1614,18 +1748,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16141748
1615 log.debug("relocating section '{s},{s}'", .{ segname, sectname });1749 log.debug("relocating section '{s},{s}'", .{ segname, sectname });
16161750
1617 // Get mapping1751 // Get target mapping
1618 const target_mapping = self.mappings.get(.{1752 const target_map = sect.target_map orelse {
1619 .object_id = @intCast(u16, object_id),1753 log.debug("no mapping for '{s},{s}'; skipping", .{ segname, sectname });
1620 .source_sect_id = @intCast(u16, source_sect_id),
1621 }) orelse {
1622 log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname });
1623 continue;1754 continue;
1624 };1755 };
1625 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;1756 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1626 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];1757 const target_sect = target_seg.sections.items[target_map.section_id];
1627 const target_sect_addr = target_sect.addr + target_mapping.offset;1758 const target_sect_addr = target_sect.addr + target_map.offset;
1628 const target_sect_off = target_sect.offset + target_mapping.offset;1759 const target_sect_off = target_sect.offset + target_map.offset;
16291760
1630 if (sect.relocs) |relocs| {1761 if (sect.relocs) |relocs| {
1631 for (relocs) |rel| {1762 for (relocs) |rel| {
...@@ -1638,11 +1769,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1638,11 +1769,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16381769
1639 switch (rel.@"type") {1770 switch (rel.@"type") {
1640 .unsigned => {1771 .unsigned => {
1641 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);1772 args.target_addr = try self.relocTargetAddr(object, rel.target);
16421773
1643 const unsigned = rel.cast(reloc.Unsigned) orelse unreachable;1774 const unsigned = rel.cast(reloc.Unsigned) orelse unreachable;
1644 if (unsigned.subtractor) |subtractor| {1775 if (unsigned.subtractor) |subtractor| {
1645 args.subtractor = try self.relocTargetAddr(@intCast(u16, object_id), subtractor);1776 args.subtractor = try self.relocTargetAddr(object, subtractor);
1646 }1777 }
1647 if (rel.target == .section) {1778 if (rel.target == .section) {
1648 const source_sect = object.sections.items[rel.target.section];1779 const source_sect = object.sections.items[rel.target.section];
...@@ -1652,14 +1783,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1652,14 +1783,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16521783
1653 rebases: {1784 rebases: {
1654 var hit: bool = false;1785 var hit: bool = false;
1655 if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {1786 if (target_map.segment_id == self.data_segment_cmd_index.?) {
1656 if (self.data_section_index) |index| {1787 if (self.data_section_index) |index| {
1657 if (index == target_mapping.target_sect_id) hit = true;1788 if (index == target_map.section_id) hit = true;
1658 }1789 }
1659 }1790 }
1660 if (target_mapping.target_seg_id == self.data_const_segment_cmd_index.?) {1791 if (target_map.segment_id == self.data_const_segment_cmd_index.?) {
1661 if (self.data_const_section_index) |index| {1792 if (self.data_const_section_index) |index| {
1662 if (index == target_mapping.target_sect_id) hit = true;1793 if (index == target_map.section_id) hit = true;
1663 }1794 }
1664 }1795 }
16651796
...@@ -1667,7 +1798,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1667,7 +1798,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16671798
1668 try self.local_rebases.append(self.allocator, .{1799 try self.local_rebases.append(self.allocator, .{
1669 .offset = source_addr - target_seg.inner.vmaddr,1800 .offset = source_addr - target_seg.inner.vmaddr,
1670 .segment_id = target_mapping.target_seg_id,1801 .segment_id = target_map.segment_id,
1671 });1802 });
1672 }1803 }
1673 // TLV is handled via a separate offset mechanism.1804 // TLV is handled via a separate offset mechanism.
...@@ -1705,7 +1836,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1705,7 +1836,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1705 args.source_source_sect_addr = sect.inner.addr;1836 args.source_source_sect_addr = sect.inner.addr;
1706 args.source_target_sect_addr = source_sect.inner.addr;1837 args.source_target_sect_addr = source_sect.inner.addr;
1707 }1838 }
1708 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);1839 args.target_addr = try self.relocTargetAddr(object, rel.target);
1709 },1840 },
1710 }1841 }
17111842
...@@ -1744,7 +1875,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1744,7 +1875,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1744 }1875 }
1745}1876}
17461877
1747fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 {1878fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.Target) !u64 {
1748 const target_addr = blk: {1879 const target_addr = blk: {
1749 switch (target) {1880 switch (target) {
1750 .symbol => |sym| {1881 .symbol => |sym| {
...@@ -1770,13 +1901,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target)...@@ -1770,13 +1901,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target)
1770 }1901 }
1771 },1902 },
1772 .section => |sect_id| {1903 .section => |sect_id| {
1773 const target_mapping = self.mappings.get(.{1904 const source_sect = object.sections.items[sect_id];
1774 .object_id = object_id,1905 const target_map = source_sect.target_map orelse unreachable;
1775 .source_sect_id = sect_id,1906 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1776 }) orelse unreachable;1907 const target_sect = target_seg.sections.items[target_map.section_id];
1777 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;1908 break :blk target_sect.addr + target_map.offset;
1778 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1779 break :blk target_sect.addr + target_mapping.offset;
1780 },1909 },
1781 }1910 }
1782 };1911 };
...@@ -2646,8 +2775,17 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2646,8 +2775,17 @@ fn writeDebugInfo(self: *Zld) !void {
2646 });2775 });
26472776
2648 for (object.symbols.items) |sym| {2777 for (object.symbols.items) |sym| {
2649 if (sym.@"type" != .regular) continue;2778 const reg = reg: {
2650 const reg = sym.cast(Symbol.Regular) orelse unreachable;2779 switch (sym.@"type") {
2780 .regular => break :reg sym.cast(Symbol.Regular) orelse unreachable,
2781 .tentative => {
2782 const final = sym.getTopmostAlias().cast(Symbol.Regular) orelse unreachable;
2783 if (object != final.file) continue;
2784 break :reg final;
2785 },
2786 else => continue,
2787 }
2788 };
26512789
2652 if (reg.isTemp() or reg.stab == null) continue;2790 if (reg.isTemp() or reg.stab == null) continue;
2653 const stab = reg.stab orelse unreachable;2791 const stab = reg.stab orelse unreachable;
...@@ -2751,6 +2889,7 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2751,6 +2889,7 @@ fn writeSymbolTable(self: *Zld) !void {
27512889
2752 const reg = final.cast(Symbol.Regular) orelse unreachable;2890 const reg = final.cast(Symbol.Regular) orelse unreachable;
2753 if (reg.isTemp()) continue;2891 if (reg.isTemp()) continue;
2892 if (reg.visited) continue;
27542893
2755 switch (reg.linkage) {2894 switch (reg.linkage) {
2756 .translation_unit => {2895 .translation_unit => {
...@@ -2772,6 +2911,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2772,6 +2911,8 @@ fn writeSymbolTable(self: *Zld) !void {
2772 });2911 });
2773 },2912 },
2774 }2913 }
2914
2915 reg.visited = true;
2775 }2916 }
2776 }2917 }
27772918
...@@ -2901,20 +3042,16 @@ fn writeDataInCode(self: *Zld) !void {...@@ -2901,20 +3042,16 @@ fn writeDataInCode(self: *Zld) !void {
29013042
2902 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;3043 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2903 const text_sect = text_seg.sections.items[self.text_section_index.?];3044 const text_sect = text_seg.sections.items[self.text_section_index.?];
2904 for (self.objects.items) |object, object_id| {3045 for (self.objects.items) |object| {
2905 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;3046 const source_sect = object.sections.items[object.text_section_index.?];
2906 const source_sect = source_seg.sections.items[object.text_section_index.?];3047 const target_map = source_sect.target_map orelse continue;
2907 const target_mapping = self.mappings.get(.{
2908 .object_id = @intCast(u16, object_id),
2909 .source_sect_id = object.text_section_index.?,
2910 }) orelse continue;
29113048
2912 try buf.ensureCapacity(3049 try buf.ensureCapacity(
2913 buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),3050 buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),
2914 );3051 );
2915 for (object.data_in_code_entries.items) |dice| {3052 for (object.data_in_code_entries.items) |dice| {
2916 const new_dice: macho.data_in_code_entry = .{3053 const new_dice: macho.data_in_code_entry = .{
2917 .offset = text_sect.offset + target_mapping.offset + dice.offset,3054 .offset = text_sect.offset + target_map.offset + dice.offset,
2918 .length = dice.length,3055 .length = dice.length,
2919 .kind = dice.kind,3056 .kind = dice.kind,
2920 };3057 };
test/standalone.zig+1
...@@ -15,6 +15,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {...@@ -15,6 +15,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
15 cases.addBuildFile("test/standalone/static_c_lib/build.zig", .{});15 cases.addBuildFile("test/standalone/static_c_lib/build.zig", .{});
16 cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig", .{});16 cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig", .{});
17 cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig", .{});17 cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig", .{});
18 cases.addBuildFile("test/standalone/link_common_symbols/build.zig", .{});
18 cases.addBuildFile("test/standalone/issue_339/build.zig", .{});19 cases.addBuildFile("test/standalone/issue_339/build.zig", .{});
19 cases.addBuildFile("test/standalone/issue_8550/build.zig", .{});20 cases.addBuildFile("test/standalone/issue_8550/build.zig", .{});
20 cases.addBuildFile("test/standalone/issue_794/build.zig", .{});21 cases.addBuildFile("test/standalone/issue_794/build.zig", .{});
test/standalone/link_common_symbols/a.c created+6
...@@ -0,0 +1,6 @@
1int i;
2int j;
3
4int add_to_i_and_j(int x) {
5 return x + i + j;
6}
test/standalone/link_common_symbols/b.c created+6
...@@ -0,0 +1,6 @@
1long i;
2int j = 2;
3
4void incr_i() {
5 i++;
6}
test/standalone/link_common_symbols/build.zig created+16
...@@ -0,0 +1,16 @@
1const Builder = @import("std").build.Builder;
2
3pub fn build(b: *Builder) void {
4 const mode = b.standardReleaseOptions();
5
6 const lib_a = b.addStaticLibrary("a", null);
7 lib_a.addCSourceFiles(&.{ "a.c", "b.c" }, &.{"-fcommon"});
8 lib_a.setBuildMode(mode);
9
10 const test_exe = b.addTest("main.zig");
11 test_exe.setBuildMode(mode);
12 test_exe.linkLibrary(lib_a);
13
14 const test_step = b.step("test", "Test it");
15 test_step.dependOn(&test_exe.step);
16}
test/standalone/link_common_symbols/main.zig created+11
...@@ -0,0 +1,11 @@
1const std = @import("std");
2const expect = std.testing.expect;
3
4extern fn incr_i() void;
5extern fn add_to_i_and_j(x: c_int) c_int;
6
7test "import C common symbols" {
8 incr_i();
9 const res = add_to_i_and_j(2);
10 try expect(res == 5);
11}