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 {
5454 inner: macho.section_64,
5555 code: []u8,
5656 relocs: ?[]*Relocation,
57 target_map: ?struct {
58 segment_id: u16,
59 section_id: u16,
60 offset: u32,
61 } = null,
5762
5863 pub fn deinit(self: *Section, allocator: *Allocator) void {
5964 allocator.free(self.code);
......@@ -346,15 +351,15 @@ pub fn parseSymbols(self: *Object) !void {
346351 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
347352
348353 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.? });
350355 return error.UnhandledSymbolType;
351356 }
352357 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.? });
354359 return error.UnhandledSymbolType;
355360 }
356361 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.? });
358363 return error.UnhandledSymbolType;
359364 }
360365
......@@ -383,11 +388,18 @@ pub fn parseSymbols(self: *Object) !void {
383388 }
384389
385390 if (sym.n_value != 0) {
386 log.err("common symbol {s} in {s}", .{ sym_name, self.name.? });
387 return error.UnhandledSymbolType;
388 // const comm_size = sym.n_value;
389 // const comm_align = (sym.n_desc >> 8) & 0x0f;
390 // log.warn("Common symbol: size 0x{x}, align 0x{x}", .{ comm_size, comm_align });
391 const tentative = try self.allocator.create(Symbol.Tentative);
392 errdefer self.allocator.destroy(tentative);
393 tentative.* = .{
394 .base = .{
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;
391403 }
392404
393405 const undef = try self.allocator.create(Symbol.Unresolved);
src/link/MachO/Symbol.zig+20
......@@ -12,6 +12,7 @@ pub const Type = enum {
1212 regular,
1313 proxy,
1414 unresolved,
15 tentative,
1516};
1617
1718/// Symbol type.
......@@ -60,6 +61,10 @@ pub const Regular = struct {
6061 size: u64,
6162 } = null,
6263
64 /// True if symbol was already committed into the final
65 /// symbol table.
66 visited: bool = false,
67
6368 pub const base_type: Symbol.Type = .regular;
6469
6570 pub const Linkage = enum {
......@@ -94,6 +99,21 @@ pub const Unresolved = struct {
9499 pub const base_type: Symbol.Type = .unresolved;
95100};
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
97117pub fn deinit(base: *Symbol, allocator: *Allocator) void {
98118 allocator.free(base.name);
99119}
src/link/MachO/Zld.zig+257-120
......@@ -84,6 +84,11 @@ common_section_index: ?u16 = null,
8484globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
8585imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
8686unresolved: 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
8893strtab: std.ArrayListUnmanaged(u8) = .{},
8994strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
......@@ -95,9 +100,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
95100
96101stub_helper_stubs_start_off: ?u64 = null,
97102
98mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
99unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
100
101103const TlvOffset = struct {
102104 source_addr: u64,
103105 offset: u64,
......@@ -107,18 +109,6 @@ const TlvOffset = struct {
107109 }
108110};
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
122112/// Default path to dyld
123113const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
124114
......@@ -159,9 +149,7 @@ pub fn deinit(self: *Zld) void {
159149 }
160150 self.dylibs.deinit(self.allocator);
161151
162 self.mappings.deinit(self.allocator);
163 self.unhandled_sections.deinit(self.allocator);
164
152 self.tentatives.deinit(self.allocator);
165153 self.globals.deinit(self.allocator);
166154 self.imports.deinit(self.allocator);
167155 self.unresolved.deinit(self.allocator);
......@@ -239,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
239227 try self.allocateDataSegment();
240228 self.allocateLinkeditSegment();
241229 try self.allocateSymbols();
230 try self.allocateTentativeSymbols();
242231 try self.flush();
243232}
244233
......@@ -407,46 +396,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
407396
408397fn mapAndUpdateSections(
409398 self: *Zld,
410 object_id: u16,
399 object: *Object,
411400 source_sect_id: u16,
412401 target_seg_id: u16,
413402 target_sect_id: u16,
414403) !void {
415 const object = self.objects.items[object_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];
404 const source_sect = &object.sections.items[source_sect_id];
418405 const target_seg = &self.load_commands.items[target_seg_id].Segment;
419406 const target_sect = &target_seg.sections.items[target_sect_id];
420407
421408 const alignment = try math.powi(u32, 2, target_sect.@"align");
422409 const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);
423 const size = mem.alignForwardGeneric(u64, source_sect.size, alignment);
424 const key = MappingKey{
425 .object_id = object_id,
426 .source_sect_id = source_sect_id,
427 };
428 try self.mappings.putNoClobber(self.allocator, key, .{
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),
410 const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment);
411
412 log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
413 object.name.?,
414 parseName(&source_sect.inner.segname),
415 parseName(&source_sect.inner.sectname),
438416 parseName(&target_sect.segname),
439417 parseName(&target_sect.sectname),
440418 offset,
441419 offset + size,
442420 });
443421
422 source_sect.target_map = .{
423 .segment_id = target_seg_id,
424 .section_id = target_sect_id,
425 .offset = @intCast(u32, offset),
426 };
444427 target_sect.size = offset + size;
445428}
446429
447430fn updateMetadata(self: *Zld) !void {
448 for (self.objects.items) |object, id| {
449 const object_id = @intCast(u16, id);
431 for (self.objects.items) |object| {
450432 const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
451433 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
452434 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
......@@ -699,20 +681,57 @@ fn updateMetadata(self: *Zld) !void {
699681 for (object_seg.sections.items) |source_sect, sect_id| {
700682 const source_sect_id = @intCast(u16, sect_id);
701683 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);
703685 continue;
704686 }
705687
706 const segname = parseName(&source_sect.segname);
707 const sectname = parseName(&source_sect.sectname);
708
709 log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });
688 log.debug("section '{s},{s}' will be unmapped", .{
689 parseName(&source_sect.segname),
690 parseName(&source_sect.sectname),
691 });
692 }
693 }
710694
711 try self.unhandled_sections.putNoClobber(self.allocator, .{
712 .object_id = object_id,
713 .source_sect_id = source_sect_id,
714 }, 0);
695 // Ensure we have __DATA,__common section if we have tentative definitions.
696 // Update size and alignment of __DATA,__common section.
697 if (self.tentatives.values().len > 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;
715725 }
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;
716735 }
717736
718737 tlv_align: {
......@@ -954,18 +973,34 @@ fn sortSections(self: *Zld) !void {
954973 }
955974 }
956975
957 var it = self.mappings.valueIterator();
958 while (it.next()) |mapping| {
959 if (self.text_segment_cmd_index.? == mapping.target_seg_id) {
960 const new_index = text_index_mapping.get(mapping.target_sect_id) orelse unreachable;
961 mapping.target_sect_id = new_index;
962 } else if (self.data_const_segment_cmd_index.? == mapping.target_seg_id) {
963 const new_index = data_const_index_mapping.get(mapping.target_sect_id) orelse unreachable;
964 mapping.target_sect_id = new_index;
965 } else if (self.data_segment_cmd_index.? == mapping.target_seg_id) {
966 const new_index = data_index_mapping.get(mapping.target_sect_id) orelse unreachable;
967 mapping.target_sect_id = new_index;
968 } else unreachable;
976 for (self.objects.items) |object| {
977 for (object.sections.items) |*sect| {
978 const target_map = sect.target_map orelse continue;
979
980 const new_index = blk: {
981 if (self.text_segment_cmd_index.? == target_map.segment_id) {
982 break :blk text_index_mapping.get(target_map.section_id) orelse unreachable;
983 } else if (self.data_const_segment_cmd_index.? == target_map.segment_id) {
984 break :blk data_const_index_mapping.get(target_map.section_id) orelse unreachable;
985 } else if (self.data_segment_cmd_index.? == target_map.segment_id) {
986 break :blk data_index_mapping.get(target_map.section_id) orelse 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 }
9691004 }
9701005}
9711006
......@@ -1080,30 +1115,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
10801115}
10811116
10821117fn allocateSymbols(self: *Zld) !void {
1083 for (self.objects.items) |object, object_id| {
1118 for (self.objects.items) |object| {
10841119 for (object.symbols.items) |sym| {
10851120 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.
1088 const target_mapping = self.mappings.get(.{
1089 .object_id = @intCast(u16, object_id),
1090 .source_sect_id = reg.section,
1091 }) orelse {
1092 if (self.unhandled_sections.get(.{
1093 .object_id = @intCast(u16, object_id),
1094 .source_sect_id = reg.section,
1095 }) != null) continue;
1096
1097 log.err("section not mapped for symbol '{s}'", .{sym.name});
1098 return error.SectionNotMappedForSymbol;
1122 const source_sect = &object.sections.items[reg.section];
1123 const target_map = source_sect.target_map orelse {
1124 log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{
1125 parseName(&source_sect.inner.segname),
1126 parseName(&source_sect.inner.sectname),
1127 sym.name,
1128 });
1129 continue;
10991130 };
11001131
1101 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
1102 const source_sect = source_seg.sections.items[reg.section];
1103 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1104 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1105 const target_addr = target_sect.addr + target_mapping.offset;
1106 const address = reg.address - source_sect.addr + target_addr;
1132 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1133 const target_sect = target_seg.sections.items[target_map.section_id];
1134 const target_addr = target_sect.addr + target_map.offset;
1135 const address = reg.address - source_sect.inner.addr + target_addr;
11071136
11081137 log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address });
11091138
......@@ -1111,8 +1140,8 @@ fn allocateSymbols(self: *Zld) !void {
11111140 var section: u8 = 0;
11121141 for (self.load_commands.items) |cmd, cmd_id| {
11131142 if (cmd != .Segment) break;
1114 if (cmd_id == target_mapping.target_seg_id) {
1115 section += @intCast(u8, target_mapping.target_sect_id) + 1;
1143 if (cmd_id == target_map.segment_id) {
1144 section += @intCast(u8, target_map.section_id) + 1;
11161145 break;
11171146 }
11181147 section += @intCast(u8, cmd.Segment.sections.items.len);
......@@ -1124,6 +1153,74 @@ fn allocateSymbols(self: *Zld) !void {
11241153 }
11251154}
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
11271224fn writeStubHelperCommon(self: *Zld) !void {
11281225 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
11291226 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1399,6 +1496,10 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
13991496 if (sym.cast(Symbol.Regular)) |reg| {
14001497 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 }
14021503 if (self.unresolved.fetchSwapRemove(sym.name)) |kv| {
14031504 // Create link to the global.
14041505 kv.value.alias = sym;
......@@ -1432,15 +1533,49 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
14321533
14331534 g_sym.alias = sym;
14341535 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;
14351565 } else if (sym.cast(Symbol.Unresolved)) |und| {
14361566 if (self.globals.get(sym.name)) |g_sym| {
14371567 sym.alias = g_sym;
14381568 continue;
14391569 }
1570 if (self.tentatives.get(sym.name)) |t_sym| {
1571 sym.alias = t_sym;
1572 continue;
1573 }
14401574 if (self.unresolved.get(sym.name)) |u_sym| {
14411575 sym.alias = u_sym;
14421576 continue;
14431577 }
1578
14441579 try self.unresolved.putNoClobber(self.allocator, sym.name, sym);
14451580 } else unreachable;
14461581 }
......@@ -1482,7 +1617,6 @@ fn resolveSymbols(self: *Zld) !void {
14821617 next_sym += 1;
14831618 }
14841619 }
1485
14861620 // Third pass, resolve symbols in dynamic libraries.
14871621 // TODO Implement libSystem as a hard-coded library, or ship with
14881622 // a libSystem.B.tbd definition file?
......@@ -1602,10 +1736,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
16021736}
16031737
16041738fn resolveRelocsAndWriteSections(self: *Zld) !void {
1605 for (self.objects.items) |object, object_id| {
1739 for (self.objects.items) |object| {
16061740 log.debug("relocating object {s}", .{object.name});
16071741
1608 for (object.sections.items) |sect, source_sect_id| {
1742 for (object.sections.items) |sect| {
16091743 if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or
16101744 sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue;
16111745
......@@ -1614,18 +1748,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16141748
16151749 log.debug("relocating section '{s},{s}'", .{ segname, sectname });
16161750
1617 // Get mapping
1618 const target_mapping = self.mappings.get(.{
1619 .object_id = @intCast(u16, object_id),
1620 .source_sect_id = @intCast(u16, source_sect_id),
1621 }) orelse {
1622 log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname });
1751 // Get target mapping
1752 const target_map = sect.target_map orelse {
1753 log.debug("no mapping for '{s},{s}'; skipping", .{ segname, sectname });
16231754 continue;
16241755 };
1625 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1626 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1627 const target_sect_addr = target_sect.addr + target_mapping.offset;
1628 const target_sect_off = target_sect.offset + target_mapping.offset;
1756 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1757 const target_sect = target_seg.sections.items[target_map.section_id];
1758 const target_sect_addr = target_sect.addr + target_map.offset;
1759 const target_sect_off = target_sect.offset + target_map.offset;
16291760
16301761 if (sect.relocs) |relocs| {
16311762 for (relocs) |rel| {
......@@ -1638,11 +1769,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16381769
16391770 switch (rel.@"type") {
16401771 .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
16431774 const unsigned = rel.cast(reloc.Unsigned) orelse unreachable;
16441775 if (unsigned.subtractor) |subtractor| {
1645 args.subtractor = try self.relocTargetAddr(@intCast(u16, object_id), subtractor);
1776 args.subtractor = try self.relocTargetAddr(object, subtractor);
16461777 }
16471778 if (rel.target == .section) {
16481779 const source_sect = object.sections.items[rel.target.section];
......@@ -1652,14 +1783,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16521783
16531784 rebases: {
16541785 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.?) {
16561787 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;
16581789 }
16591790 }
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.?) {
16611792 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;
16631794 }
16641795 }
16651796
......@@ -1667,7 +1798,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
16671798
16681799 try self.local_rebases.append(self.allocator, .{
16691800 .offset = source_addr - target_seg.inner.vmaddr,
1670 .segment_id = target_mapping.target_seg_id,
1801 .segment_id = target_map.segment_id,
16711802 });
16721803 }
16731804 // TLV is handled via a separate offset mechanism.
......@@ -1705,7 +1836,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
17051836 args.source_source_sect_addr = sect.inner.addr;
17061837 args.source_target_sect_addr = source_sect.inner.addr;
17071838 }
1708 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
1839 args.target_addr = try self.relocTargetAddr(object, rel.target);
17091840 },
17101841 }
17111842
......@@ -1744,7 +1875,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
17441875 }
17451876}
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 {
17481879 const target_addr = blk: {
17491880 switch (target) {
17501881 .symbol => |sym| {
......@@ -1770,13 +1901,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target)
17701901 }
17711902 },
17721903 .section => |sect_id| {
1773 const target_mapping = self.mappings.get(.{
1774 .object_id = object_id,
1775 .source_sect_id = sect_id,
1776 }) orelse unreachable;
1777 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1778 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1779 break :blk target_sect.addr + target_mapping.offset;
1904 const source_sect = object.sections.items[sect_id];
1905 const target_map = source_sect.target_map orelse unreachable;
1906 const target_seg = self.load_commands.items[target_map.segment_id].Segment;
1907 const target_sect = target_seg.sections.items[target_map.section_id];
1908 break :blk target_sect.addr + target_map.offset;
17801909 },
17811910 }
17821911 };
......@@ -2646,8 +2775,17 @@ fn writeDebugInfo(self: *Zld) !void {
26462775 });
26472776
26482777 for (object.symbols.items) |sym| {
2649 if (sym.@"type" != .regular) continue;
2650 const reg = sym.cast(Symbol.Regular) orelse unreachable;
2778 const reg = reg: {
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
26522790 if (reg.isTemp() or reg.stab == null) continue;
26532791 const stab = reg.stab orelse unreachable;
......@@ -2751,6 +2889,7 @@ fn writeSymbolTable(self: *Zld) !void {
27512889
27522890 const reg = final.cast(Symbol.Regular) orelse unreachable;
27532891 if (reg.isTemp()) continue;
2892 if (reg.visited) continue;
27542893
27552894 switch (reg.linkage) {
27562895 .translation_unit => {
......@@ -2772,6 +2911,8 @@ fn writeSymbolTable(self: *Zld) !void {
27722911 });
27732912 },
27742913 }
2914
2915 reg.visited = true;
27752916 }
27762917 }
27772918
......@@ -2901,20 +3042,16 @@ fn writeDataInCode(self: *Zld) !void {
29013042
29023043 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
29033044 const text_sect = text_seg.sections.items[self.text_section_index.?];
2904 for (self.objects.items) |object, object_id| {
2905 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
2906 const source_sect = source_seg.sections.items[object.text_section_index.?];
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;
3045 for (self.objects.items) |object| {
3046 const source_sect = object.sections.items[object.text_section_index.?];
3047 const target_map = source_sect.target_map orelse continue;
29113048
29123049 try buf.ensureCapacity(
29133050 buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),
29143051 );
29153052 for (object.data_in_code_entries.items) |dice| {
29163053 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,
29183055 .length = dice.length,
29193056 .kind = dice.kind,
29203057 };
test/standalone.zig+1
......@@ -15,6 +15,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
1515 cases.addBuildFile("test/standalone/static_c_lib/build.zig", .{});
1616 cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig", .{});
1717 cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig", .{});
18 cases.addBuildFile("test/standalone/link_common_symbols/build.zig", .{});
1819 cases.addBuildFile("test/standalone/issue_339/build.zig", .{});
1920 cases.addBuildFile("test/standalone/issue_8550/build.zig", .{});
2021 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}