authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-08 17:35:56+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-11-08 17:35:56+01:00
log0b4d398c40d4dde23c1770f7a9a0c22417f6d51f
treee3781c7d91e49fe258963cc8ec50bde485afe9c5
parenta16e6706b337e2c7247238d08f205594d777a63a

elf: streamline codepaths for different linker modes (object, ar, exe/dyn)


1 files changed, 464 insertions(+), 355 deletions(-)

src/link/Elf.zig+464-355
......@@ -959,6 +959,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
959959 } else null;
960960 const gc_sections = self.base.options.gc_sections orelse false;
961961
962 // --verbose-link
963 if (self.base.options.verbose_link) try self.dumpArgv(comp);
964
962965 var csu = try CsuObjects.init(arena, self.base.options, comp);
963966 const compiler_rt_path: ?[]const u8 = blk: {
964967 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
......@@ -966,247 +969,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
966969 break :blk null;
967970 };
968971
969 // --verbose-link
970 if (self.base.options.verbose_link) {
971 var argv = std.ArrayList([]const u8).init(arena);
972
973 try argv.append("zig");
974 try argv.append("ld");
975
976 try argv.append("-o");
977 try argv.append(full_out_path);
978
979 if (self.base.options.entry) |entry| {
980 try argv.append("--entry");
981 try argv.append(entry);
982 }
983
984 if (self.base.options.dynamic_linker) |path| {
985 try argv.append("-dynamic-linker");
986 try argv.append(path);
987 }
988
989 if (self.base.options.soname) |name| {
990 try argv.append("-soname");
991 try argv.append(name);
992 }
993
994 for (self.base.options.rpath_list) |rpath| {
995 try argv.append("-rpath");
996 try argv.append(rpath);
997 }
998
999 if (self.base.options.each_lib_rpath) {
1000 for (self.base.options.lib_dirs) |lib_dir_path| {
1001 try argv.append("-rpath");
1002 try argv.append(lib_dir_path);
1003 }
1004 for (self.base.options.objects) |obj| {
1005 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
1006 const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
1007 if (obj.loption) continue;
1008
1009 try argv.append("-rpath");
1010 try argv.append(lib_dir_path);
1011 }
1012 }
1013 }
1014
1015 if (self.base.options.stack_size_override) |ss| {
1016 try argv.append("-z");
1017 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
1018 }
1019
1020 if (self.base.options.image_base_override) |image_base| {
1021 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1022 }
1023
1024 if (gc_sections) {
1025 try argv.append("--gc-sections");
1026 }
1027
1028 if (self.base.options.print_gc_sections) {
1029 try argv.append("--print-gc-sections");
1030 }
1031
1032 if (self.base.options.eh_frame_hdr) {
1033 try argv.append("--eh-frame-hdr");
1034 }
1035
1036 if (self.base.options.rdynamic) {
1037 try argv.append("--export-dynamic");
1038 }
1039
1040 if (self.base.options.strip) {
1041 try argv.append("-s");
1042 }
1043
1044 if (self.base.options.z_notext) {
1045 try argv.append("-z");
1046 try argv.append("notext");
1047 }
1048
1049 if (self.base.options.z_nocopyreloc) {
1050 try argv.append("-z");
1051 try argv.append("nocopyreloc");
1052 }
1053
1054 if (self.base.options.z_now) {
1055 try argv.append("-z");
1056 try argv.append("now");
1057 }
1058
1059 if (self.isStatic()) {
1060 try argv.append("-static");
1061 } else if (self.isDynLib()) {
1062 try argv.append("-shared");
1063 }
1064
1065 if (self.base.options.pie and self.isExe()) {
1066 try argv.append("-pie");
1067 }
1068
1069 // csu prelude
1070 if (csu.crt0) |v| try argv.append(v);
1071 if (csu.crti) |v| try argv.append(v);
1072 if (csu.crtbegin) |v| try argv.append(v);
1073
1074 for (self.base.options.lib_dirs) |lib_dir| {
1075 try argv.append("-L");
1076 try argv.append(lib_dir);
1077 }
1078
1079 if (self.base.options.link_libc) {
1080 if (self.base.options.libc_installation) |libc_installation| {
1081 try argv.append("-L");
1082 try argv.append(libc_installation.crt_dir.?);
1083 }
1084 }
1085
1086 var whole_archive = false;
1087 for (self.base.options.objects) |obj| {
1088 if (obj.must_link and !whole_archive) {
1089 try argv.append("-whole-archive");
1090 whole_archive = true;
1091 } else if (!obj.must_link and whole_archive) {
1092 try argv.append("-no-whole-archive");
1093 whole_archive = false;
1094 }
1095
1096 if (obj.loption) {
1097 assert(obj.path[0] == ':');
1098 try argv.append("-l");
1099 }
1100 try argv.append(obj.path);
1101 }
1102 if (whole_archive) {
1103 try argv.append("-no-whole-archive");
1104 whole_archive = false;
1105 }
1106
1107 for (comp.c_object_table.keys()) |key| {
1108 try argv.append(key.status.success.object_path);
1109 }
1110
1111 if (module_obj_path) |p| {
1112 try argv.append(p);
1113 }
1114
1115 // TSAN
1116 if (self.base.options.tsan) {
1117 try argv.append(comp.tsan_static_lib.?.full_object_path);
1118 }
1119
1120 // libc
1121 if (!self.base.options.skip_linker_dependencies and
1122 !self.base.options.link_libc)
1123 {
1124 if (comp.libc_static_lib) |lib| {
1125 try argv.append(lib.full_object_path);
1126 }
1127 }
1128
1129 // stack-protector.
1130 // Related: https://github.com/ziglang/zig/issues/7265
1131 if (comp.libssp_static_lib) |ssp| {
1132 try argv.append(ssp.full_object_path);
1133 }
1134
1135 // Shared libraries.
1136 // Worst-case, we need an --as-needed argument for every lib, as well
1137 // as one before and one after.
1138 try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
1139 argv.appendAssumeCapacity("--as-needed");
1140 var as_needed = true;
1141
1142 for (self.base.options.system_libs.values()) |lib_info| {
1143 const lib_as_needed = !lib_info.needed;
1144 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1145 0b00, 0b11 => {},
1146 0b01 => {
1147 argv.appendAssumeCapacity("--no-as-needed");
1148 as_needed = false;
1149 },
1150 0b10 => {
1151 argv.appendAssumeCapacity("--as-needed");
1152 as_needed = true;
1153 },
1154 }
1155 argv.appendAssumeCapacity(lib_info.path.?);
1156 }
1157
1158 if (!as_needed) {
1159 argv.appendAssumeCapacity("--as-needed");
1160 as_needed = true;
1161 }
1162
1163 // libc++ dep
1164 if (self.base.options.link_libcpp) {
1165 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1166 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1167 }
1168
1169 // libunwind dep
1170 if (self.base.options.link_libunwind) {
1171 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1172 }
1173
1174 // libc dep
1175 if (self.base.options.link_libc) {
1176 if (self.base.options.libc_installation != null) {
1177 const needs_grouping = self.base.options.link_mode == .Static;
1178 if (needs_grouping) try argv.append("--start-group");
1179 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1180 if (needs_grouping) try argv.append("--end-group");
1181 } else if (target.isGnuLibC()) {
1182 for (glibc.libs) |lib| {
1183 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1184 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1185 });
1186 try argv.append(lib_path);
1187 }
1188 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1189 } else if (target.isMusl()) {
1190 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1191 .Static => "libc.a",
1192 .Dynamic => "libc.so",
1193 }));
1194 }
1195 }
1196
1197 // compiler-rt
1198 if (compiler_rt_path) |p| {
1199 try argv.append(p);
1200 }
1201
1202 // crt postlude
1203 if (csu.crtend) |v| try argv.append(v);
1204 if (csu.crtn) |v| try argv.append(v);
1205
1206 Compilation.dump_argv(argv.items);
1207 }
1208
1209972 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
973 if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path);
974 if (self.isObject()) return self.flushObject(comp, module_obj_path);
1210975
1211976 // Here we will parse input positional and library files (if referenced).
1212977 // This will roughly match in any linker backend we support.
......@@ -1232,6 +997,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1232997 // rpaths
1233998 var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);
1234999 defer rpath_table.deinit();
1000
12351001 for (self.base.options.rpath_list) |rpath| {
12361002 _ = try rpath_table.put(rpath, {});
12371003 }
......@@ -1380,8 +1146,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13801146 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
13811147 }
13821148
1383 if (self.isStaticLib()) return self.flushStaticLib();
1384
13851149 // Init all objects
13861150 for (self.objects.items) |index| {
13871151 try self.file(index).?.object.init(self);
......@@ -1410,7 +1174,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14101174
14111175 // If we haven't already, create a linker-generated input file comprising of
14121176 // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
1413 if (self.linker_defined_index == null and !self.isRelocatable()) {
1177 if (self.linker_defined_index == null) {
14141178 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
14151179 self.files.set(index, .{ .linker_defined = .{ .index = index } });
14161180 self.linker_defined_index = index;
......@@ -1424,8 +1188,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14241188 self.resolveSymbols();
14251189 self.markEhFrameAtomsDead();
14261190
1427 if (self.isObject()) return self.flushObject();
1428
14291191 try self.convertCommonSymbols();
14301192 self.markImportsExports();
14311193
......@@ -1519,145 +1281,490 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15191281 }
15201282}
15211283
1522pub fn flushStaticLib(self: *Elf) link.File.FlushError!void {
1523 const gpa = self.base.allocator;
1284pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1285 const gpa = self.base.allocator;
1286
1287 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
1288 defer positionals.deinit();
1289
1290 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
1291 positionals.appendSliceAssumeCapacity(self.base.options.objects);
1292
1293 // This is a set of object files emitted by clang in a single `build-exe` invocation.
1294 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
1295 // in this set.
1296 for (comp.c_object_table.keys()) |key| {
1297 try positionals.append(.{ .path = key.status.success.object_path });
1298 }
1299
1300 if (module_obj_path) |path| try positionals.append(.{ .path = path });
1301
1302 for (positionals.items) |obj| {
1303 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1304 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
1305 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1306 }
1307
1308 // First, we flush relocatable object file generated with our backends.
1309 if (self.zigObjectPtr()) |zig_object| {
1310 zig_object.resolveSymbols(self);
1311 zig_object.claimUnresolvedObject(self);
1312
1313 try self.initSymtab();
1314 try self.initShStrtab();
1315 try self.sortShdrs();
1316 try zig_object.addAtomsToRelaSections(self);
1317 try self.updateSectionSizesObject();
1318
1319 try self.allocateNonAllocSections();
1320
1321 if (build_options.enable_logging) {
1322 state_log.debug("{}", .{self.dumpState()});
1323 }
1324
1325 try self.writeSyntheticSectionsObject();
1326 try self.writeShdrTable();
1327 try self.writeElfHeader();
1328 }
1329
1330 var files = std.ArrayList(File.Index).init(gpa);
1331 defer files.deinit();
1332 try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);
1333 // Note to self: we currently must have ZigObject written out first as we write the object
1334 // file into the same file descriptor and then re-read its contents.
1335 // TODO implement writing ZigObject to a buffer instead of file.
1336 if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index);
1337 for (self.objects.items) |index| files.appendAssumeCapacity(index);
1338
1339 // Update ar symtab from parsed objects
1340 var ar_symtab: Archive.ArSymtab = .{};
1341 defer ar_symtab.deinit(gpa);
1342
1343 for (files.items) |index| {
1344 try self.file(index).?.updateArSymtab(&ar_symtab, self);
1345 }
1346
1347 ar_symtab.sort();
1348
1349 // Save object paths in filenames strtab.
1350 var ar_strtab: Archive.ArStrtab = .{};
1351 defer ar_strtab.deinit(gpa);
1352
1353 for (files.items) |index| {
1354 const file_ptr = self.file(index).?;
1355 try file_ptr.updateArStrtab(gpa, &ar_strtab);
1356 file_ptr.updateArSize(self);
1357 }
1358
1359 // Update file offsets of contributing objects.
1360 const total_size: usize = blk: {
1361 var pos: usize = elf.ARMAG.len;
1362 pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64);
1363
1364 if (ar_strtab.size() > 0) {
1365 pos = mem.alignForward(usize, pos, 2);
1366 pos += @sizeOf(elf.ar_hdr) + ar_strtab.size();
1367 }
1368
1369 for (files.items) |index| {
1370 const file_ptr = self.file(index).?;
1371 const state = switch (file_ptr) {
1372 .zig_object => |x| &x.output_ar_state,
1373 .object => |x| &x.output_ar_state,
1374 else => unreachable,
1375 };
1376 pos = mem.alignForward(usize, pos, 2);
1377 state.file_off = pos;
1378 pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
1379 }
1380
1381 break :blk pos;
1382 };
1383
1384 if (build_options.enable_logging) {
1385 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1386 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
1387 }
1388
1389 var buffer = std.ArrayList(u8).init(gpa);
1390 defer buffer.deinit();
1391 try buffer.ensureTotalCapacityPrecise(total_size);
1392
1393 // Write magic
1394 try buffer.writer().writeAll(elf.ARMAG);
1395
1396 // Write symtab
1397 try ar_symtab.write(.p64, self, buffer.writer());
1398
1399 // Write strtab
1400 if (ar_strtab.size() > 0) {
1401 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1402 try ar_strtab.write(buffer.writer());
1403 }
1404
1405 // Write object files
1406 for (files.items) |index| {
1407 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1408 try self.file(index).?.writeAr(self, buffer.writer());
1409 }
1410
1411 assert(buffer.items.len == total_size);
1412
1413 try self.base.file.?.setEndPos(total_size);
1414 try self.base.file.?.pwriteAll(buffer.items, 0);
1415}
1416
1417pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
1418 const gpa = self.base.allocator;
1419
1420 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
1421 defer positionals.deinit();
1422 try positionals.ensureUnusedCapacity(self.base.options.objects.len);
1423 positionals.appendSliceAssumeCapacity(self.base.options.objects);
1424
1425 // This is a set of object files emitted by clang in a single `build-exe` invocation.
1426 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
1427 // in this set.
1428 for (comp.c_object_table.keys()) |key| {
1429 try positionals.append(.{ .path = key.status.success.object_path });
1430 }
1431
1432 if (module_obj_path) |path| try positionals.append(.{ .path = path });
1433
1434 for (positionals.items) |obj| {
1435 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1436 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
1437 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1438 }
1439
1440 // Init all objects
1441 for (self.objects.items) |index| {
1442 try self.file(index).?.object.init(self);
1443 }
1444
1445 // Now, we are ready to resolve the symbols across all input files.
1446 // We will first resolve the files in the ZigObject, next in the parsed
1447 // input Object files.
1448 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1449 // symbol for potential resolution at load-time.
1450 self.resolveSymbols();
1451 self.markEhFrameAtomsDead();
1452 self.claimUnresolvedObject();
1453
1454 try self.initSectionsObject();
1455 try self.sortShdrs();
1456 if (self.zigObjectPtr()) |zig_object| {
1457 try zig_object.addAtomsToRelaSections(self);
1458 }
1459 for (self.objects.items) |index| {
1460 const object = self.file(index).?.object;
1461 try object.addAtomsToOutputSections(self);
1462 try object.addAtomsToRelaSections(self);
1463 }
1464 try self.updateSectionSizesObject();
1465
1466 try self.allocateAllocSectionsObject();
1467 try self.allocateNonAllocSections();
1468 self.allocateAtoms();
1469
1470 if (build_options.enable_logging) {
1471 state_log.debug("{}", .{self.dumpState()});
1472 }
1473
1474 try self.writeAtomsObject();
1475 try self.writeSyntheticSectionsObject();
1476 try self.writeShdrTable();
1477 try self.writeElfHeader();
1478}
1479
1480/// --verbose-link output
1481fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1482 var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
1483 defer arena_allocator.deinit();
1484 const arena = arena_allocator.allocator();
1485
1486 const target = self.base.options.target;
1487 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
1488 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
1489 const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
1490 if (fs.path.dirname(full_out_path)) |dirname| {
1491 break :blk try fs.path.join(arena, &.{ dirname, path });
1492 } else {
1493 break :blk path;
1494 }
1495 } else null;
1496 const gc_sections = self.base.options.gc_sections orelse false;
1497
1498 var csu = try CsuObjects.init(arena, self.base.options, comp);
1499 const compiler_rt_path: ?[]const u8 = blk: {
1500 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1501 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
1502 break :blk null;
1503 };
1504
1505 var argv = std.ArrayList([]const u8).init(arena);
1506
1507 try argv.append("zig");
1508
1509 if (self.isStaticLib()) {
1510 try argv.append("ar");
1511 } else {
1512 try argv.append("ld");
1513 }
1514
1515 if (self.isObject()) {
1516 try argv.append("-r");
1517 }
1518
1519 try argv.append("-o");
1520 try argv.append(full_out_path);
1521
1522 if (self.isRelocatable()) {
1523 for (self.base.options.objects) |obj| {
1524 try argv.append(obj.path);
1525 }
1526
1527 for (comp.c_object_table.keys()) |key| {
1528 try argv.append(key.status.success.object_path);
1529 }
1530
1531 if (module_obj_path) |p| {
1532 try argv.append(p);
1533 }
1534 } else {
1535 if (!self.isStatic()) {
1536 if (self.base.options.dynamic_linker) |path| {
1537 try argv.append("-dynamic-linker");
1538 try argv.append(path);
1539 }
1540 }
1541
1542 if (self.isDynLib()) {
1543 if (self.base.options.soname) |name| {
1544 try argv.append("-soname");
1545 try argv.append(name);
1546 }
1547 }
1548
1549 if (self.base.options.entry) |entry| {
1550 try argv.append("--entry");
1551 try argv.append(entry);
1552 }
1553
1554 for (self.base.options.rpath_list) |rpath| {
1555 try argv.append("-rpath");
1556 try argv.append(rpath);
1557 }
1558
1559 if (self.base.options.each_lib_rpath) {
1560 for (self.base.options.lib_dirs) |lib_dir_path| {
1561 try argv.append("-rpath");
1562 try argv.append(lib_dir_path);
1563 }
1564 for (self.base.options.objects) |obj| {
1565 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
1566 const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
1567 if (obj.loption) continue;
1568
1569 try argv.append("-rpath");
1570 try argv.append(lib_dir_path);
1571 }
1572 }
1573 }
1574
1575 if (self.base.options.stack_size_override) |ss| {
1576 try argv.append("-z");
1577 try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
1578 }
1579
1580 if (self.base.options.image_base_override) |image_base| {
1581 try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
1582 }
1583
1584 if (gc_sections) {
1585 try argv.append("--gc-sections");
1586 }
1587
1588 if (self.base.options.print_gc_sections) {
1589 try argv.append("--print-gc-sections");
1590 }
15241591
1525 // First, we flush relocatable object file generated with our backends.
1526 if (self.zigObjectPtr()) |zig_object| {
1527 zig_object.resolveSymbols(self);
1528 zig_object.claimUnresolvedObject(self);
1592 if (self.base.options.eh_frame_hdr) {
1593 try argv.append("--eh-frame-hdr");
1594 }
15291595
1530 try self.initSymtab();
1531 try self.initShStrtab();
1532 try self.sortShdrs();
1533 try zig_object.addAtomsToRelaSections(self);
1534 try self.updateSectionSizesObject();
1596 if (self.base.options.rdynamic) {
1597 try argv.append("--export-dynamic");
1598 }
15351599
1536 try self.allocateNonAllocSections();
1600 if (self.base.options.z_notext) {
1601 try argv.append("-z");
1602 try argv.append("notext");
1603 }
15371604
1538 if (build_options.enable_logging) {
1539 state_log.debug("{}", .{self.dumpState()});
1605 if (self.base.options.z_nocopyreloc) {
1606 try argv.append("-z");
1607 try argv.append("nocopyreloc");
15401608 }
15411609
1542 try self.writeSyntheticSectionsObject();
1543 try self.writeShdrTable();
1544 try self.writeElfHeader();
1545 }
1610 if (self.base.options.z_now) {
1611 try argv.append("-z");
1612 try argv.append("now");
1613 }
15461614
1547 var files = std.ArrayList(File.Index).init(gpa);
1548 defer files.deinit();
1549 try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);
1550 // Note to self: we currently must have ZigObject written out first as we write the object
1551 // file into the same file descriptor and then re-read its contents.
1552 // TODO implement writing ZigObject to a buffer instead of file.
1553 if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index);
1554 for (self.objects.items) |index| files.appendAssumeCapacity(index);
1615 if (self.isStatic()) {
1616 try argv.append("-static");
1617 } else if (self.isDynLib()) {
1618 try argv.append("-shared");
1619 }
15551620
1556 // Update ar symtab from parsed objects
1557 var ar_symtab: Archive.ArSymtab = .{};
1558 defer ar_symtab.deinit(gpa);
1621 if (self.base.options.pie and self.isExe()) {
1622 try argv.append("-pie");
1623 }
15591624
1560 for (files.items) |index| {
1561 try self.file(index).?.updateArSymtab(&ar_symtab, self);
1562 }
1625 if (self.base.options.strip) {
1626 try argv.append("-s");
1627 }
15631628
1564 ar_symtab.sort();
1629 // csu prelude
1630 if (csu.crt0) |v| try argv.append(v);
1631 if (csu.crti) |v| try argv.append(v);
1632 if (csu.crtbegin) |v| try argv.append(v);
15651633
1566 // Save object paths in filenames strtab.
1567 var ar_strtab: Archive.ArStrtab = .{};
1568 defer ar_strtab.deinit(gpa);
1634 for (self.base.options.lib_dirs) |lib_dir| {
1635 try argv.append("-L");
1636 try argv.append(lib_dir);
1637 }
15691638
1570 for (files.items) |index| {
1571 const file_ptr = self.file(index).?;
1572 try file_ptr.updateArStrtab(gpa, &ar_strtab);
1573 file_ptr.updateArSize(self);
1574 }
1639 if (self.base.options.link_libc) {
1640 if (self.base.options.libc_installation) |libc_installation| {
1641 try argv.append("-L");
1642 try argv.append(libc_installation.crt_dir.?);
1643 }
1644 }
15751645
1576 // Update file offsets of contributing objects.
1577 const total_size: usize = blk: {
1578 var pos: usize = elf.ARMAG.len;
1579 pos += @sizeOf(elf.ar_hdr) + ar_symtab.size(.p64);
1646 var whole_archive = false;
1647 for (self.base.options.objects) |obj| {
1648 if (obj.must_link and !whole_archive) {
1649 try argv.append("-whole-archive");
1650 whole_archive = true;
1651 } else if (!obj.must_link and whole_archive) {
1652 try argv.append("-no-whole-archive");
1653 whole_archive = false;
1654 }
15801655
1581 if (ar_strtab.size() > 0) {
1582 pos = mem.alignForward(usize, pos, 2);
1583 pos += @sizeOf(elf.ar_hdr) + ar_strtab.size();
1656 if (obj.loption) {
1657 assert(obj.path[0] == ':');
1658 try argv.append("-l");
1659 }
1660 try argv.append(obj.path);
15841661 }
1585
1586 for (files.items) |index| {
1587 const file_ptr = self.file(index).?;
1588 const state = switch (file_ptr) {
1589 .zig_object => |x| &x.output_ar_state,
1590 .object => |x| &x.output_ar_state,
1591 else => unreachable,
1592 };
1593 pos = mem.alignForward(usize, pos, 2);
1594 state.file_off = pos;
1595 pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
1662 if (whole_archive) {
1663 try argv.append("-no-whole-archive");
1664 whole_archive = false;
15961665 }
15971666
1598 break :blk pos;
1599 };
1667 for (comp.c_object_table.keys()) |key| {
1668 try argv.append(key.status.success.object_path);
1669 }
16001670
1601 if (build_options.enable_logging) {
1602 state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
1603 state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
1604 }
1671 if (module_obj_path) |p| {
1672 try argv.append(p);
1673 }
16051674
1606 var buffer = std.ArrayList(u8).init(gpa);
1607 defer buffer.deinit();
1608 try buffer.ensureTotalCapacityPrecise(total_size);
1675 // TSAN
1676 if (self.base.options.tsan) {
1677 try argv.append(comp.tsan_static_lib.?.full_object_path);
1678 }
16091679
1610 // Write magic
1611 try buffer.writer().writeAll(elf.ARMAG);
1680 // libc
1681 if (!self.base.options.skip_linker_dependencies and
1682 !self.base.options.link_libc)
1683 {
1684 if (comp.libc_static_lib) |lib| {
1685 try argv.append(lib.full_object_path);
1686 }
1687 }
16121688
1613 // Write symtab
1614 try ar_symtab.write(.p64, self, buffer.writer());
1689 // stack-protector.
1690 // Related: https://github.com/ziglang/zig/issues/7265
1691 if (comp.libssp_static_lib) |ssp| {
1692 try argv.append(ssp.full_object_path);
1693 }
16151694
1616 // Write strtab
1617 if (ar_strtab.size() > 0) {
1618 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1619 try ar_strtab.write(buffer.writer());
1620 }
1695 // Shared libraries.
1696 // Worst-case, we need an --as-needed argument for every lib, as well
1697 // as one before and one after.
1698 try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
1699 argv.appendAssumeCapacity("--as-needed");
1700 var as_needed = true;
16211701
1622 // Write object files
1623 for (files.items) |index| {
1624 if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
1625 try self.file(index).?.writeAr(self, buffer.writer());
1626 }
1702 for (self.base.options.system_libs.values()) |lib_info| {
1703 const lib_as_needed = !lib_info.needed;
1704 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
1705 0b00, 0b11 => {},
1706 0b01 => {
1707 argv.appendAssumeCapacity("--no-as-needed");
1708 as_needed = false;
1709 },
1710 0b10 => {
1711 argv.appendAssumeCapacity("--as-needed");
1712 as_needed = true;
1713 },
1714 }
1715 argv.appendAssumeCapacity(lib_info.path.?);
1716 }
16271717
1628 assert(buffer.items.len == total_size);
1718 if (!as_needed) {
1719 argv.appendAssumeCapacity("--as-needed");
1720 as_needed = true;
1721 }
16291722
1630 try self.base.file.?.setEndPos(total_size);
1631 try self.base.file.?.pwriteAll(buffer.items, 0);
1632}
1723 // libc++ dep
1724 if (self.base.options.link_libcpp) {
1725 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
1726 try argv.append(comp.libcxx_static_lib.?.full_object_path);
1727 }
16331728
1634pub fn flushObject(self: *Elf) link.File.FlushError!void {
1635 self.claimUnresolvedObject();
1729 // libunwind dep
1730 if (self.base.options.link_libunwind) {
1731 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1732 }
16361733
1637 try self.initSectionsObject();
1638 try self.sortShdrs();
1639 if (self.zigObjectPtr()) |zig_object| {
1640 try zig_object.addAtomsToRelaSections(self);
1641 }
1642 for (self.objects.items) |index| {
1643 const object = self.file(index).?.object;
1644 try object.addAtomsToOutputSections(self);
1645 try object.addAtomsToRelaSections(self);
1646 }
1647 try self.updateSectionSizesObject();
1734 // libc dep
1735 if (self.base.options.link_libc) {
1736 if (self.base.options.libc_installation != null) {
1737 const needs_grouping = self.base.options.link_mode == .Static;
1738 if (needs_grouping) try argv.append("--start-group");
1739 try argv.appendSlice(target_util.libcFullLinkFlags(target));
1740 if (needs_grouping) try argv.append("--end-group");
1741 } else if (target.isGnuLibC()) {
1742 for (glibc.libs) |lib| {
1743 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
1744 comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
1745 });
1746 try argv.append(lib_path);
1747 }
1748 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
1749 } else if (target.isMusl()) {
1750 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
1751 .Static => "libc.a",
1752 .Dynamic => "libc.so",
1753 }));
1754 }
1755 }
16481756
1649 try self.allocateAllocSectionsObject();
1650 try self.allocateNonAllocSections();
1651 self.allocateAtoms();
1757 // compiler-rt
1758 if (compiler_rt_path) |p| {
1759 try argv.append(p);
1760 }
16521761
1653 if (build_options.enable_logging) {
1654 state_log.debug("{}", .{self.dumpState()});
1762 // crt postlude
1763 if (csu.crtend) |v| try argv.append(v);
1764 if (csu.crtn) |v| try argv.append(v);
16551765 }
16561766
1657 try self.writeAtomsObject();
1658 try self.writeSyntheticSectionsObject();
1659 try self.writeShdrTable();
1660 try self.writeElfHeader();
1767 Compilation.dump_argv(argv.items);
16611768}
16621769
16631770const ParseError = error{
......@@ -3651,8 +3758,10 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
36513758 try self.dynamic.addNeeded(shared_object, self);
36523759 }
36533760
3654 if (self.base.options.soname) |soname| {
3655 try self.dynamic.setSoname(soname, self);
3761 if (self.isDynLib()) {
3762 if (self.base.options.soname) |soname| {
3763 try self.dynamic.setSoname(soname, self);
3764 }
36563765 }
36573766
36583767 try self.dynamic.setRpath(rpaths, self);