| ... | ... | @@ -347,26 +347,17 @@ fn detectAbiAndDynamicLinker( |
| 347 | 347 | }; |
| 348 | 348 | errdefer file.close(); |
| 349 | 349 | |
| 350 | | const line = file.reader().readUntilDelimiter(&buffer, '\n') catch |err| switch (err) { |
| 351 | | error.IsDir => unreachable, // Handled before |
| 352 | | error.AccessDenied => unreachable, |
| 353 | | error.WouldBlock => unreachable, // Did not request blocking mode |
| 354 | | error.OperationAborted => unreachable, // Windows-only |
| 355 | | error.BrokenPipe => unreachable, |
| 356 | | error.ConnectionResetByPeer => unreachable, |
| 357 | | error.ConnectionTimedOut => unreachable, |
| 358 | | error.InputOutput => unreachable, |
| 359 | | error.Unexpected => unreachable, |
| 360 | | |
| 361 | | error.StreamTooLong, |
| 362 | | error.EndOfStream, |
| 363 | | error.NotOpenForReading, |
| 350 | const len = preadMin(file, &buffer, 0, buffer.len) catch |err| switch (err) { |
| 351 | error.UnexpectedEndOfFile, |
| 352 | error.UnableToReadElfFile, |
| 364 | 353 | => break :blk file, |
| 365 | 354 | |
| 366 | 355 | else => |e| return e, |
| 367 | 356 | }; |
| 357 | const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file; |
| 358 | const line = buffer[0..newline]; |
| 368 | 359 | if (!mem.startsWith(u8, line, "#!")) break :blk file; |
| 369 | | var it = std.mem.tokenize(u8, line[2..], " "); |
| 360 | var it = mem.tokenize(u8, line[2..], " "); |
| 370 | 361 | file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); |
| 371 | 362 | file.close(); |
| 372 | 363 | } |
| ... | ... | @@ -375,6 +366,8 @@ fn detectAbiAndDynamicLinker( |
| 375 | 366 | |
| 376 | 367 | // If Zig is statically linked, such as via distributed binary static builds, the above |
| 377 | 368 | // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. |
| 369 | // TODO: inline this function and combine the buffer we already read above to find |
| 370 | // the possible shebang line with the buffer we use for the ELF header. |
| 378 | 371 | return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { |
| 379 | 372 | error.FileSystem, |
| 380 | 373 | error.SystemResources, |
| ... | ... | @@ -586,6 +579,23 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { |
| 586 | 579 | return max_ver; |
| 587 | 580 | } |
| 588 | 581 | |
| 582 | fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.builtin.Version { |
| 583 | // example: "libc-2.3.4.so" |
| 584 | // example: "libc-2.27.so" |
| 585 | // example: "ld-2.33.so" |
| 586 | const suffix = ".so"; |
| 587 | if (!mem.startsWith(u8, link_name, prefix) or !mem.endsWith(u8, link_name, suffix)) { |
| 588 | return error.UnrecognizedGnuLibCFileName; |
| 589 | } |
| 590 | // chop off "libc-" and ".so" |
| 591 | const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len]; |
| 592 | return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) { |
| 593 | error.Overflow => return error.InvalidGnuLibCVersion, |
| 594 | error.InvalidCharacter => return error.InvalidGnuLibCVersion, |
| 595 | error.InvalidVersion => return error.InvalidGnuLibCVersion, |
| 596 | }; |
| 597 | } |
| 598 | |
| 589 | 599 | pub const AbiAndDynamicLinkerFromFileError = error{ |
| 590 | 600 | FileSystem, |
| 591 | 601 | SystemResources, |
| ... | ... | @@ -816,17 +826,48 @@ pub fn abiAndDynamicLinkerFromFile( |
| 816 | 826 | else => |e| return e, |
| 817 | 827 | } |
| 818 | 828 | } |
| 819 | | } else if (result.dynamic_linker.get()) |dl_path| { |
| 829 | } else if (result.dynamic_linker.get()) |dl_path| glibc_ver: { |
| 820 | 830 | // There is no DT_RUNPATH so we try to find libc.so.6 inside the same |
| 821 | 831 | // directory as the dynamic linker. |
| 822 | 832 | if (fs.path.dirname(dl_path)) |rpath| { |
| 823 | 833 | if (glibcVerFromRPath(rpath)) |ver| { |
| 824 | 834 | result.target.os.version_range.linux.glibc = ver; |
| 835 | break :glibc_ver; |
| 825 | 836 | } else |err| switch (err) { |
| 826 | 837 | error.GLibCNotFound => {}, |
| 827 | 838 | else => |e| return e, |
| 828 | 839 | } |
| 829 | 840 | } |
| 841 | |
| 842 | // So far, no luck. Next we try to see if the information is |
| 843 | // present in the symlink data for the dynamic linker path. |
| 844 | var link_buf: [std.os.PATH_MAX]u8 = undefined; |
| 845 | const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) { |
| 846 | error.NameTooLong => unreachable, |
| 847 | error.InvalidUtf8 => unreachable, // Windows only |
| 848 | error.BadPathName => unreachable, // Windows only |
| 849 | error.UnsupportedReparsePointType => unreachable, // Windows only |
| 850 | |
| 851 | error.AccessDenied, |
| 852 | error.FileNotFound, |
| 853 | error.NotLink, |
| 854 | error.NotDir, |
| 855 | => break :glibc_ver, |
| 856 | |
| 857 | error.SystemResources, |
| 858 | error.FileSystem, |
| 859 | error.SymLinkLoop, |
| 860 | error.Unexpected, |
| 861 | => |e| return e, |
| 862 | }; |
| 863 | result.target.os.version_range.linux.glibc = glibcVerFromLinkName( |
| 864 | fs.path.basename(link_name), |
| 865 | "ld-", |
| 866 | ) catch |err| switch (err) { |
| 867 | error.UnrecognizedGnuLibCFileName, |
| 868 | error.InvalidGnuLibCVersion, |
| 869 | => break :glibc_ver, |
| 870 | }; |
| 830 | 871 | } |
| 831 | 872 | } |
| 832 | 873 | } |