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{
5050 OutOfMemory,
5151};
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
5356/// This function will emit a log error when there is a problem with the zig
5457/// 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 {
5659 const tracy = trace(@src());
5760 defer tracy.end();
5861
......@@ -60,22 +63,6 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI
6063 errdefer arena_allocator.deinit();
6164 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
7966 var index: usize = 0;
8067
8168 {
......@@ -662,386 +649,383 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
662649 const target_version = target.os.version_range.linux.glibc;
663650
664651 // Use the global cache directory.
665 var cache_parent: Cache = .{
652 var cache: Cache = .{
666653 .gpa = comp.gpa,
667654 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
668655 };
669 defer cache_parent.manifest_dir.close();
670
671 var cache = cache_parent.obtain();
672 defer cache.deinit();
673 cache.hash.addBytes(build_options.version);
674 cache.hash.addBytes(comp.zig_lib_directory.path orelse ".");
675 cache.hash.add(target.cpu.arch);
676 cache.hash.add(target.abi);
677 cache.hash.add(target_version);
678
679 const hit = try cache.hit();
680 const digest = cache.final();
681 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
656 defer cache.manifest_dir.close();
657
658 var man = cache.obtain();
659 defer man.deinit();
660 man.hash.addBytes(build_options.version);
661 man.hash.addBytes(comp.zig_lib_directory.path orelse ".");
662 man.hash.add(target.cpu.arch);
663 man.hash.add(target.abi);
664 man.hash.add(target_version);
665
666 const full_abilists_path = try comp.zig_lib_directory.join(arena, &.{abilists_path});
667 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
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.
684 // We use the presence of an "ok" file to determine if it is a true hit.
680 const digest = man.final();
681 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
685682
686683 var o_directory: Compilation.Directory = .{
687684 .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}),
689686 };
690687 defer o_directory.handle.close();
691688
692 const ok_basename = "ok";
693 const actual_hit = if (hit) blk: {
694 o_directory.handle.access(ok_basename, .{}) catch |err| switch (err) {
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);
689 const abilists_contents = man.files.items[abilists_index].contents.?;
690 const metadata = try loadMetaData(comp.gpa, abilists_contents);
691 defer metadata.destroy(comp.gpa);
704692
705 const target_targ_index = for (metadata.all_targets) |targ, i| {
706 if (targ.arch == target.cpu.arch and
707 targ.os == target.os.tag and
708 targ.abi == target.abi)
709 {
710 break i;
711 }
712 } else {
713 unreachable; // target_util.available_libcs prevents us from getting here
714 };
693 const target_targ_index = for (metadata.all_targets) |targ, i| {
694 if (targ.arch == target.cpu.arch and
695 targ.os == target.os.tag and
696 targ.abi == target.abi)
697 {
698 break i;
699 }
700 } else {
701 unreachable; // target_util.available_libcs prevents us from getting here
702 };
715703
716 const target_ver_index = for (metadata.all_versions) |ver, i| {
717 switch (ver.order(target_version)) {
718 .eq => break i,
719 .lt => continue,
720 .gt => {
721 // TODO Expose via compile error mechanism instead of log.
722 log.warn("invalid target glibc version: {}", .{target_version});
723 return error.InvalidTargetGLibCVersion;
724 },
725 }
726 } else blk: {
727 const latest_index = metadata.all_versions.len - 1;
728 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
729 target_version, metadata.all_versions[latest_index],
730 });
731 break :blk latest_index;
732 };
704 const target_ver_index = for (metadata.all_versions) |ver, i| {
705 switch (ver.order(target_version)) {
706 .eq => break i,
707 .lt => continue,
708 .gt => {
709 // TODO Expose via compile error mechanism instead of log.
710 log.warn("invalid target glibc version: {}", .{target_version});
711 return error.InvalidTargetGLibCVersion;
712 },
713 }
714 } else blk: {
715 const latest_index = metadata.all_versions.len - 1;
716 log.warn("zig cannot build new glibc version {}; providing instead {}", .{
717 target_version, metadata.all_versions[latest_index],
718 });
719 break :blk latest_index;
720 };
733721
734 {
735 var map_contents = std.ArrayList(u8).init(arena);
736 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
737 if (ver.patch == 0) {
738 try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
739 } else {
740 try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });
741 }
722 {
723 var map_contents = std.ArrayList(u8).init(arena);
724 for (metadata.all_versions[0 .. target_ver_index + 1]) |ver| {
725 if (ver.patch == 0) {
726 try map_contents.writer().print("GLIBC_{d}.{d} {{ }};\n", .{ ver.major, ver.minor });
727 } else {
728 try map_contents.writer().print("GLIBC_{d}.{d}.{d} {{ }};\n", .{ ver.major, ver.minor, ver.patch });
742729 }
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 :)
745730 }
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);
748 defer stubs_asm.deinit();
735 var stubs_asm = std.ArrayList(u8).init(comp.gpa);
736 defer stubs_asm.deinit();
749737
750 for (libs) |lib, lib_i| {
751 stubs_asm.shrinkRetainingCapacity(0);
752 try stubs_asm.appendSlice(".text\n");
738 for (libs) |lib, lib_i| {
739 stubs_asm.shrinkRetainingCapacity(0);
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]);
757 inc_i += 2;
744 const fn_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);
745 inc_i += 2;
758746
759 var sym_i: usize = 0;
760 var opt_symbol_name: ?[]const u8 = null;
761 var versions_buffer: [32]u8 = undefined;
762 var versions_len: usize = undefined;
763 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
764 const sym_name = opt_symbol_name orelse n: {
765 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);
766 inc_i += name.len + 1;
767
768 opt_symbol_name = name;
769 versions_buffer = undefined;
770 versions_len = 0;
771 break :n name;
772 };
773 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..4]);
774 inc_i += 4;
747 var sym_i: usize = 0;
748 var opt_symbol_name: ?[]const u8 = null;
749 var versions_buffer: [32]u8 = undefined;
750 var versions_len: usize = undefined;
751 while (sym_i < fn_inclusions_len) : (sym_i += 1) {
752 const sym_name = opt_symbol_name orelse n: {
753 const name = mem.sliceTo(metadata.inclusions[inc_i..], 0);
754 inc_i += name.len + 1;
755
756 opt_symbol_name = name;
757 versions_buffer = undefined;
758 versions_len = 0;
759 break :n name;
760 };
761 const targets = mem.readIntLittle(u32, metadata.inclusions[inc_i..][0..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];
777776 inc_i += 1;
778 const is_terminal = (targets & (1 << 31)) != 0;
779 if (is_terminal) opt_symbol_name = null;
780
781 // Test whether the inclusion applies to our current library and target.
782 const ok_lib_and_target =
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;
777 const last = (byte & 0b1000_0000) != 0;
778 const ver_i = @truncate(u7, byte);
779 if (ok_lib_and_target and ver_i <= target_ver_index) {
780 versions_buffer[versions_len] = ver_i;
781 versions_len += 1;
796782 }
783 if (last) break;
784 }
797785
798 if (!is_terminal) continue;
799
800 // Pick the default symbol version:
801 // - If there are no versions, don't emit it
802 // - Take the greatest one <= than the target one
803 // - If none of them is <= than the
804 // specified one don't pick any default version
805 if (versions_len == 0) continue;
806 var chosen_def_ver_index: u8 = 255;
807 {
808 var ver_buf_i: u8 = 0;
809 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
810 const ver_index = versions_buffer[ver_buf_i];
811 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
812 chosen_def_ver_index = ver_index;
813 }
786 if (!is_terminal) continue;
787
788 // Pick the default symbol version:
789 // - If there are no versions, don't emit it
790 // - Take the greatest one <= than the target one
791 // - If none of them is <= than the
792 // specified one don't pick any default version
793 if (versions_len == 0) continue;
794 var chosen_def_ver_index: u8 = 255;
795 {
796 var ver_buf_i: u8 = 0;
797 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
798 const ver_index = versions_buffer[ver_buf_i];
799 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
800 chosen_def_ver_index = ver_index;
814801 }
815802 }
816 {
817 var ver_buf_i: u8 = 0;
818 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
819 // Example:
820 // .globl _Exit_2_2_5
821 // .type _Exit_2_2_5, %function;
822 // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5
823 // _Exit_2_2_5:
824 const ver_index = versions_buffer[ver_buf_i];
825 const ver = metadata.all_versions[ver_index];
826 // Default symbol version definition vs normal symbol version definition
827 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
828 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
829 if (ver.patch == 0) {
830 const sym_plus_ver = if (want_default)
831 sym_name
832 else
833 try std.fmt.allocPrint(
834 arena,
835 "{s}_GLIBC_{d}_{d}",
836 .{ sym_name, ver.major, ver.minor },
837 );
838 try stubs_asm.writer().print(
839 \\.globl {s}
840 \\.type {s}, %function;
841 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
842 \\{s}:
843 \\
844 , .{
845 sym_plus_ver,
846 sym_plus_ver,
847 sym_plus_ver,
848 sym_name,
849 at_sign_str,
850 ver.major,
851 ver.minor,
852 sym_plus_ver,
853 });
854 } else {
855 const sym_plus_ver = if (want_default)
856 sym_name
857 else
858 try std.fmt.allocPrint(
859 arena,
860 "{s}_GLIBC_{d}_{d}_{d}",
861 .{ sym_name, ver.major, ver.minor, ver.patch },
862 );
863 try stubs_asm.writer().print(
864 \\.globl {s}
865 \\.type {s}, %function;
866 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
867 \\{s}:
868 \\
869 , .{
870 sym_plus_ver,
871 sym_plus_ver,
872 sym_plus_ver,
873 sym_name,
874 at_sign_str,
875 ver.major,
876 ver.minor,
877 ver.patch,
878 sym_plus_ver,
879 });
880 }
803 }
804 {
805 var ver_buf_i: u8 = 0;
806 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
807 // Example:
808 // .globl _Exit_2_2_5
809 // .type _Exit_2_2_5, %function;
810 // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5
811 // _Exit_2_2_5:
812 const ver_index = versions_buffer[ver_buf_i];
813 const ver = metadata.all_versions[ver_index];
814 // Default symbol version definition vs normal symbol version definition
815 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
816 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
817 if (ver.patch == 0) {
818 const sym_plus_ver = if (want_default)
819 sym_name
820 else
821 try std.fmt.allocPrint(
822 arena,
823 "{s}_GLIBC_{d}_{d}",
824 .{ sym_name, ver.major, ver.minor },
825 );
826 try stubs_asm.writer().print(
827 \\.globl {s}
828 \\.type {s}, %function;
829 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
830 \\{s}:
831 \\
832 , .{
833 sym_plus_ver,
834 sym_plus_ver,
835 sym_plus_ver,
836 sym_name,
837 at_sign_str,
838 ver.major,
839 ver.minor,
840 sym_plus_ver,
841 });
842 } else {
843 const sym_plus_ver = if (want_default)
844 sym_name
845 else
846 try std.fmt.allocPrint(
847 arena,
848 "{s}_GLIBC_{d}_{d}_{d}",
849 .{ sym_name, ver.major, ver.minor, ver.patch },
850 );
851 try stubs_asm.writer().print(
852 \\.globl {s}
853 \\.type {s}, %function;
854 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
855 \\{s}:
856 \\
857 , .{
858 sym_plus_ver,
859 sym_plus_ver,
860 sym_plus_ver,
861 sym_name,
862 at_sign_str,
863 ver.major,
864 ver.minor,
865 ver.patch,
866 sym_plus_ver,
867 });
881868 }
882869 }
883870 }
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]);
888896 inc_i += 2;
889897
890 sym_i = 0;
891 opt_symbol_name = null;
892 versions_buffer = undefined;
893 versions_len = undefined;
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;
898 const lib_index = metadata.inclusions[inc_i];
899 inc_i += 1;
900 const is_terminal = (targets & (1 << 31)) != 0;
901 if (is_terminal) opt_symbol_name = null;
906902
907 const size = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]);
908 inc_i += 2;
903 // Test whether the inclusion applies to our current library and target.
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];
911910 inc_i += 1;
912 const is_terminal = (targets & (1 << 31)) != 0;
913 if (is_terminal) opt_symbol_name = null;
914
915 // Test whether the inclusion applies to our current library and target.
916 const ok_lib_and_target =
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;
911 const last = (byte & 0b1000_0000) != 0;
912 const ver_i = @truncate(u7, byte);
913 if (ok_lib_and_target and ver_i <= target_ver_index) {
914 versions_buffer[versions_len] = ver_i;
915 versions_len += 1;
930916 }
917 if (last) break;
918 }
919
920 if (!is_terminal) continue;
931921
932 if (!is_terminal) continue;
933
934 // Pick the default symbol version:
935 // - If there are no versions, don't emit it
936 // - Take the greatest one <= than the target one
937 // - If none of them is <= than the
938 // specified one don't pick any default version
939 if (versions_len == 0) continue;
940 var chosen_def_ver_index: u8 = 255;
941 {
942 var ver_buf_i: u8 = 0;
943 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
944 const ver_index = versions_buffer[ver_buf_i];
945 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
946 chosen_def_ver_index = ver_index;
947 }
922 // Pick the default symbol version:
923 // - If there are no versions, don't emit it
924 // - Take the greatest one <= than the target one
925 // - If none of them is <= than the
926 // specified one don't pick any default version
927 if (versions_len == 0) continue;
928 var chosen_def_ver_index: u8 = 255;
929 {
930 var ver_buf_i: u8 = 0;
931 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
932 const ver_index = versions_buffer[ver_buf_i];
933 if (chosen_def_ver_index == 255 or ver_index > chosen_def_ver_index) {
934 chosen_def_ver_index = ver_index;
948935 }
949936 }
950 {
951 var ver_buf_i: u8 = 0;
952 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
953 // Example:
954 // .globl environ_2_2_5
955 // .type environ_2_2_5, %object;
956 // .size environ_2_2_5, 4;
957 // .symver environ_2_2_5, environ@@GLIBC_2.2.5
958 // environ_2_2_5:
959 const ver_index = versions_buffer[ver_buf_i];
960 const ver = metadata.all_versions[ver_index];
961 // Default symbol version definition vs normal symbol version definition
962 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
963 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
964 if (ver.patch == 0) {
965 const sym_plus_ver = if (want_default)
966 sym_name
967 else
968 try std.fmt.allocPrint(
969 arena,
970 "{s}_GLIBC_{d}_{d}",
971 .{ sym_name, ver.major, ver.minor },
972 );
973 try stubs_asm.writer().print(
974 \\.globl {s}
975 \\.type {s}, %object;
976 \\.size {s}, {d};
977 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
978 \\{s}:
979 \\
980 , .{
981 sym_plus_ver,
982 sym_plus_ver,
983 sym_plus_ver,
984 size,
985 sym_plus_ver,
986 sym_name,
987 at_sign_str,
988 ver.major,
989 ver.minor,
990 sym_plus_ver,
991 });
992 } else {
993 const sym_plus_ver = if (want_default)
994 sym_name
995 else
996 try std.fmt.allocPrint(
997 arena,
998 "{s}_GLIBC_{d}_{d}_{d}",
999 .{ sym_name, ver.major, ver.minor, ver.patch },
1000 );
1001 try stubs_asm.writer().print(
1002 \\.globl {s}
1003 \\.type {s}, %object;
1004 \\.size {s}, {d};
1005 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
1006 \\{s}:
1007 \\
1008 , .{
1009 sym_plus_ver,
1010 sym_plus_ver,
1011 sym_plus_ver,
1012 size,
1013 sym_plus_ver,
1014 sym_name,
1015 at_sign_str,
1016 ver.major,
1017 ver.minor,
1018 ver.patch,
1019 sym_plus_ver,
1020 });
1021 }
937 }
938 {
939 var ver_buf_i: u8 = 0;
940 while (ver_buf_i < versions_len) : (ver_buf_i += 1) {
941 // Example:
942 // .globl environ_2_2_5
943 // .type environ_2_2_5, %object;
944 // .size environ_2_2_5, 4;
945 // .symver environ_2_2_5, environ@@GLIBC_2.2.5
946 // environ_2_2_5:
947 const ver_index = versions_buffer[ver_buf_i];
948 const ver = metadata.all_versions[ver_index];
949 // Default symbol version definition vs normal symbol version definition
950 const want_default = chosen_def_ver_index != 255 and ver_index == chosen_def_ver_index;
951 const at_sign_str: []const u8 = if (want_default) "@@" else "@";
952 if (ver.patch == 0) {
953 const sym_plus_ver = if (want_default)
954 sym_name
955 else
956 try std.fmt.allocPrint(
957 arena,
958 "{s}_GLIBC_{d}_{d}",
959 .{ sym_name, ver.major, ver.minor },
960 );
961 try stubs_asm.writer().print(
962 \\.globl {s}
963 \\.type {s}, %object;
964 \\.size {s}, {d};
965 \\.symver {s}, {s}{s}GLIBC_{d}.{d}
966 \\{s}:
967 \\
968 , .{
969 sym_plus_ver,
970 sym_plus_ver,
971 sym_plus_ver,
972 size,
973 sym_plus_ver,
974 sym_name,
975 at_sign_str,
976 ver.major,
977 ver.minor,
978 sym_plus_ver,
979 });
980 } else {
981 const sym_plus_ver = if (want_default)
982 sym_name
983 else
984 try std.fmt.allocPrint(
985 arena,
986 "{s}_GLIBC_{d}_{d}_{d}",
987 .{ sym_name, ver.major, ver.minor, ver.patch },
988 );
989 try stubs_asm.writer().print(
990 \\.globl {s}
991 \\.type {s}, %object;
992 \\.size {s}, {d};
993 \\.symver {s}, {s}{s}GLIBC_{d}.{d}.{d}
994 \\{s}:
995 \\
996 , .{
997 sym_plus_ver,
998 sym_plus_ver,
999 sym_plus_ver,
1000 size,
1001 sym_plus_ver,
1002 sym_name,
1003 at_sign_str,
1004 ver.major,
1005 ver.minor,
1006 ver.patch,
1007 sym_plus_ver,
1008 });
10221009 }
10231010 }
10241011 }
1012 }
10251013
1026 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;
1028 try o_directory.handle.writeFile(asm_file_basename, stubs_asm.items);
1014 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
1015 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
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);
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 }
1018 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib);
10391019 }
10401020
1021 man.writeManifest() catch |err| {
1022 log.warn("failed to write cache manifest for glibc stubs: {s}", .{@errorName(err)});
1023 };
1024
10411025 assert(comp.glibc_so_files == null);
10421026 comp.glibc_so_files = BuiltSharedObjects{
1043 .lock = cache.toOwnedLock(),
1044 .dir_path = try path.join(comp.gpa, &[_][]const u8{ comp.global_cache_directory.path.?, o_sub_path }),
1027 .lock = man.toOwnedLock(),
1028 .dir_path = try comp.global_cache_directory.join(comp.gpa, &.{ "o", &digest }),
10451029 };
10461030}
10471031
src/print_targets.zig+11-1
......@@ -25,7 +25,17 @@ pub fn cmdTargets(
2525 defer zig_lib_directory.handle.close();
2626 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);
2939 defer glibc_abi.destroy(allocator);
3040
3141 var bw = io.bufferedWriter(stdout);