| ... | @@ -50,9 +50,12 @@ pub const LoadMetaDataError = error{ | ... | @@ -50,9 +50,12 @@ pub const LoadMetaDataError = error{ |
| 50 | OutOfMemory, | 50 | OutOfMemory, |
| 51 | }; | 51 | }; |
| 52 | | 52 | |
| | 53 | pub const abilists_path = "libc" ++ path.sep_str ++ "glibc" ++ path.sep_str ++ "abilists"; |
| | 54 | pub 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 zig | 56 | /// 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`. |
| 55 | pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI { | 58 | pub 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(); |
| 58 | | 61 | |
| ... | @@ -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(); |
| 62 | | 65 | |
| 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; |
| 80 | | 67 | |
| 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; |
| 663 | | 650 | |
| 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(); |
| 670 | | 657 | |
| 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); |
| 678 | | 665 | |
| 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 | } |
| 682 | | 679 | |
| 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 }); |
| 685 | | 682 | |
| 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(); |
| 691 | | 688 | |
| 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); | | |
| 704 | | 692 | |
| 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 and | 694 | if (targ.arch == target.cpu.arch and |
| 707 | targ.os == target.os.tag and | 695 | 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 here | 701 | unreachable; // target_util.available_libcs prevents us from getting here |
| 714 | }; | 702 | }; |
| 715 | | 703 | |
| 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 | }; |
| 733 | | 721 | |
| 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 | } |
| 746 | | 734 | |
| 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(); |
| 749 | | 737 | |
| 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"); |
| 753 | | 741 | |
| 754 | var inc_i: usize = 0; | 742 | var inc_i: usize = 0; |
| 755 | | 743 | |
| 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; |
| 758 | | 746 | |
| 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; |
| 767 | | 755 | |
| 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; |
| 775 | | 763 | |
| 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); |
| 780 | | 779 | 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 | } |
| 797 | | 785 | |
| 798 | if (!is_terminal) continue; | 786 | if (!is_terminal) continue; |
| 799 | | 787 | |
| 800 | // Pick the default symbol version: | 788 | // Pick the default symbol version: |
| 801 | // - If there are no versions, don't emit it | 789 | // - If there are no versions, don't emit it |
| 802 | // - Take the greatest one <= than the target one | 790 | // - Take the greatest one <= than the target one |
| 803 | // - If none of them is <= than the | 791 | // - If none of them is <= than the |
| 804 | // specified one don't pick any default version | 792 | // 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_5 | 807 | // Example: |
| 821 | // .type _Exit_2_2_5, %function; | 808 | // .globl _Exit_2_2_5 |
| 822 | // .symver _Exit_2_2_5, _Exit@@GLIBC_2.2.5 | 809 | // .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 definition | 813 | 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_name | 818 | const sym_plus_ver = if (want_default) |
| 832 | else | 819 | 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_name | 843 | const sym_plus_ver = if (want_default) |
| 857 | else | 844 | 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; |
| 884 | | 877 | |
| 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; |
| 886 | | 886 | |
| 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; |
| 889 | | 897 | |
| 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; | | |
| 906 | | 902 | |
| 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); |
| 909 | | 907 | |
| 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); |
| 914 | | 913 | 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; |
| 931 | | 921 | |
| 932 | if (!is_terminal) continue; | 922 | // Pick the default symbol version: |
| 933 | | 923 | // - 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 it | 925 | // - If none of them is <= than the |
| 936 | // - Take the greatest one <= than the target one | 926 | // specified one don't pick any default version |
| 937 | // - If none of them is <= than the | 927 | if (versions_len == 0) continue; |
| 938 | // specified one don't pick any default version | 928 | 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_5 | 941 | // 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.5 | 944 | // .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 definition | 948 | 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_name | 953 | const sym_plus_ver = if (want_default) |
| 967 | else | 954 | 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_name | 981 | const sym_plus_ver = if (want_default) |
| 995 | else | 982 | 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 | } |
| 1025 | | 1013 | |
| 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); |
| 1029 | | 1017 | |
| 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 | } |
| 1040 | | 1020 | |
| | 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 | } |
| 1047 | | 1031 | |