| ... | ... | @@ -50,9 +50,12 @@ pub const LoadMetaDataError = error{ |
| 50 | 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 | 56 | /// This function will emit a log error when there is a problem with the zig |
| 54 | 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 | 59 | const tracy = trace(@src()); |
| 57 | 60 | defer tracy.end(); |
| 58 | 61 | |
| ... | ... | @@ -60,22 +63,6 @@ pub fn loadMetaData(gpa: Allocator, zig_lib_dir: fs.Dir) LoadMetaDataError!*ABI |
| 60 | 63 | errdefer arena_allocator.deinit(); |
| 61 | 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 | 66 | var index: usize = 0; |
| 80 | 67 | |
| 81 | 68 | { |
| ... | ... | @@ -662,386 +649,383 @@ pub fn buildSharedObjects(comp: *Compilation) !void { |
| 662 | 649 | const target_version = target.os.version_range.linux.glibc; |
| 663 | 650 | |
| 664 | 651 | // Use the global cache directory. |
| 665 | | var cache_parent: Cache = .{ |
| 652 | var cache: Cache = .{ |
| 666 | 653 | .gpa = comp.gpa, |
| 667 | 654 | .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}), |
| 668 | 655 | }; |
| 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 | } |
| 682 | 679 | |
| 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 }); |
| 685 | 682 | |
| 686 | 683 | var o_directory: Compilation.Directory = .{ |
| 687 | 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 | 687 | defer o_directory.handle.close(); |
| 691 | 688 | |
| 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); |
| 704 | 692 | |
| 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 | }; |
| 715 | 703 | |
| 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 | }; |
| 733 | 721 | |
| 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 }); |
| 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); |
| 748 | | defer stubs_asm.deinit(); |
| 735 | var stubs_asm = std.ArrayList(u8).init(comp.gpa); |
| 736 | defer stubs_asm.deinit(); |
| 749 | 737 | |
| 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"); |
| 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]); |
| 757 | | inc_i += 2; |
| 744 | const fn_inclusions_len = mem.readIntLittle(u16, metadata.inclusions[inc_i..][0..2]); |
| 745 | inc_i += 2; |
| 758 | 746 | |
| 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; |
| 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 | 776 | 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; |
| 796 | 782 | } |
| 783 | if (last) break; |
| 784 | } |
| 797 | 785 | |
| 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; |
| 814 | 801 | } |
| 815 | 802 | } |
| 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 | }); |
| 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 | 896 | inc_i += 2; |
| 889 | 897 | |
| 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; |
| 906 | 902 | |
| 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); |
| 909 | 907 | |
| 910 | | const lib_index = metadata.inclusions[inc_i]; |
| 908 | while (true) { |
| 909 | const byte = metadata.inclusions[inc_i]; |
| 911 | 910 | 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; |
| 930 | 916 | } |
| 917 | if (last) break; |
| 918 | } |
| 919 | |
| 920 | if (!is_terminal) continue; |
| 931 | 921 | |
| 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; |
| 948 | 935 | } |
| 949 | 936 | } |
| 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 | }); |
| 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. |
| 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); |
| 1029 | 1017 | |
| 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); |
| 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 | 1025 | assert(comp.glibc_so_files == null); |
| 1042 | 1026 | 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 }), |
| 1045 | 1029 | }; |
| 1046 | 1030 | } |
| 1047 | 1031 | |