Commit 17f094ec5b

Andrew Kelley <andrew@ziglang.org>
2020-09-16 23:33:13
stage2: build glibc shared objects using assembly files
closes #6358
1 parent 3256b3c
Changed files (2)
src-self-hosted
src-self-hosted/glibc.zig
@@ -744,6 +744,9 @@ pub const BuiltSharedObjects = struct {
 
 const all_map_basename = "all.map";
 
+// TODO Turn back on zig fmt when https://github.com/ziglang/zig/issues/5948 is implemented.
+// zig fmt: off
+
 pub fn buildSharedObjects(comp: *Compilation) !void {
     const tracy = trace(@src());
     defer tracy.end();
@@ -765,8 +768,6 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
     cache.hash.addBytes(build_options.version);
     cache.hash.addBytes(comp.zig_lib_directory.path orelse ".");
     cache.hash.add(target.cpu.arch);
-    cache.hash.addBytes(target.cpu.model.name);
-    cache.hash.add(target.cpu.features.ints);
     cache.hash.add(target.abi);
     cache.hash.add(target_version);
 
@@ -832,17 +833,9 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
         }
         var zig_body = std.ArrayList(u8).init(comp.gpa);
         defer zig_body.deinit();
-        var zig_footer = std.ArrayList(u8).init(comp.gpa);
-        defer zig_footer.deinit();
         for (libs) |*lib| {
             zig_body.shrinkRetainingCapacity(0);
-            zig_footer.shrinkRetainingCapacity(0);
 
-            try zig_body.appendSlice(
-                \\comptime {
-                \\    asm (
-                \\
-            );
             for (metadata.all_functions) |*libc_fn, fn_i| {
                 if (libc_fn.lib != lib) continue;
 
@@ -868,46 +861,66 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
                 {
                     var ver_i: u8 = 0;
                     while (ver_i < ver_list.len) : (ver_i += 1) {
+                        // Example:
+                        // .globl _Exit_2_2_5
+                        // .type _Exit_2_2_5, @function;
+                        // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5
+                        // .hidden _Exit_2_2_5
+                        // _Exit_2_2_5:
                         const ver_index = ver_list.versions[ver_i];
                         const ver = metadata.all_versions[ver_index];
                         const sym_name = libc_fn.name;
-                        const stub_name = if (ver.patch == 0)
-                            try std.fmt.allocPrint(arena, "{s}_{d}_{d}", .{ sym_name, ver.major, ver.minor })
-                        else
-                            try std.fmt.allocPrint(arena, "{s}_{d}_{d}_{d}", .{ sym_name, ver.major, ver.minor, ver.patch });
-
-                        try zig_footer.writer().print("export fn {s}() void {{}}\n", .{stub_name});
-
                         // Default symbol version definition vs normal symbol version definition
                         const want_two_ats = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
                         const at_sign_str = "@@"[0 .. @boolToInt(want_two_ats) + @as(usize, 1)];
+
                         if (ver.patch == 0) {
-                            try zig_body.writer().print("        \\\\.symver {s}, {s}{s}GLIBC_{d}.{d}\n", .{
-                                stub_name, sym_name, at_sign_str, ver.major, ver.minor,
+                            const sym_plus_ver = try std.fmt.allocPrint(
+                                arena, "{s}_{d}_{d}",
+                                .{sym_name, ver.major, ver.minor},
+                            );
+                            try zig_body.writer().print(
+                                \\.globl {s}
+                                \\.type {s}, @function;
+                                \\.symver {s}, {s}{s}GLIBC_{d}.{d}
+                                \\.hidden {s}
+                                \\{s}:
+                                \\
+                            , .{
+                                sym_plus_ver,
+                                sym_plus_ver,
+                                sym_plus_ver, sym_name, at_sign_str, ver.major, ver.minor,
+                                sym_plus_ver,
+                                sym_plus_ver,
                             });
                         } else {
-                            try zig_body.writer().print("        \\\\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}\n", .{
-                                stub_name, sym_name, at_sign_str, ver.major, ver.minor, ver.patch,
+                            const sym_plus_ver = try std.fmt.allocPrint(arena, "{s}_{d}_{d}_{d}",
+                                .{sym_name, ver.major, ver.minor, ver.patch},
+                            );
+                            try zig_body.writer().print(
+                                \\.globl {s}
+                                \\.type {s}, @function;
+                                \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
+                                \\.hidden {s}
+                                \\{s}:
+                                \\
+                            , .{
+                                sym_plus_ver,
+                                sym_plus_ver,
+                                sym_plus_ver, sym_name, at_sign_str, ver.major, ver.minor, ver.patch,
+                                sym_plus_ver,
+                                sym_plus_ver,
                             });
                         }
-                        // Hide the stub to keep the symbol table clean
-                        try zig_body.writer().print("        \\\\.hidden {s}\n", .{stub_name});
                     }
                 }
             }
 
-            try zig_body.appendSlice(
-                \\    );
-                \\}
-                \\
-            );
-            try zig_body.appendSlice(zig_footer.items);
-
             var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
-            const zig_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.zig", .{lib.name}) catch unreachable;
-            try o_directory.handle.writeFile(zig_file_basename, zig_body.items);
+            const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
+            try o_directory.handle.writeFile(asm_file_basename, zig_body.items);
 
-            try buildSharedLib(comp, arena, comp.zig_cache_directory, o_directory, zig_file_basename, lib);
+            try buildSharedLib(comp, arena, comp.zig_cache_directory, o_directory, asm_file_basename, lib);
         }
         // No need to write the manifest because there are no file inputs associated with this cache hash.
         // However we do need to write the ok file now.
@@ -925,12 +938,14 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
     };
 }
 
+// zig fmt: on
+
 fn buildSharedLib(
     comp: *Compilation,
     arena: *Allocator,
     zig_cache_directory: Compilation.Directory,
     bin_directory: Compilation.Directory,
-    zig_file_basename: []const u8,
+    asm_file_basename: []const u8,
     lib: *const Lib,
 ) !void {
     const tracy = trace(@src());
@@ -944,15 +959,17 @@ fn buildSharedLib(
     const ld_basename = path.basename(comp.getTarget().standardDynamicLinkerPath().get().?);
     const override_soname = if (mem.eql(u8, lib.name, "ld")) ld_basename else null;
     const map_file_path = try path.join(arena, &[_][]const u8{ bin_directory.path.?, all_map_basename });
-    // TODO we should be able to just give the open directory to Package
-    const root_pkg = try Package.create(comp.gpa, std.fs.cwd(), bin_directory.path.?, zig_file_basename);
-    defer root_pkg.destroy(comp.gpa);
+    const c_source_files = [1]Compilation.CSourceFile{
+        .{
+            .src_path = try path.join(arena, &[_][]const u8{ bin_directory.path.?, asm_file_basename }),
+        },
+    };
     const sub_compilation = try Compilation.create(comp.gpa, .{
         .zig_cache_directory = zig_cache_directory,
         .zig_lib_directory = comp.zig_lib_directory,
         .target = comp.getTarget(),
         .root_name = lib.name,
-        .root_pkg = root_pkg,
+        .root_pkg = null,
         .output_mode = .Lib,
         .link_mode = .Dynamic,
         .rand = comp.rand,
@@ -973,6 +990,7 @@ fn buildSharedLib(
         .stage1_is_dummy_so = true,
         .version_script = map_file_path,
         .override_soname = override_soname,
+        .c_source_files = &c_source_files,
     });
     defer sub_compilation.destroy();
 
BRANCH_TODO
@@ -1,8 +1,5 @@
- * glibc .so files
-   - without stage1 c++ code integration it should fail with a better error message
-     instead of lld not getting the object file on the linker line for some reason.
-   - stage1 C++ code integration
-   - ok file
+ * libunwind
+ * stage1 C++ code integration
  * support rpaths in ELF linker code
  * build & link against compiler-rt
  * build & link againstn freestanding libc