Lines 983-989
fn detectAbiAndDynamicLinker(
Link Here
|
983 |
|
983 |
|
984 |
// Best case scenario: the executable is dynamically linked, and we can iterate |
984 |
// Best case scenario: the executable is dynamically linked, and we can iterate |
985 |
// over our own shared objects and find a dynamic linker. |
985 |
// over our own shared objects and find a dynamic linker. |
986 |
const elf_file = blk: { |
986 |
const elf_file = elf_file: { |
987 |
// This block looks for a shebang line in /usr/bin/env, |
987 |
// This block looks for a shebang line in /usr/bin/env, |
988 |
// if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead, |
988 |
// if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead, |
989 |
// doing the same logic recursively in case it finds another shebang line. |
989 |
// doing the same logic recursively in case it finds another shebang line. |
Lines 995-1003
fn detectAbiAndDynamicLinker(
Link Here
|
995 |
// Haiku does not have a /usr root directory. |
995 |
// Haiku does not have a /usr root directory. |
996 |
.haiku => "/bin/env", |
996 |
.haiku => "/bin/env", |
997 |
}; |
997 |
}; |
998 |
// #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1) |
998 |
|
999 |
var buffer: [258]u8 = undefined; |
999 |
// According to `man 2 execve`: |
|
|
1000 |
// |
1001 |
// The kernel imposes a maximum length on the text |
1002 |
// that follows the "#!" characters at the start of a script; |
1003 |
// characters beyond the limit are ignored. |
1004 |
// Before Linux 5.1, the limit is 127 characters. |
1005 |
// Since Linux 5.1, the limit is 255 characters. |
1006 |
// |
1007 |
// Tests show that bash and zsh consider 255 as total limit, |
1008 |
// *including* "#!" characters and ignoring newline. |
1009 |
// For safety, we set max length as 255 + \n (1). |
1010 |
var buffer: [255 + 1]u8 = undefined; |
1000 |
while (true) { |
1011 |
while (true) { |
|
|
1012 |
// Interpreter path can be relative on Linux, but |
1013 |
// for simplicity we are asserting it is an absolute path. |
1001 |
const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { |
1014 |
const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { |
1002 |
error.NoSpaceLeft => unreachable, |
1015 |
error.NoSpaceLeft => unreachable, |
1003 |
error.NameTooLong => unreachable, |
1016 |
error.NameTooLong => unreachable, |
Lines 1027-1053
fn detectAbiAndDynamicLinker(
Link Here
|
1027 |
|
1040 |
|
1028 |
else => |e| return e, |
1041 |
else => |e| return e, |
1029 |
}; |
1042 |
}; |
1030 |
errdefer file.close(); |
1043 |
var is_elf_file = false; |
1031 |
|
1044 |
defer if (is_elf_file == false) file.close(); |
1032 |
const len = preadAtLeast(file, &buffer, 0, buffer.len) catch |err| switch (err) { |
1045 |
|
|
|
1046 |
// Shortest working interpreter path is "#!/i" (4) |
1047 |
// (interpreter is "/i", assuming all pathes are absolute, like in above comment). |
1048 |
// ELF magic number length is also 4. |
1049 |
// |
1050 |
// If file is shorter than that, it is definitely not ELF file |
1051 |
// nor file with "shebang" line. |
1052 |
const min_len: usize = 4; |
1053 |
|
1054 |
const len = preadAtLeast(file, &buffer, 0, min_len) catch |err| switch (err) { |
1033 |
error.UnexpectedEndOfFile, |
1055 |
error.UnexpectedEndOfFile, |
1034 |
error.UnableToReadElfFile, |
1056 |
error.UnableToReadElfFile, |
1035 |
=> break :blk file, |
1057 |
=> return defaultAbiAndDynamicLinker(cpu, os, query), |
1036 |
|
1058 |
|
1037 |
else => |e| return e, |
1059 |
else => |e| return e, |
1038 |
}; |
1060 |
}; |
1039 |
const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file; |
1061 |
const content = buffer[0..len]; |
1040 |
const line = buffer[0..newline]; |
1062 |
|
1041 |
if (!mem.startsWith(u8, line, "#!")) break :blk file; |
1063 |
if (mem.eql(u8, content[0..4], std.elf.MAGIC)) { |
1042 |
var it = mem.tokenizeScalar(u8, line[2..], ' '); |
1064 |
// It is very likely ELF file! |
1043 |
file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, query); |
1065 |
is_elf_file = true; |
1044 |
file.close(); |
1066 |
break :elf_file file; |
|
|
1067 |
} else if (mem.eql(u8, content[0..2], "#!")) { |
1068 |
// We detected shebang, now parse entire line. |
1069 |
|
1070 |
// Trim leading "#!", spaces and tabs. |
1071 |
const trimmed_line = mem.trimLeft(u8, content[2..], &.{ ' ', '\t' }); |
1072 |
|
1073 |
// This line can have: |
1074 |
// * Interpreter path only, |
1075 |
// * Interpreter path and arguments, all separated by space, tab or NUL character. |
1076 |
// And optionally newline at the end. |
1077 |
const path_maybe_args = mem.trimRight(u8, trimmed_line, "\n"); |
1078 |
|
1079 |
// Separate path and args. |
1080 |
const path_end = mem.indexOfAny(u8, path_maybe_args, &.{ ' ', '\t', 0 }) orelse path_maybe_args.len; |
1081 |
|
1082 |
file_name = path_maybe_args[0..path_end]; |
1083 |
continue; |
1084 |
} else { |
1085 |
// Not a ELF file, not a shell script with "shebang line", invalid duck. |
1086 |
return defaultAbiAndDynamicLinker(cpu, os, query); |
1087 |
} |
1045 |
} |
1088 |
} |
1046 |
}; |
1089 |
}; |
1047 |
defer elf_file.close(); |
1090 |
defer elf_file.close(); |
1048 |
|
1091 |
|
1049 |
// If Zig is statically linked, such as via distributed binary static builds, the above |
|
|
1050 |
// trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. |
1051 |
// TODO: inline this function and combine the buffer we already read above to find |
1092 |
// TODO: inline this function and combine the buffer we already read above to find |
1052 |
// the possible shebang line with the buffer we use for the ELF header. |
1093 |
// the possible shebang line with the buffer we use for the ELF header. |
1053 |
return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, query) catch |err| switch (err) { |
1094 |
return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, query) catch |err| switch (err) { |
Lines 1075-1081
fn detectAbiAndDynamicLinker(
Link Here
|
1075 |
}; |
1116 |
}; |
1076 |
} |
1117 |
} |
1077 |
|
1118 |
|
1078 |
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Query) !Target { |
1119 |
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Query) Target { |
1079 |
const abi = query.abi orelse Target.Abi.default(cpu.arch, os); |
1120 |
const abi = query.abi orelse Target.Abi.default(cpu.arch, os); |
1080 |
return .{ |
1121 |
return .{ |
1081 |
.cpu = cpu, |
1122 |
.cpu = cpu, |