authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-28 19:40:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-10-29 12:15:47-07:00
log4cfeb9a541b3e6db2c67a494abf4f6bd12900353
treeff71b6cffa2d9b41549fcf97d69381cc5775391f
parent20925b2f5c5c0ae20fdc0574e5d4e5740d17b4d6

glibc: fix race condition when building stubs

Before, the code for building glibc stubs used a special case of the Cache API that did not add any file inputs, and did not use writeManifest(). This is not really how the Cache API is designed to work and it shows because there was a race condition. This commit adds as an input file the abilists file that comes with Zig's installation, which has the added benefit of making glibc stub caching properly detect cache invalidation when the user decides to overwrite their abilists file. This harmonizes with the rest of how Zig works, which intentionally allows you to hack the installation files and have it behave properly with the cache system. Finally, because of having any file inputs, the normal API flow of the Cache system can be used, eliminating the one place that used the Cache API in a special way. In other words, it uses writeManifest() now and properly obeys the cache hit/miss semantics. closes #13160

2 files changed, 343 insertions(+), 349 deletions(-)

src/glibc.zig+332-348
...@@ -50,9 +50,12 @@ pub const LoadMetaDataError = error{...@@ -50,9 +50,12 @@ pub const LoadMetaDataError = error{
50 OutOfMemory,50 OutOfMemory,
51};51};
5252
53pub const abilists_path = "libc" ++ path.sep_str ++ "glibc" ++ path.sep_str ++ "abilists";
54pub const abilists_max_size = 800 * 1024; // Bigger than this and something is definitely borked.
55
53/// This function will emit a log error when there is a problem with the zig56/// This function will emit a log error when there is a problem with the zig
54/// installation and then return `error.ZigInstallationCorrupt`.57/// installation and then return `error.ZigInstallationCorrupt`.
55pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI {58pub fn loadMetaData(gpa: Allocator, contents: []const u8) LoadMetaDataError!*ABI {
56 const tracy = trace(@src());59 const tracy = trace(@src());
57 defer tracy.end();60 defer tracy.end();
5861
...@@ -60,22 +63,6 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI...@@ -60,22 +63,6 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
60 errdefer arena_allocator.deinit();63 errdefer arena_allocator.deinit();
61 const arena = arena_allocator.allocator();64 const arena = arena_allocator.allocator();
6265
63 var glibc_dir = zig_lib_dir.openDir("libc" ++ path.sep_str ++ "glibc", .{}) catch |err| {
64 log.err("unable to open glibc dir: {s}", .{@errorName(err)});
65 return error.ZigInstallationCorrupt;
66 };
67 defer glibc_dir.close();
68
69 const max_size = 500 * 1024; // Bigger than this and something is definitely borked.
70 const contents = glibc_dir.readFileAlloc(arena, "abilists", max_size) catch |err| switch (err) {
71 error.OutOfMemory => return error.OutOfMemory,
72 else => {
73 log.err("unable to read libc" ++ path.sep_str ++ "glibc" ++ path.sep_str ++
74 "abilists: {s}", .{@errorName(err)});
75 return error.ZigInstallationCorrupt;
76 },
77 };
78
79 var index: usize = 0;66 var index: usize = 0;
8067
81 {68 {
...@@ -662,386 +649,383 @@ pub fn buildSharedObjects(comp: *Compilation) !void {...@@ -662,386 +649,383 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
662 const target_version = target.os.version_range.linux.glibc;649 const target_version = target.os.version_range.linux.glibc;
663650
664 // Use the global cache directory.651 // Use the global cache directory.
665 var cache_parent: Cache = .{652 var cache: Cache = .{
666 .gpa = comp.gpa,653 .gpa = comp.gpa,
667 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),654 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
668 };655 };
669 defer cache_parent.manifest_dir.close();656 defer cache.manifest_dir.close();
670657
671 var cache = cache_parent.obtain();658 var man = cache.obtain();
672 defer cache.deinit();659 defer man.deinit();
673 cache.hash.addBytes(build_options.version);660 man.hash.addBytes(build_options.version);
674 cache.hash.addBytes(comp.zig_lib_directory.path orelse ".");661 man.hash.addBytes(comp.zig_lib_directory.path orelse ".");
675 cache.hash.add(target.cpu.arch);662 man.hash.add(target.cpu.arch);
676 cache.hash.add(target.abi);663 man.hash.add(target.abi);
677 cache.hash.add(target_version);664 man.hash.add(target_version);
678665
679 const hit = try cache.hit();666 const full_abilists_path = try comp.zig_lib_directory.join(arena, &.{abilists_path});
680 const digest = cache.final();667 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
681 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });668
669 if (try man.hit()) {
670 const digest = man.final();
671
672 assert(comp.glibc_so_files == null);
673 comp.glibc_so_files = BuiltSharedObjects{
674 .lock = man.toOwnedLock(),
675 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
676 };
677 return;
678 }
682679
683 // Even if we get a hit, it doesn't guarantee that we finished the job last time.680 const digest = man.final();
684 // We use the presence of an "ok" file to determine if it is a true hit.681 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
685682
686 var o_directory: Compilation.Directory = .{683 var o_directory: Compilation.Directory = .{
687 .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}),684 .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}),
688 .path = try path.join(arena, &[_][]const u8{ comp.global_cache_directory.path.?, o_sub_path }),685 .path = try comp.global_cache_directory.join(arena, &.{o_sub_path}),
689 };686 };
690 defer o_directory.handle.close();687 defer o_directory.handle.close();
691688
692 const ok_basename = "ok";689 const abilists_contents = man.files.items[abilists_index].contents.?;
693 const actual_hit = if (hit) blk: {690 const metadata = try loadMetaData(comp.gpa, abilists_contents);
694 o_directory.handle.access(ok_basename, .{}) catch |err| switch (err) {691 defer metadata.destroy(comp.gpa);
695 error.FileNotFound => break :blk false,
696 else => |e| return e,
697 };
698 break :blk true;
699 } else false;
700
701 if (!actual_hit) {
702 const metadata = try loadMetaData(comp.gpa, comp.zig_lib_directory.handle);
703 defer metadata.destroy(comp.gpa);
704692
705 const target_targ_index = for (metadata.all_targets) |targ, i| {693 const target_targ_index = for (metadata.all_targets) |targ, i| {
706 if (targ.arch == target.cpu.arch and694 if (targ.arch == target.cpu.arch and
707 targ.os == target.os.tag and695 targ.os == target.os.tag and
708 targ.abi == target.abi)696 targ.abi == target.abi)
709 {697 {
710 break i;698 break i;
711 }699 }
712 } else {700 } else {
713 unreachable; // target_util.available_libcs prevents us from getting here701 unreachable; // target_util.available_libcs prevents us from getting here
714 };702 };
715703
716 const target_ver_index = for (metadata.all_versions) |ver, i| {704 const target_ver_index = for (metadata.all_versions) |ver, i| {
717 switch (ver.order(target_version)) {705 switch (ver.order(target_version)) {
718 .eq => break i,706 .eq => break i,
719 .lt => continue,707 .lt => continue,
720 .gt => {708 .gt => {
721 // TODO Expose via compile error mechanism instead of log.709 // TODO Expose via compile error mechanism instead of log.
722 log.warn("invalid target glibc version: {}", .{target_version});710 log.warn("invalid target glibc version: {}", .{target_version});
723 return error.InvalidTargetGLibCVersion;711 return error.InvalidTargetGLibCVersion;
724 },712 },
725 }713 }
726 } else blk: {714 } else blk: {
727 const latest_index = metadata.all_versions.len - 1;715 const latest_index = metadata.all_versions.len - 1;
728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{716 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
729 target_version, metadata.all_versions[latest_index],717 target_version, metadata.all_versions[latest_index],
730 });718 });
731 break :blk latest_index;719 break :blk latest_index;
732 };720 };
733721
734 {722 {
735 var map_contents = std.ArrayList(u8).init(arena);723 var map_contents = std.ArrayList(u8).init(arena);
736 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {724 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
737 if (ver.patch == 0) {725 if (ver.patch == 0) {
738 try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });726 try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
739 } else {727 } else {
740 try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });728 try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });
741 }
742 }729 }
743 try o_directory.handle.writeFile(all_map_basename, map_contents.items);
744 map_contents.deinit(); // The most recent allocation of an arena can be freed :)
745 }730 }
731 try o_directory.handle.writeFile(all_map_basename, map_contents.items);
732 map_contents.deinit(); // The most recent allocation of an arena can be freed :)
733 }
746734
747 var stubs_asm = std.ArrayList(u8).init(comp.gpa);735 var stubs_asm = std.ArrayList(u8).init(comp.gpa);
748 defer stubs_asm.deinit();736 defer stubs_asm.deinit();
749737
750 for (libs) |lib, lib_i| {738 for (libs) |lib, lib_i| {
751 stubs_asm.shrinkRetainingCapacity(0);739 stubs_asm.shrinkRetainingCapacity(0);
752 try stubs_asm.appendSlice(".text\n");740 try stubs_asm.appendSlice(".text\n");
753741
754 var inc_i: usize = 0;742 var inc_i: usize = 0;
755743
756 const fn_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);744 const fn_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);
757 inc_i += 2;745 inc_i += 2;
758746
759 var sym_i: usize = 0;747 var sym_i: usize = 0;
760 var opt_symbol_name: ?[]const u8 = null;748 var opt_symbol_name: ?[]const u8 = null;
761 var versions_buffer: [32]u8 = undefined;749 var versions_buffer: [32]u8 = undefined;
762 var versions_len: usize = undefined;750 var versions_len: usize = undefined;
763 while (sym_i < fn_inclusions_len) : (sym_i += 1) {751 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
764 const sym_name = opt_symbol_name orelse n: {752 const sym_name = opt_symbol_name orelse n: {
765 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);753 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);
766 inc_i += name.len + 1;754 inc_i += name.len + 1;
767755
768 opt_symbol_name = name;756 opt_symbol_name = name;
769 versions_buffer = undefined;757 versions_buffer = undefined;
770 versions_len = 0;758 versions_len = 0;
771 break :n name;759 break :n name;
772 };760 };
773 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..4]);761 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..4]);
774 inc_i += 4;762 inc_i += 4;
775763
776 const lib_index = metadata.inclusions[inc_i];764 const lib_index = metadata.inclusions[inc_i];
765 inc_i += 1;
766 const is_terminal = (targets & (1 << 31)) != 0;
767 if (is_terminal) opt_symbol_name = null;
768
769 // Test whether the inclusion applies to our current library and target.
770 const ok_lib_and_target =
771 (lib_index == lib_i) and
772 ((targets & (@as(u32, 1) << @intCast(u5, target_targ_index))) != 0);
773
774 while (true) {
775 const byte = metadata.inclusions[inc_i];
777 inc_i += 1;776 inc_i += 1;
778 const is_terminal = (targets & (1 << 31)) != 0;777 const last = (byte & 0b1000_0000) != 0;
779 if (is_terminal) opt_symbol_name = null;778 const ver_i = @truncate(u7, byte);
780779 if (ok_lib_and_target and ver_i <= target_ver_index) {
781 // Test whether the inclusion applies to our current library and target.780 versions_buffer[versions_len] = ver_i;
782 const ok_lib_and_target =781 versions_len += 1;
783 (lib_index == lib_i) and
784 ((targets & (@as(u32, 1) << @intCast(u5, target_targ_index))) != 0);
785
786 while (true) {
787 const byte = metadata.inclusions[inc_i];
788 inc_i += 1;
789 const last = (byte & 0b1000_0000) != 0;
790 const ver_i = @truncate(u7, byte);
791 if (ok_lib_and_target and ver_i <= target_ver_index) {
792 versions_buffer[versions_len] = ver_i;
793 versions_len += 1;
794 }
795 if (last) break;
796 }782 }
783 if (last) break;
784 }
797785
798 if (!is_terminal) continue;786 if (!is_terminal) continue;
799787
800 // Pick the default symbol version:788 // Pick the default symbol version:
801 // - If there are no versions, don't emit it789 // - If there are no versions, don't emit it
802 // - Take the greatest one <= than the target one790 // - Take the greatest one <= than the target one
803 // - If none of them is <= than the791 // - If none of them is <= than the
804 // specified one don't pick any default version792 // specified one don't pick any default version
805 if (versions_len == 0) continue;793 if (versions_len == 0) continue;
806 var chosen_def_ver_index: u8 = 255;794 var chosen_def_ver_index: u8 = 255;
807 {795 {
808 var ver_buf_i: u8 = 0;796 var ver_buf_i: u8 = 0;
809 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {797 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
810 const ver_index = versions_buffer[ver_buf_i];798 const ver_index = versions_buffer[ver_buf_i];
811 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {799 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
812 chosen_def_ver_index = ver_index;800 chosen_def_ver_index = ver_index;
813 }
814 }801 }
815 }802 }
816 {803 }
817 var ver_buf_i: u8 = 0;804 {
818 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {805 var ver_buf_i: u8 = 0;
819 // Example:806 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
820 // .globl _Exit_2_2_5807 // Example:
821 // .type _Exit_2_2_5, %function;808 // .globl _Exit_2_2_5
822 // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5809 // .type _Exit_2_2_5, %function;
823 // _Exit_2_2_5:810 // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5
824 const ver_index = versions_buffer[ver_buf_i];811 // _Exit_2_2_5:
825 const ver = metadata.all_versions[ver_index];812 const ver_index = versions_buffer[ver_buf_i];
826 // Default symbol version definition vs normal symbol version definition813 const ver = metadata.all_versions[ver_index];
827 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;814 // Default symbol version definition vs normal symbol version definition
828 const at_sign_str: []const u8 = if (want_default) "@@" else "@";815 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
829 if (ver.patch == 0) {816 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
830 const sym_plus_ver = if (want_default)817 if (ver.patch == 0) {
831 sym_name818 const sym_plus_ver = if (want_default)
832 else819 sym_name
833 try std.fmt.allocPrint(820 else
834 arena,821 try std.fmt.allocPrint(
835 "{s}_GLIBC_{d}_{d}",822 arena,
836 .{ sym_name, ver.major, ver.minor },823 "{s}_GLIBC_{d}_{d}",
837 );824 .{ sym_name, ver.major, ver.minor },
838 try stubs_asm.writer().print(825 );
839 \\.globl {s}826 try stubs_asm.writer().print(
840 \\.type {s}, %function;827 \\.globl {s}
841 \\.symver {s}, {s}{s}GLIBC_{d}.{d}828 \\.type {s}, %function;
842 \\{s}:829 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
843 \\830 \\{s}:
844 , .{831 \\
845 sym_plus_ver,832 , .{
846 sym_plus_ver,833 sym_plus_ver,
847 sym_plus_ver,834 sym_plus_ver,
848 sym_name,835 sym_plus_ver,
849 at_sign_str,836 sym_name,
850 ver.major,837 at_sign_str,
851 ver.minor,838 ver.major,
852 sym_plus_ver,839 ver.minor,
853 });840 sym_plus_ver,
854 } else {841 });
855 const sym_plus_ver = if (want_default)842 } else {
856 sym_name843 const sym_plus_ver = if (want_default)
857 else844 sym_name
858 try std.fmt.allocPrint(845 else
859 arena,846 try std.fmt.allocPrint(
860 "{s}_GLIBC_{d}_{d}_{d}",847 arena,
861 .{ sym_name, ver.major, ver.minor, ver.patch },848 "{s}_GLIBC_{d}_{d}_{d}",
862 );849 .{ sym_name, ver.major, ver.minor, ver.patch },
863 try stubs_asm.writer().print(850 );
864 \\.globl {s}851 try stubs_asm.writer().print(
865 \\.type {s}, %function;852 \\.globl {s}
866 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}853 \\.type {s}, %function;
867 \\{s}:854 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
868 \\855 \\{s}:
869 , .{856 \\
870 sym_plus_ver,857 , .{
871 sym_plus_ver,858 sym_plus_ver,
872 sym_plus_ver,859 sym_plus_ver,
873 sym_name,860 sym_plus_ver,
874 at_sign_str,861 sym_name,
875 ver.major,862 at_sign_str,
876 ver.minor,863 ver.major,
877 ver.patch,864 ver.minor,
878 sym_plus_ver,865 ver.patch,
879 });866 sym_plus_ver,
880 }867 });
881 }868 }
882 }869 }
883 }870 }
871 }
872
873 try stubs_asm.appendSlice(".data\n");
874
875 const obj_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);
876 inc_i += 2;
884877
885 try stubs_asm.appendSlice(".data\n");878 sym_i = 0;
879 opt_symbol_name = null;
880 versions_buffer = undefined;
881 versions_len = undefined;
882 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
883 const sym_name = opt_symbol_name orelse n: {
884 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);
885 inc_i += name.len + 1;
886886
887 const obj_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);887 opt_symbol_name = name;
888 versions_buffer = undefined;
889 versions_len = 0;
890 break :n name;
891 };
892 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..4]);
893 inc_i += 4;
894
895 const size = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);
888 inc_i += 2;896 inc_i += 2;
889897
890 sym_i = 0;898 const lib_index = metadata.inclusions[inc_i];
891 opt_symbol_name = null;899 inc_i += 1;
892 versions_buffer = undefined;900 const is_terminal = (targets & (1 << 31)) != 0;
893 versions_len = undefined;901 if (is_terminal) opt_symbol_name = null;
894 while (sym_i < obj_inclusions_len) : (sym_i += 1) {
895 const sym_name = opt_symbol_name orelse n: {
896 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);
897 inc_i += name.len + 1;
898
899 opt_symbol_name = name;
900 versions_buffer = undefined;
901 versions_len = 0;
902 break :n name;
903 };
904 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..4]);
905 inc_i += 4;
906902
907 const size = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);903 // Test whether the inclusion applies to our current library and target.
908 inc_i += 2;904 const ok_lib_and_target =
905 (lib_index == lib_i) and
906 ((targets & (@as(u32, 1) << @intCast(u5, target_targ_index))) != 0);
909907
910 const lib_index = metadata.inclusions[inc_i];908 while (true) {
909 const byte = metadata.inclusions[inc_i];
911 inc_i += 1;910 inc_i += 1;
912 const is_terminal = (targets & (1 << 31)) != 0;911 const last = (byte & 0b1000_0000) != 0;
913 if (is_terminal) opt_symbol_name = null;912 const ver_i = @truncate(u7, byte);
914913 if (ok_lib_and_target and ver_i <= target_ver_index) {
915 // Test whether the inclusion applies to our current library and target.914 versions_buffer[versions_len] = ver_i;
916 const ok_lib_and_target =915 versions_len += 1;
917 (lib_index == lib_i) and
918 ((targets & (@as(u32, 1) << @intCast(u5, target_targ_index))) != 0);
919
920 while (true) {
921 const byte = metadata.inclusions[inc_i];
922 inc_i += 1;
923 const last = (byte & 0b1000_0000) != 0;
924 const ver_i = @truncate(u7, byte);
925 if (ok_lib_and_target and ver_i <= target_ver_index) {
926 versions_buffer[versions_len] = ver_i;
927 versions_len += 1;
928 }
929 if (last) break;
930 }916 }
917 if (last) break;
918 }
919
920 if (!is_terminal) continue;
931921
932 if (!is_terminal) continue;922 // Pick the default symbol version:
933923 // - If there are no versions, don't emit it
934 // Pick the default symbol version:924 // - Take the greatest one <= than the target one
935 // - If there are no versions, don't emit it925 // - If none of them is <= than the
936 // - Take the greatest one <= than the target one926 // specified one don't pick any default version
937 // - If none of them is <= than the927 if (versions_len == 0) continue;
938 // specified one don't pick any default version928 var chosen_def_ver_index: u8 = 255;
939 if (versions_len == 0) continue;929 {
940 var chosen_def_ver_index: u8 = 255;930 var ver_buf_i: u8 = 0;
941 {931 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
942 var ver_buf_i: u8 = 0;932 const ver_index = versions_buffer[ver_buf_i];
943 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {933 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
944 const ver_index = versions_buffer[ver_buf_i];934 chosen_def_ver_index = ver_index;
945 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
946 chosen_def_ver_index = ver_index;
947 }
948 }935 }
949 }936 }
950 {937 }
951 var ver_buf_i: u8 = 0;938 {
952 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {939 var ver_buf_i: u8 = 0;
953 // Example:940 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
954 // .globl environ_2_2_5941 // Example:
955 // .type environ_2_2_5, %object;942 // .globl environ_2_2_5
956 // .size environ_2_2_5, 4;943 // .type environ_2_2_5, %object;
957 // .symver environ_2_2_5, environ@@GLIBC_2.2.5944 // .size environ_2_2_5, 4;
958 // environ_2_2_5:945 // .symver environ_2_2_5, environ@@GLIBC_2.2.5
959 const ver_index = versions_buffer[ver_buf_i];946 // environ_2_2_5:
960 const ver = metadata.all_versions[ver_index];947 const ver_index = versions_buffer[ver_buf_i];
961 // Default symbol version definition vs normal symbol version definition948 const ver = metadata.all_versions[ver_index];
962 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;949 // Default symbol version definition vs normal symbol version definition
963 const at_sign_str: []const u8 = if (want_default) "@@" else "@";950 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
964 if (ver.patch == 0) {951 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
965 const sym_plus_ver = if (want_default)952 if (ver.patch == 0) {
966 sym_name953 const sym_plus_ver = if (want_default)
967 else954 sym_name
968 try std.fmt.allocPrint(955 else
969 arena,956 try std.fmt.allocPrint(
970 "{s}_GLIBC_{d}_{d}",957 arena,
971 .{ sym_name, ver.major, ver.minor },958 "{s}_GLIBC_{d}_{d}",
972 );959 .{ sym_name, ver.major, ver.minor },
973 try stubs_asm.writer().print(960 );
974 \\.globl {s}961 try stubs_asm.writer().print(
975 \\.type {s}, %object;962 \\.globl {s}
976 \\.size {s}, {d};963 \\.type {s}, %object;
977 \\.symver {s}, {s}{s}GLIBC_{d}.{d}964 \\.size {s}, {d};
978 \\{s}:965 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
979 \\966 \\{s}:
980 , .{967 \\
981 sym_plus_ver,968 , .{
982 sym_plus_ver,969 sym_plus_ver,
983 sym_plus_ver,970 sym_plus_ver,
984 size,971 sym_plus_ver,
985 sym_plus_ver,972 size,
986 sym_name,973 sym_plus_ver,
987 at_sign_str,974 sym_name,
988 ver.major,975 at_sign_str,
989 ver.minor,976 ver.major,
990 sym_plus_ver,977 ver.minor,
991 });978 sym_plus_ver,
992 } else {979 });
993 const sym_plus_ver = if (want_default)980 } else {
994 sym_name981 const sym_plus_ver = if (want_default)
995 else982 sym_name
996 try std.fmt.allocPrint(983 else
997 arena,984 try std.fmt.allocPrint(
998 "{s}_GLIBC_{d}_{d}_{d}",985 arena,
999 .{ sym_name, ver.major, ver.minor, ver.patch },986 "{s}_GLIBC_{d}_{d}_{d}",
1000 );987 .{ sym_name, ver.major, ver.minor, ver.patch },
1001 try stubs_asm.writer().print(988 );
1002 \\.globl {s}989 try stubs_asm.writer().print(
1003 \\.type {s}, %object;990 \\.globl {s}
1004 \\.size {s}, {d};991 \\.type {s}, %object;
1005 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}992 \\.size {s}, {d};
1006 \\{s}:993 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
1007 \\994 \\{s}:
1008 , .{995 \\
1009 sym_plus_ver,996 , .{
1010 sym_plus_ver,997 sym_plus_ver,
1011 sym_plus_ver,998 sym_plus_ver,
1012 size,999 sym_plus_ver,
1013 sym_plus_ver,1000 size,
1014 sym_name,1001 sym_plus_ver,
1015 at_sign_str,1002 sym_name,
1016 ver.major,1003 at_sign_str,
1017 ver.minor,1004 ver.major,
1018 ver.patch,1005 ver.minor,
1019 sym_plus_ver,1006 ver.patch,
1020 });1007 sym_plus_ver,
1021 }1008 });
1022 }1009 }
1023 }1010 }
1024 }1011 }
1012 }
10251013
1026 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.1014 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
1027 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;1015 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
1028 try o_directory.handle.writeFile(asm_file_basename, stubs_asm.items);1016 try o_directory.handle.writeFile(asm_file_basename, stubs_asm.items);
10291017
1030 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib);1018 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib);
1031 }
1032 // No need to write the manifest because there are no file inputs associated with this cache hash.
1033 // However we do need to write the ok file now.
1034 if (o_directory.handle.createFile(ok_basename, .{})) |file| {
1035 file.close();
1036 } else |err| {
1037 log.warn("glibc shared objects: failed to mark completion: {s}", .{@errorName(err)});
1038 }
1039 }1019 }
10401020
1021 man.writeManifest() catch |err| {
1022 log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});
1023 };
1024
1041 assert(comp.glibc_so_files == null);1025 assert(comp.glibc_so_files == null);
1042 comp.glibc_so_files = BuiltSharedObjects{1026 comp.glibc_so_files = BuiltSharedObjects{
1043 .lock = cache.toOwnedLock(),1027 .lock = man.toOwnedLock(),
1044 .dir_path = try path.join(comp.gpa, &[_][]const u8{ comp.global_cache_directory.path.?, o_sub_path }),1028 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
1045 };1029 };
1046}1030}
10471031
src/print_targets.zig+11-1
...@@ -25,7 +25,17 @@ pub fn cmdTargets(...@@ -25,7 +25,17 @@ pub fn cmdTargets(
25 defer zig_lib_directory.handle.close();25 defer zig_lib_directory.handle.close();
26 defer allocator.free(zig_lib_directory.path.?);26 defer allocator.free(zig_lib_directory.path.?);
2727
28 const glibc_abi = try glibc.loadMetaData(allocator, zig_lib_directory.handle);28 const abilists_contents = zig_lib_directory.handle.readFileAlloc(
29 allocator,
30 glibc.abilists_path,
31 glibc.abilists_max_size,
32 ) catch |err| switch (err) {
33 error.OutOfMemory => return error.OutOfMemory,
34 else => fatal("unable to read " ++ glibc.abilists_path ++ ": {s}", .{@errorName(err)}),
35 };
36 defer allocator.free(abilists_contents);
37
38 const glibc_abi = try glibc.loadMetaData(allocator, abilists_contents);
29 defer glibc_abi.destroy(allocator);39 defer glibc_abi.destroy(allocator);
3040
31 var bw = io.bufferedWriter(stdout);41 var bw = io.bufferedWriter(stdout);