| ... | @@ -347,26 +347,17 @@ fn detectAbiAndDynamicLinker( | ... | @@ -347,26 +347,17 @@ fn detectAbiAndDynamicLinker( |
| 347 | }; | 347 | }; |
| 348 | errdefer file.close(); | 348 | errdefer file.close(); |
| 349 | | 349 | |
| 350 | const line = file.reader().readUntilDelimiter(&buffer, '\n') catch |err| switch (err) { | 350 | const len = preadMin(file, &buffer, 0, buffer.len) catch |err| switch (err) { |
| 351 | error.IsDir => unreachable, // Handled before | 351 | error.UnexpectedEndOfFile, |
| 352 | error.AccessDenied => unreachable, | 352 | error.UnableToReadElfFile, |
| 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, | | |
| 364 | => break :blk file, | 353 | => break :blk file, |
| 365 | | 354 | |
| 366 | else => |e| return e, | 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 | if (!mem.startsWith(u8, line, "#!")) break :blk file; | 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 | file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); | 361 | file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); |
| 371 | file.close(); | 362 | file.close(); |
| 372 | } | 363 | } |
| ... | @@ -375,6 +366,8 @@ fn detectAbiAndDynamicLinker( | ... | @@ -375,6 +366,8 @@ fn detectAbiAndDynamicLinker( |
| 375 | | 366 | |
| 376 | // If Zig is statically linked, such as via distributed binary static builds, the above | 367 | // If Zig is statically linked, such as via distributed binary static builds, the above |
| 377 | // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. | 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 | return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { | 371 | return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { |
| 379 | error.FileSystem, | 372 | error.FileSystem, |
| 380 | error.SystemResources, | 373 | error.SystemResources, |
| ... | @@ -586,6 +579,23 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { | ... | @@ -586,6 +579,23 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { |
| 586 | return max_ver; | 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 | pub const AbiAndDynamicLinkerFromFileError = error{ | 599 | pub const AbiAndDynamicLinkerFromFileError = error{ |
| 590 | FileSystem, | 600 | FileSystem, |
| 591 | SystemResources, | 601 | SystemResources, |
| ... | @@ -816,17 +826,48 @@ pub fn abiAndDynamicLinkerFromFile( | ... | @@ -816,17 +826,48 @@ pub fn abiAndDynamicLinkerFromFile( |
| 816 | else => |e| return e, | 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 | // There is no DT_RUNPATH so we try to find libc.so.6 inside the same | 830 | // There is no DT_RUNPATH so we try to find libc.so.6 inside the same |
| 821 | // directory as the dynamic linker. | 831 | // directory as the dynamic linker. |
| 822 | if (fs.path.dirname(dl_path)) |rpath| { | 832 | if (fs.path.dirname(dl_path)) |rpath| { |
| 823 | if (glibcVerFromRPath(rpath)) |ver| { | 833 | if (glibcVerFromRPath(rpath)) |ver| { |
| 824 | result.target.os.version_range.linux.glibc = ver; | 834 | result.target.os.version_range.linux.glibc = ver; |
| | 835 | break :glibc_ver; |
| 825 | } else |err| switch (err) { | 836 | } else |err| switch (err) { |
| 826 | error.GLibCNotFound => {}, | 837 | error.GLibCNotFound => {}, |
| 827 | else => |e| return e, | 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 | } |