| ... | @@ -238,16 +238,6 @@ pub const NativeTargetInfo = struct { | ... | @@ -238,16 +238,6 @@ pub const NativeTargetInfo = struct { |
| 238 | // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined | 238 | // A user could then run that zig compiler on riscv64-linux-gnu. This use case is well-defined |
| 239 | // and supported by Zig. But that means that we must detect the system ABI here rather than | 239 | // and supported by Zig. But that means that we must detect the system ABI here rather than |
| 240 | // relying on `Target.current`. | 240 | // relying on `Target.current`. |
| 241 | const LdInfo = struct { | | |
| 242 | ld_path_buffer: [255]u8, | | |
| 243 | ld_path_max: u8, | | |
| 244 | abi: Target.Abi, | | |
| 245 | | | |
| 246 | pub fn ldPath(self: *const @This()) []const u8 { | | |
| 247 | const m: usize = self.ld_path_max; | | |
| 248 | return self.ld_path_buffer[0 .. m + 1]; | | |
| 249 | } | | |
| 250 | }; | | |
| 251 | const all_abis = comptime blk: { | 241 | const all_abis = comptime blk: { |
| 252 | assert(@enumToInt(Target.Abi.none) == 0); | 242 | assert(@enumToInt(Target.Abi.none) == 0); |
| 253 | const fields = std.meta.fields(Target.Abi)[1..]; | 243 | const fields = std.meta.fields(Target.Abi)[1..]; |
| ... | @@ -333,7 +323,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -333,7 +323,7 @@ pub const NativeTargetInfo = struct { |
| 333 | // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. | 323 | // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. |
| 334 | // Since that path is hard-coded into the shebang line of many portable scripts, it's a | 324 | // Since that path is hard-coded into the shebang line of many portable scripts, it's a |
| 335 | // reasonably reliable path to check for. | 325 | // reasonably reliable path to check for. |
| 336 | return abiAndDynamicLinkerFromUsrBinEnv(cpu, os) catch |err| switch (err) { | 326 | return abiAndDynamicLinkerFromUsrBinEnv(cpu, os, ld_info_list) catch |err| switch (err) { |
| 337 | error.FileSystem, | 327 | error.FileSystem, |
| 338 | error.SystemResources, | 328 | error.SystemResources, |
| 339 | error.SymLinkLoop, | 329 | error.SymLinkLoop, |
| ... | @@ -343,8 +333,6 @@ pub const NativeTargetInfo = struct { | ... | @@ -343,8 +333,6 @@ pub const NativeTargetInfo = struct { |
| 343 | => |e| return e, | 333 | => |e| return e, |
| 344 | | 334 | |
| 345 | error.UnableToReadElfFile, | 335 | error.UnableToReadElfFile, |
| 346 | error.ElfNotADynamicExecutable, | | |
| 347 | error.InvalidElfProgramHeaders, | | |
| 348 | error.InvalidElfClass, | 336 | error.InvalidElfClass, |
| 349 | error.InvalidElfVersion, | 337 | error.InvalidElfVersion, |
| 350 | error.InvalidElfEndian, | 338 | error.InvalidElfEndian, |
| ... | @@ -373,6 +361,10 @@ pub const NativeTargetInfo = struct { | ... | @@ -373,6 +361,10 @@ pub const NativeTargetInfo = struct { |
| 373 | error.NotDir => return error.GnuLibCVersionUnavailable, | 361 | error.NotDir => return error.GnuLibCVersionUnavailable, |
| 374 | error.Unexpected => return error.GnuLibCVersionUnavailable, | 362 | error.Unexpected => return error.GnuLibCVersionUnavailable, |
| 375 | }; | 363 | }; |
| | 364 | return glibcVerFromLinkName(link_name); |
| | 365 | } |
| | 366 | |
| | 367 | fn glibcVerFromLinkName(link_name: []const u8) !std.builtin.Version { |
| 376 | // example: "libc-2.3.4.so" | 368 | // example: "libc-2.3.4.so" |
| 377 | // example: "libc-2.27.so" | 369 | // example: "libc-2.27.so" |
| 378 | const prefix = "libc-"; | 370 | const prefix = "libc-"; |
| ... | @@ -389,7 +381,11 @@ pub const NativeTargetInfo = struct { | ... | @@ -389,7 +381,11 @@ pub const NativeTargetInfo = struct { |
| 389 | }; | 381 | }; |
| 390 | } | 382 | } |
| 391 | | 383 | |
| 392 | fn abiAndDynamicLinkerFromUsrBinEnv(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { | 384 | fn abiAndDynamicLinkerFromUsrBinEnv( |
| | 385 | cpu: Target.Cpu, |
| | 386 | os: Target.Os, |
| | 387 | ld_info_list: []const LdInfo, |
| | 388 | ) !NativeTargetInfo { |
| 393 | const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { | 389 | const env_file = std.fs.openFileAbsoluteC("/usr/bin/env", .{}) catch |err| switch (err) { |
| 394 | error.NoSpaceLeft => unreachable, | 390 | error.NoSpaceLeft => unreachable, |
| 395 | error.NameTooLong => unreachable, | 391 | error.NameTooLong => unreachable, |
| ... | @@ -409,8 +405,7 @@ pub const NativeTargetInfo = struct { | ... | @@ -409,8 +405,7 @@ pub const NativeTargetInfo = struct { |
| 409 | else => |e| return e, | 405 | else => |e| return e, |
| 410 | }; | 406 | }; |
| 411 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; | 407 | var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 align(@alignOf(elf.Elf64_Ehdr)) = undefined; |
| 412 | const hdr_bytes_len = try wrapRead(env_file.pread(&hdr_buf, 0)); | 408 | _ = try preadFull(env_file, &hdr_buf, 0, hdr_buf.len); |
| 413 | if (hdr_bytes_len < @sizeOf(elf.Elf32_Ehdr)) return error.InvalidElfFile; | | |
| 414 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); | 409 | const hdr32 = @ptrCast(*elf.Elf32_Ehdr, &hdr_buf); |
| 415 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); | 410 | const hdr64 = @ptrCast(*elf.Elf64_Ehdr, &hdr_buf); |
| 416 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; | 411 | if (!mem.eql(u8, hdr32.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; |
| ... | @@ -430,7 +425,6 @@ pub const NativeTargetInfo = struct { | ... | @@ -430,7 +425,6 @@ pub const NativeTargetInfo = struct { |
| 430 | var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff); | 425 | var phoff = elfInt(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff); |
| 431 | const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize); | 426 | const phentsize = elfInt(is_64, need_bswap, hdr32.e_phentsize, hdr64.e_phentsize); |
| 432 | const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum); | 427 | const phnum = elfInt(is_64, need_bswap, hdr32.e_phnum, hdr64.e_phnum); |
| 433 | const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx); | | |
| 434 | | 428 | |
| 435 | var result: NativeTargetInfo = .{ | 429 | var result: NativeTargetInfo = .{ |
| 436 | .target = .{ | 430 | .target = .{ |
| ... | @@ -439,67 +433,234 @@ pub const NativeTargetInfo = struct { | ... | @@ -439,67 +433,234 @@ pub const NativeTargetInfo = struct { |
| 439 | .abi = Target.Abi.default(cpu.arch, os), | 433 | .abi = Target.Abi.default(cpu.arch, os), |
| 440 | }, | 434 | }, |
| 441 | }; | 435 | }; |
| | 436 | var rpath_offset: ?u64 = null; // Found inside PT_DYNAMIC |
| 442 | | 437 | |
| 443 | const ph_total_size = std.math.mul(u32, phentsize, phnum) catch |err| switch (err) { | | |
| 444 | error.Overflow => return error.InvalidElfProgramHeaders, | | |
| 445 | }; | | |
| 446 | var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined; | 438 | var ph_buf: [16 * @sizeOf(elf.Elf64_Phdr)]u8 align(@alignOf(elf.Elf64_Phdr)) = undefined; |
| | 439 | if (phentsize > @sizeOf(elf.Elf64_Phdr)) return error.InvalidElfFile; |
| | 440 | |
| 447 | var ph_i: u16 = 0; | 441 | var ph_i: u16 = 0; |
| 448 | while (ph_i < phnum) { | 442 | while (ph_i < phnum) { |
| 449 | // Reserve some bytes so that we can deref the 64-bit struct fields even when the ELF file is 32-bits. | 443 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| 450 | const reserve = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); | 444 | // even when the ELF file is 32-bits. |
| 451 | const read_byte_len = try wrapRead(env_file.pread(ph_buf[0 .. ph_buf.len - reserve], phoff)); | 445 | const ph_reserve: usize = @sizeOf(elf.Elf64_Phdr) - @sizeOf(elf.Elf32_Phdr); |
| 452 | if (read_byte_len < phentsize) return error.ElfNotADynamicExecutable; | 446 | const ph_read_byte_len = try preadFull(env_file, ph_buf[0 .. ph_buf.len - ph_reserve], phoff, phentsize); |
| 453 | var buf_i: usize = 0; | 447 | var ph_buf_i: usize = 0; |
| 454 | while (buf_i < read_byte_len and ph_i < phnum) : ({ | 448 | while (ph_buf_i < ph_read_byte_len and ph_i < phnum) : ({ |
| 455 | ph_i += 1; | 449 | ph_i += 1; |
| 456 | phoff += phentsize; | 450 | phoff += phentsize; |
| 457 | buf_i += phentsize; | 451 | ph_buf_i += phentsize; |
| 458 | }) { | 452 | }) { |
| 459 | const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[buf_i])); | 453 | const ph32 = @ptrCast(*elf.Elf32_Phdr, @alignCast(@alignOf(elf.Elf32_Phdr), &ph_buf[ph_buf_i])); |
| 460 | const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[buf_i])); | 454 | const ph64 = @ptrCast(*elf.Elf64_Phdr, @alignCast(@alignOf(elf.Elf64_Phdr), &ph_buf[ph_buf_i])); |
| 461 | const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); | 455 | const p_type = elfInt(is_64, need_bswap, ph32.p_type, ph64.p_type); |
| 462 | switch (p_type) { | 456 | switch (p_type) { |
| 463 | elf.PT_INTERP => { | 457 | elf.PT_INTERP => { |
| 464 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); | 458 | const p_offset = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| 465 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); | 459 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| 466 | var interp_buf: [255]u8 = undefined; | 460 | if (p_filesz > result.dynamic_linker_buffer.len) return error.NameTooLong; |
| 467 | if (p_filesz > interp_buf.len) return error.NameTooLong; | 461 | _ = try preadFull(env_file, result.dynamic_linker_buffer[0..p_filesz], p_offset, p_filesz); |
| 468 | var read_offset: usize = 0; | | |
| 469 | while (true) { | | |
| 470 | const len = try wrapRead(env_file.pread( | | |
| 471 | interp_buf[read_offset .. p_filesz - read_offset], | | |
| 472 | p_offset + read_offset, | | |
| 473 | )); | | |
| 474 | if (len == 0) return error.UnexpectedEndOfFile; | | |
| 475 | read_offset += len; | | |
| 476 | if (read_offset == p_filesz) break; | | |
| 477 | } | | |
| 478 | // PT_INTERP includes a null byte in p_filesz. | 462 | // PT_INTERP includes a null byte in p_filesz. |
| 479 | result.setDynamicLinker(interp_buf[0 .. p_filesz - 1]); | 463 | const len = p_filesz - 1; |
| | 464 | // dynamic_linker_max is "max", not "len". |
| | 465 | // We know it will fit in u8 because we check against dynamic_linker_buffer.len above. |
| | 466 | result.dynamic_linker_max = @intCast(u8, len - 1); |
| | 467 | |
| | 468 | // Use it to determine ABI. |
| | 469 | const full_ld_path = result.dynamic_linker_buffer[0..len]; |
| | 470 | for (ld_info_list) |ld_info| { |
| | 471 | const standard_ld_basename = fs.path.basename(ld_info.ldPath()); |
| | 472 | if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) { |
| | 473 | result.target.abi = ld_info.abi; |
| | 474 | break; |
| | 475 | } |
| | 476 | } |
| 480 | }, | 477 | }, |
| 481 | elf.PT_DYNAMIC => { | 478 | // We only need this for detecting glibc version. |
| 482 | std.debug.warn("found PT_DYNAMIC\n", .{}); | 479 | elf.PT_DYNAMIC => if (Target.current.os.tag == .linux and result.target.isGnuLibC()) { |
| | 480 | var dyn_off = elfInt(is_64, need_bswap, ph32.p_offset, ph64.p_offset); |
| | 481 | const p_filesz = elfInt(is_64, need_bswap, ph32.p_filesz, ph64.p_filesz); |
| | 482 | const dyn_size: u64 = if (is_64) @sizeOf(elf.Elf64_Dyn) else @sizeOf(elf.Elf32_Dyn); |
| | 483 | const dyn_num = p_filesz / dyn_size; |
| | 484 | var dyn_buf: [16 * @sizeOf(elf.Elf64_Dyn)]u8 align(@alignOf(elf.Elf64_Dyn)) = undefined; |
| | 485 | var dyn_i: usize = 0; |
| | 486 | dyn: while (dyn_i < dyn_num) { |
| | 487 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| | 488 | // even when the ELF file is 32-bits. |
| | 489 | const dyn_reserve: usize = @sizeOf(elf.Elf64_Dyn) - @sizeOf(elf.Elf32_Dyn); |
| | 490 | const dyn_read_byte_len = try preadFull( |
| | 491 | env_file, |
| | 492 | dyn_buf[0 .. dyn_buf.len - dyn_reserve], |
| | 493 | dyn_off, |
| | 494 | dyn_size, |
| | 495 | ); |
| | 496 | var dyn_buf_i: usize = 0; |
| | 497 | while (dyn_buf_i < dyn_read_byte_len and dyn_i < dyn_num) : ({ |
| | 498 | dyn_i += 1; |
| | 499 | dyn_off += dyn_size; |
| | 500 | dyn_buf_i += dyn_size; |
| | 501 | }) { |
| | 502 | const dyn32 = @ptrCast( |
| | 503 | *elf.Elf32_Dyn, |
| | 504 | @alignCast(@alignOf(elf.Elf32_Dyn), &dyn_buf[dyn_buf_i]), |
| | 505 | ); |
| | 506 | const dyn64 = @ptrCast( |
| | 507 | *elf.Elf64_Dyn, |
| | 508 | @alignCast(@alignOf(elf.Elf64_Dyn), &dyn_buf[dyn_buf_i]), |
| | 509 | ); |
| | 510 | const tag = elfInt(is_64, need_bswap, dyn32.d_tag, dyn64.d_tag); |
| | 511 | const val = elfInt(is_64, need_bswap, dyn32.d_val, dyn64.d_val); |
| | 512 | if (tag == elf.DT_RUNPATH) { |
| | 513 | rpath_offset = val; |
| | 514 | break :dyn; |
| | 515 | } |
| | 516 | } |
| | 517 | } |
| 483 | }, | 518 | }, |
| 484 | else => continue, | 519 | else => continue, |
| 485 | } | 520 | } |
| 486 | } | 521 | } |
| 487 | } | 522 | } |
| 488 | | 523 | |
| | 524 | if (Target.current.os.tag == .linux and result.target.isGnuLibC()) { |
| | 525 | if (rpath_offset) |rpoff| { |
| | 526 | const shstrndx = elfInt(is_64, need_bswap, hdr32.e_shstrndx, hdr64.e_shstrndx); |
| | 527 | |
| | 528 | var shoff = elfInt(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff); |
| | 529 | const shentsize = elfInt(is_64, need_bswap, hdr32.e_shentsize, hdr64.e_shentsize); |
| | 530 | const str_section_off = shoff + @as(u64, shentsize) * @as(u64, shstrndx); |
| | 531 | |
| | 532 | var sh_buf: [16 * @sizeOf(elf.Elf64_Shdr)]u8 align(@alignOf(elf.Elf64_Shdr)) = undefined; |
| | 533 | if (sh_buf.len < shentsize) return error.InvalidElfFile; |
| | 534 | |
| | 535 | _ = try preadFull(env_file, &sh_buf, str_section_off, shentsize); |
| | 536 | const shstr32 = @ptrCast(*elf.Elf32_Shdr, @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf)); |
| | 537 | const shstr64 = @ptrCast(*elf.Elf64_Shdr, @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf)); |
| | 538 | const shstrtab_off = elfInt(is_64, need_bswap, shstr32.sh_offset, shstr64.sh_offset); |
| | 539 | const shstrtab_size = elfInt(is_64, need_bswap, shstr32.sh_size, shstr64.sh_size); |
| | 540 | var strtab_buf: [4096:0]u8 = undefined; |
| | 541 | const shstrtab_len = std.math.min(shstrtab_size, strtab_buf.len); |
| | 542 | const shstrtab_read_len = try preadFull(env_file, &strtab_buf, shstrtab_off, shstrtab_len); |
| | 543 | const shstrtab = strtab_buf[0..shstrtab_read_len]; |
| | 544 | |
| | 545 | const shnum = elfInt(is_64, need_bswap, hdr32.e_shnum, hdr64.e_shnum); |
| | 546 | var sh_i: u16 = 0; |
| | 547 | const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: while (sh_i < shnum) { |
| | 548 | // Reserve some bytes so that we can deref the 64-bit struct fields |
| | 549 | // even when the ELF file is 32-bits. |
| | 550 | const sh_reserve: usize = @sizeOf(elf.Elf64_Shdr) - @sizeOf(elf.Elf32_Shdr); |
| | 551 | const sh_read_byte_len = try preadFull( |
| | 552 | env_file, |
| | 553 | sh_buf[0 .. sh_buf.len - sh_reserve], |
| | 554 | shoff, |
| | 555 | shentsize, |
| | 556 | ); |
| | 557 | var sh_buf_i: usize = 0; |
| | 558 | while (sh_buf_i < sh_read_byte_len and sh_i < shnum) : ({ |
| | 559 | sh_i += 1; |
| | 560 | shoff += shentsize; |
| | 561 | sh_buf_i += shentsize; |
| | 562 | }) { |
| | 563 | const sh32 = @ptrCast( |
| | 564 | *elf.Elf32_Shdr, |
| | 565 | @alignCast(@alignOf(elf.Elf32_Shdr), &sh_buf[sh_buf_i]), |
| | 566 | ); |
| | 567 | const sh64 = @ptrCast( |
| | 568 | *elf.Elf64_Shdr, |
| | 569 | @alignCast(@alignOf(elf.Elf64_Shdr), &sh_buf[sh_buf_i]), |
| | 570 | ); |
| | 571 | const sh_name_off = elfInt(is_64, need_bswap, sh32.sh_name, sh64.sh_name); |
| | 572 | // TODO this pointer cast should not be necessary |
| | 573 | const sh_name = mem.toSliceConst(u8, @ptrCast([*:0]u8, shstrtab[sh_name_off..].ptr)); |
| | 574 | if (mem.eql(u8, sh_name, ".dynstr")) { |
| | 575 | break :find_dyn_str .{ |
| | 576 | .offset = elfInt(is_64, need_bswap, sh32.sh_offset, sh64.sh_offset), |
| | 577 | .size = elfInt(is_64, need_bswap, sh32.sh_size, sh64.sh_size), |
| | 578 | }; |
| | 579 | } |
| | 580 | } |
| | 581 | } else null; |
| | 582 | |
| | 583 | if (dynstr) |ds| { |
| | 584 | const strtab_len = std.math.min(ds.size, strtab_buf.len); |
| | 585 | const strtab_read_len = try preadFull(env_file, &strtab_buf, ds.offset, shstrtab_len); |
| | 586 | const strtab = strtab_buf[0..strtab_read_len]; |
| | 587 | // TODO this pointer cast should not be necessary |
| | 588 | const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); |
| | 589 | var it = mem.tokenize(rpath_list, ":"); |
| | 590 | while (it.next()) |rpath| { |
| | 591 | var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) { |
| | 592 | error.NameTooLong => unreachable, |
| | 593 | error.InvalidUtf8 => unreachable, |
| | 594 | error.BadPathName => unreachable, |
| | 595 | error.DeviceBusy => unreachable, |
| | 596 | |
| | 597 | error.FileNotFound, |
| | 598 | error.NotDir, |
| | 599 | error.AccessDenied, |
| | 600 | error.NoDevice, |
| | 601 | => continue, |
| | 602 | |
| | 603 | error.ProcessFdQuotaExceeded, |
| | 604 | error.SystemFdQuotaExceeded, |
| | 605 | error.SystemResources, |
| | 606 | error.SymLinkLoop, |
| | 607 | error.Unexpected, |
| | 608 | => |e| return e, |
| | 609 | }; |
| | 610 | defer dir.close(); |
| | 611 | |
| | 612 | var link_buf: [std.os.PATH_MAX]u8 = undefined; |
| | 613 | const link_name = std.os.readlinkatC( |
| | 614 | dir.fd, |
| | 615 | glibc_so_basename, |
| | 616 | &link_buf, |
| | 617 | ) catch |err| switch (err) { |
| | 618 | error.NameTooLong => unreachable, |
| | 619 | |
| | 620 | error.AccessDenied, |
| | 621 | error.FileNotFound, |
| | 622 | error.NotDir, |
| | 623 | => continue, |
| | 624 | |
| | 625 | error.SystemResources, |
| | 626 | error.FileSystem, |
| | 627 | error.SymLinkLoop, |
| | 628 | error.Unexpected, |
| | 629 | => |e| return e, |
| | 630 | }; |
| | 631 | result.target.os.version_range.linux.glibc = glibcVerFromLinkName( |
| | 632 | link_name, |
| | 633 | ) catch |err| switch (err) { |
| | 634 | error.UnrecognizedGnuLibCFileName, |
| | 635 | error.InvalidGnuLibCVersion, |
| | 636 | => continue, |
| | 637 | }; |
| | 638 | break; |
| | 639 | } |
| | 640 | } |
| | 641 | } |
| | 642 | } |
| | 643 | |
| 489 | return result; | 644 | return result; |
| 490 | } | 645 | } |
| 491 | | 646 | |
| 492 | fn wrapRead(res: std.os.ReadError!usize) !usize { | 647 | fn preadFull(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usize { |
| 493 | return res catch |err| switch (err) { | 648 | var i: u64 = 0; |
| 494 | error.OperationAborted => unreachable, // Windows-only | 649 | while (i < min_read_len) { |
| 495 | error.WouldBlock => unreachable, // Did not request blocking mode | 650 | const len = file.pread(buf[i .. buf.len - i], offset + i) catch |err| switch (err) { |
| 496 | error.SystemResources => return error.SystemResources, | 651 | error.OperationAborted => unreachable, // Windows-only |
| 497 | error.IsDir => return error.UnableToReadElfFile, | 652 | error.WouldBlock => unreachable, // Did not request blocking mode |
| 498 | error.BrokenPipe => return error.UnableToReadElfFile, | 653 | error.SystemResources => return error.SystemResources, |
| 499 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, | 654 | error.IsDir => return error.UnableToReadElfFile, |
| 500 | error.Unexpected => return error.Unexpected, | 655 | error.BrokenPipe => return error.UnableToReadElfFile, |
| 501 | error.InputOutput => return error.FileSystem, | 656 | error.ConnectionResetByPeer => return error.UnableToReadElfFile, |
| 502 | }; | 657 | error.Unexpected => return error.Unexpected, |
| | 658 | error.InputOutput => return error.FileSystem, |
| | 659 | }; |
| | 660 | if (len == 0) return error.UnexpectedEndOfFile; |
| | 661 | i += len; |
| | 662 | } |
| | 663 | return i; |
| 503 | } | 664 | } |
| 504 | | 665 | |
| 505 | fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { | 666 | fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os) !NativeTargetInfo { |
| ... | @@ -513,20 +674,31 @@ pub const NativeTargetInfo = struct { | ... | @@ -513,20 +674,31 @@ pub const NativeTargetInfo = struct { |
| 513 | result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer); | 674 | result.dynamic_linker_max = result.target.standardDynamicLinkerPath(&result.dynamic_linker_buffer); |
| 514 | return result; | 675 | return result; |
| 515 | } | 676 | } |
| 516 | }; | | |
| 517 | | 677 | |
| 518 | fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { | 678 | const LdInfo = struct { |
| 519 | if (is_64) { | 679 | ld_path_buffer: [255]u8, |
| 520 | if (need_bswap) { | 680 | ld_path_max: u8, |
| 521 | return @byteSwap(@TypeOf(int_64), int_64); | 681 | abi: Target.Abi, |
| 522 | } else { | 682 | |
| 523 | return int_64; | 683 | pub fn ldPath(self: *const LdInfo) []const u8 { |
| | 684 | const m: usize = self.ld_path_max; |
| | 685 | return self.ld_path_buffer[0 .. m + 1]; |
| 524 | } | 686 | } |
| 525 | } else { | 687 | }; |
| 526 | if (need_bswap) { | 688 | |
| 527 | return @byteSwap(@TypeOf(int_32), int_32); | 689 | fn elfInt(is_64: bool, need_bswap: bool, int_32: var, int_64: var) @TypeOf(int_64) { |
| | 690 | if (is_64) { |
| | 691 | if (need_bswap) { |
| | 692 | return @byteSwap(@TypeOf(int_64), int_64); |
| | 693 | } else { |
| | 694 | return int_64; |
| | 695 | } |
| 528 | } else { | 696 | } else { |
| 529 | return int_32; | 697 | if (need_bswap) { |
| | 698 | return @byteSwap(@TypeOf(int_32), int_32); |
| | 699 | } else { |
| | 700 | return int_32; |
| | 701 | } |
| 530 | } | 702 | } |
| 531 | } | 703 | } |
| 532 | } | 704 | }; |