| ... | @@ -399,17 +399,38 @@ pub const NativeTargetInfo = struct { | ... | @@ -399,17 +399,38 @@ pub const NativeTargetInfo = struct { |
| 399 | return result; | 399 | return result; |
| 400 | } | 400 | } |
| 401 | | 401 | |
| | 402 | const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { |
| | 403 | error.NoSpaceLeft => unreachable, |
| | 404 | error.NameTooLong => unreachable, |
| | 405 | error.PathAlreadyExists => unreachable, |
| | 406 | error.SharingViolation => unreachable, |
| | 407 | error.InvalidUtf8 => unreachable, |
| | 408 | error.BadPathName => unreachable, |
| | 409 | error.PipeBusy => unreachable, |
| | 410 | |
| | 411 | error.IsDir, |
| | 412 | error.NotDir, |
| | 413 | error.AccessDenied, |
| | 414 | error.NoDevice, |
| | 415 | error.FileNotFound, |
| | 416 | error.FileTooBig, |
| | 417 | error.Unexpected, |
| | 418 | => return defaultAbiAndDynamicLinker(cpu, os, cross_target), |
| | 419 | |
| | 420 | else => |e| return e, |
| | 421 | }; |
| | 422 | defer env_file.close(); |
| | 423 | |
| 402 | // If Zig is statically linked, such as via distributed binary static builds, the above | 424 | // If Zig is statically linked, such as via distributed binary static builds, the above |
| 403 | // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. | 425 | // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. |
| 404 | // Since that path is hard-coded into the shebang line of many portable scripts, it's a | 426 | // Since that path is hard-coded into the shebang line of many portable scripts, it's a |
| 405 | // reasonably reliable path to check for. | 427 | // reasonably reliable path to check for. |
| 406 | return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list, cross_target) catch |err| switch (err) { | 428 | return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { |
| 407 | error.FileSystem, | 429 | error.FileSystem, |
| 408 | error.SystemResources, | 430 | error.SystemResources, |
| 409 | error.SymLinkLoop, | 431 | error.SymLinkLoop, |
| 410 | error.ProcessFdQuotaExceeded, | 432 | error.ProcessFdQuotaExceeded, |
| 411 | error.SystemFdQuotaExceeded, | 433 | error.SystemFdQuotaExceeded, |
| 412 | error.DeviceBusy, | | |
| 413 | => |e| return e, | 434 | => |e| return e, |
| 414 | | 435 | |
| 415 | error.UnableToReadElfFile, | 436 | error.UnableToReadElfFile, |
| ... | @@ -418,7 +439,6 @@ pub const NativeTargetInfo = struct { | ... | @@ -418,7 +439,6 @@ pub const NativeTargetInfo = struct { |
| 418 | error.InvalidElfEndian, | 439 | error.InvalidElfEndian, |
| 419 | error.InvalidElfFile, | 440 | error.InvalidElfFile, |
| 420 | error.InvalidElfMagic, | 441 | error.InvalidElfMagic, |
| 421 | error.UsrBinEnvNotAvailable, | | |
| 422 | error.Unexpected, | 442 | error.Unexpected, |
| 423 | error.UnexpectedEndOfFile, | 443 | error.UnexpectedEndOfFile, |
| 424 | error.NameTooLong, | 444 | error.NameTooLong, |
| ... | @@ -461,32 +481,15 @@ pub const NativeTargetInfo = struct { | ... | @@ -461,32 +481,15 @@ pub const NativeTargetInfo = struct { |
| 461 | }; | 481 | }; |
| 462 | } | 482 | } |
| 463 | | 483 | |
| 464 | fn abiAndDynamicLinkerFromUsrBinEnv( | 484 | pub fn abiAndDynamicLinkerFromFile( |
| | 485 | file: fs.File, |
| 465 | cpu: Target.Cpu, | 486 | cpu: Target.Cpu, |
| 466 | os: Target.Os, | 487 | os: Target.Os, |
| 467 | ld_info_list: []const LdInfo, | 488 | ld_info_list: []const LdInfo, |
| 468 | cross_target: CrossTarget, | 489 | cross_target: CrossTarget, |
| 469 | ) !NativeTargetInfo { | 490 | ) !NativeTargetInfo { |
| 470 | const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { | | |
| 471 | error.NoSpaceLeft => unreachable, | | |
| 472 | error.NameTooLong => unreachable, | | |
| 473 | error.PathAlreadyExists => unreachable, | | |
| 474 | error.SharingViolation => unreachable, | | |
| 475 | error.InvalidUtf8 => unreachable, | | |
| 476 | error.BadPathName => unreachable, | | |
| 477 | error.PipeBusy => unreachable, | | |
| 478 | | | |
| 479 | error.IsDir => return error.UsrBinEnvNotAvailable, | | |
| 480 | error.NotDir => return error.UsrBinEnvNotAvailable, | | |
| 481 | error.AccessDenied => return error.UsrBinEnvNotAvailable, | | |
| 482 | error.NoDevice => return error.UsrBinEnvNotAvailable, | | |
| 483 | error.FileNotFound => return error.UsrBinEnvNotAvailable, | | |
| 484 | error.FileTooBig => return error.UsrBinEnvNotAvailable, | | |
| 485 | | | |
| 486 | else => |e| return e, | | |
| 487 | }; | | |
| 488 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; | 491 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; |
| 489 | _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len); | 492 | _ = try preadFull(file, &hdr_buf, 0, hdr_buf.len); |
| 490 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); | 493 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); |
| 491 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); | 494 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); |
| 492 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; | 495 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; |
| ... | @@ -526,7 +529,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -526,7 +529,7 @@ pub const NativeTargetInfo = struct { |
| 526 | // Reserve some bytes so that we can deref the 64-bit struct fields | 529 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 527 | // even when the ELF file is 32-bits. | 530 | // even when the ELF file is 32-bits. |
| 528 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); | 531 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); |
| 529 | const ph_read_byte_len = try preadFull(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); | 532 | const ph_read_byte_len = try preadFull(file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); |
| 530 | var ph_buf_i: usize = 0; | 533 | var ph_buf_i: usize = 0; |
| 531 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ | 534 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ |
| 532 | ph_i += 1; | 535 | ph_i += 1; |
| ... | @@ -541,7 +544,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -541,7 +544,7 @@ pub const NativeTargetInfo = struct { |
| 541 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | 544 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 542 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | 545 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 543 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; | 546 | if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong; |
| 544 | _ = try preadFull(env_file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); | 547 | _ = try preadFull(file, result.dynamic_linker.buffer[0..p_filesz], p_offset, p_filesz); |
| 545 | // PT_INTERP includes a null byte in p_filesz. | 548 | // PT_INTERP includes a null byte in p_filesz. |
| 546 | const len = p_filesz - 1; | 549 | const len = p_filesz - 1; |
| 547 | // dynamic_linker.max_byte is "max", not "len". | 550 | // dynamic_linker.max_byte is "max", not "len". |
| ... | @@ -573,7 +576,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -573,7 +576,7 @@ pub const NativeTargetInfo = struct { |
| 573 | // even when the ELF file is 32-bits. | 576 | // even when the ELF file is 32-bits. |
| 574 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); | 577 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); |
| 575 | const dyn_read_byte_len = try preadFull( | 578 | const dyn_read_byte_len = try preadFull( |
| 576 | env_file, | 579 | file, |
| 577 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], | 580 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], |
| 578 | dyn_off, | 581 | dyn_off, |
| 579 | dyn_size, | 582 | dyn_size, |
| ... | @@ -617,14 +620,14 @@ pub const NativeTargetInfo = struct { | ... | @@ -617,14 +620,14 @@ pub const NativeTargetInfo = struct { |
| 617 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; | 620 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; |
| 618 | if (sh_buf.len < shentsize) return error.InvalidElfFile; | 621 | if (sh_buf.len < shentsize) return error.InvalidElfFile; |
| 619 | | 622 | |
| 620 | _ = try preadFull(env_file, &sh_buf, str_section_off, shentsize); | 623 | _ = try preadFull(file, &sh_buf, str_section_off, shentsize); |
| 621 | const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); | 624 | const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); |
| 622 | const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); | 625 | const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); |
| 623 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); | 626 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); |
| 624 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); | 627 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); |
| 625 | var strtab_buf: [4096:0]u8 = undefined; | 628 | var strtab_buf: [4096:0]u8 = undefined; |
| 626 | const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); | 629 | const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); |
| 627 | const shstrtab_read_len = try preadFull(env_file, &strtab_buf, shstrtab_off, shstrtab_len); | 630 | const shstrtab_read_len = try preadFull(file, &strtab_buf, shstrtab_off, shstrtab_len); |
| 628 | const shstrtab = strtab_buf[0..shstrtab_read_len]; | 631 | const shstrtab = strtab_buf[0..shstrtab_read_len]; |
| 629 | | 632 | |
| 630 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); | 633 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); |
| ... | @@ -634,7 +637,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -634,7 +637,7 @@ pub const NativeTargetInfo = struct { |
| 634 | // even when the ELF file is 32-bits. | 637 | // even when the ELF file is 32-bits. |
| 635 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); | 638 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); |
| 636 | const sh_read_byte_len = try preadFull( | 639 | const sh_read_byte_len = try preadFull( |
| 637 | env_file, | 640 | file, |
| 638 | sh_buf[0 .. sh_buf.len - sh_reserve], | 641 | sh_buf[0 .. sh_buf.len - sh_reserve], |
| 639 | shoff, | 642 | shoff, |
| 640 | shentsize, | 643 | shentsize, |
| ... | @@ -667,7 +670,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -667,7 +670,7 @@ pub const NativeTargetInfo = struct { |
| 667 | | 670 | |
| 668 | if (dynstr) |ds| { | 671 | if (dynstr) |ds| { |
| 669 | const strtab_len = std.math.min(ds.size, strtab_buf.len); | 672 | const strtab_len = std.math.min(ds.size, strtab_buf.len); |
| 670 | const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_len); | 673 | const strtab_read_len = try preadFull(file, &strtab_buf, ds.offset, shstrtab_len); |
| 671 | const strtab = strtab_buf[0..strtab_read_len]; | 674 | const strtab = strtab_buf[0..strtab_read_len]; |
| 672 | // TODO this pointer cast should not be necessary | 675 | // TODO this pointer cast should not be necessary |
| 673 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); | 676 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); |
| ... | @@ -763,7 +766,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -763,7 +766,7 @@ pub const NativeTargetInfo = struct { |
| 763 | }; | 766 | }; |
| 764 | } | 767 | } |
| 765 | | 768 | |
| 766 | const LdInfo = struct { | 769 | pub const LdInfo = struct { |
| 767 | ld: DynamicLinker, | 770 | ld: DynamicLinker, |
| 768 | abi: Target.Abi, | 771 | abi: Target.Abi, |
| 769 | }; | 772 | }; |