Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Private Function

abiAndDynamicLinkerFromFile

Private Function
std.zig.system.abiAndDynamicLinkerFromFile
fn abiAndDynamicLinkerFromFile(
    file_reader: *Io.File.Reader,
    header: *const elf.Header,
    cpu: Target.Cpu,
    os: Target.Os,
    ld_info_list: []const LdInfo,
    query: Target.Query,
) AbiAndDynamicLinkerFromFileError!Target

Params

Errors

Canceled
AccessDenied
Unexpected
Unseekable
ReadFailed
EndOfStream
NameTooLong
StaticElfFile
InvalidElfFile
StreamTooLong
Timeout
SymLinkLoop
SystemResources
ProcessFdQuotaExceeded
SystemFdQuotaExceeded
IsDir
WouldBlock
InputOutput
BrokenPipe
ConnectionResetByPeer
NotOpenForReading
SocketUnconnected
LockViolation
FileSystem

File

zig/system.zig:584
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
fn abiAndDynamicLinkerFromFile(
    file_reader: *Io.File.Reader,
    header: *const elf.Header,
    cpu: Target.Cpu,
    os: Target.Os,
    ld_info_list: []const LdInfo,
    query: Target.Query,
) AbiAndDynamicLinkerFromFileError!Target {
    const io = file_reader.io;
    var result: Target = .{
        .cpu = cpu,
        .os = os,
        .abi = query.abi orelse Target.Abi.default(cpu.arch, os.tag),
        .ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
        .dynamic_linker = query.dynamic_linker orelse .none,
    };
    var rpath_offset: ?u64 = null; // Found inside PT.DYNAMIC
    const look_for_ld = query.dynamic_linker == null;

    var got_dyn_section: bool = false;
    {
        var it = header.iterateProgramHeaders(file_reader);
        while (try it.next()) |phdr| switch (phdr.type) {
            .INTERP => {
                got_dyn_section = true;

                if (look_for_ld) {
                    const p_filesz = phdr.filesz;
                    if (p_filesz > result.dynamic_linker.buffer.len) return error.NameTooLong;
                    const filesz: usize = @intCast(p_filesz);
                    try file_reader.seekTo(phdr.offset);
                    try file_reader.interface.readSliceAll(result.dynamic_linker.buffer[0..filesz]);
                    // PT.INTERP includes a null byte in filesz.
                    const len = filesz - 1;
                    // dynamic_linker.max_byte is "max", not "len".
                    // We know it will fit in u8 because we check against dynamic_linker.buffer.len above.
                    result.dynamic_linker.len = @intCast(len);

                    // Use it to determine ABI.
                    const full_ld_path = result.dynamic_linker.buffer[0..len];
                    for (ld_info_list) |ld_info| {
                        const standard_ld_basename = fs.path.basename(ld_info.ld.get().?);
                        if (std.mem.endsWith(u8, full_ld_path, standard_ld_basename)) {
                            result.abi = ld_info.abi;
                            break;
                        }
                    }
                }
            },
            // We only need this for detecting glibc version.
            .DYNAMIC => {
                got_dyn_section = true;

                if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) {
                    var dyn_it = header.iterateDynamicSection(file_reader, phdr.offset, phdr.filesz);
                    while (try dyn_it.next()) |dyn| {
                        if (dyn.d_tag == elf.DT_RUNPATH) {
                            rpath_offset = dyn.d_val;
                            break;
                        }
                    }
                }
            },
            else => continue,
        };
    }

    if (!got_dyn_section) {
        return error.StaticElfFile;
    }

    if (builtin.target.os.tag == .linux and result.isGnuLibC() and query.glibc_version == null) {
        const str_section_off = header.shoff + @as(u64, header.shentsize) * @as(u64, header.shstrndx);
        try file_reader.seekTo(str_section_off);
        const shstr = try elf.takeSectionHeader(&file_reader.interface, header.is_64, header.endian);
        var strtab_buf: [4096]u8 = undefined;
        const shstrtab = strtab_buf[0..@min(shstr.sh_size, strtab_buf.len)];
        try file_reader.seekTo(shstr.sh_offset);
        try file_reader.interface.readSliceAll(shstrtab);
        const dynstr: ?struct { offset: u64, size: u64 } = find_dyn_str: {
            var it = header.iterateSectionHeaders(file_reader);
            while (try it.next()) |shdr| {
                const end = mem.findScalarPos(u8, shstrtab, shdr.sh_name, 0) orelse continue;
                const sh_name = shstrtab[shdr.sh_name..end :0];
                if (mem.eql(u8, sh_name, ".dynstr")) break :find_dyn_str .{
                    .offset = shdr.sh_offset,
                    .size = shdr.sh_size,
                };
            } else break :find_dyn_str null;
        };
        if (dynstr) |ds| {
            if (rpath_offset) |rpoff| {
                if (rpoff > ds.size) return error.InvalidElfFile;
                const rpoff_file = ds.offset + rpoff;
                const rp_max_size = ds.size - rpoff;

                try file_reader.seekTo(rpoff_file);
                const rpath_list = try file_reader.interface.takeSentinel(0);
                if (rpath_list.len > rp_max_size) return error.StreamTooLong;

                var it = mem.tokenizeScalar(u8, rpath_list, ':');
                while (it.next()) |rpath| {
                    if (glibcVerFromRPath(io, rpath)) |ver| {
                        result.os.version_range.linux.glibc = ver;
                        return result;
                    } else |err| switch (err) {
                        error.GLibCNotFound => continue,
                        else => |e| return e,
                    }
                }
            }
        }

        if (result.dynamic_linker.get()) |dl_path| glibc_ver: {
            // There is no DT_RUNPATH so we try to find libc.so.6 inside the same
            // directory as the dynamic linker.
            if (fs.path.dirname(dl_path)) |rpath| {
                if (glibcVerFromRPath(io, rpath)) |ver| {
                    result.os.version_range.linux.glibc = ver;
                    return result;
                } else |err| switch (err) {
                    error.GLibCNotFound => {},
                    else => |e| return e,
                }
            }

            // So far, no luck. Next we try to see if the information is
            // present in the symlink data for the dynamic linker path.
            var link_buffer: [posix.PATH_MAX]u8 = undefined;
            const link_name = if (Io.Dir.readLinkAbsolute(io, dl_path, &link_buffer)) |n|
                link_buffer[0..n]
            else |err| switch (err) {
                error.NameTooLong => unreachable,
                error.BadPathName => unreachable, // Windows only
                error.UnsupportedReparsePointType => unreachable, // Windows only
                error.NetworkNotFound => unreachable, // Windows only
                error.AntivirusInterference => unreachable, // Windows only
                error.FileBusy => unreachable, // Windows only

                error.AccessDenied,
                error.PermissionDenied,
                error.FileNotFound,
                error.NotLink,
                error.NotDir,
                => break :glibc_ver,

                error.SystemResources,
                error.FileSystem,
                error.SymLinkLoop,
                error.Canceled,
                error.Unexpected,
                => |e| return e,
            };
            result.os.version_range.linux.glibc = glibcVerFromLinkName(
                fs.path.basename(link_name),
                "ld-",
            ) catch |err| switch (err) {
                error.UnrecognizedGnuLibCFileName,
                error.InvalidGnuLibCVersion,
                => break :glibc_ver,
            };
            return result;
        }

        // Nothing worked so far. Finally we fall back to hard-coded search paths.
        // Some distros such as Debian keep their libc.so.6 in `/lib/$triple/`.
        var path_buf: [posix.PATH_MAX]u8 = undefined;
        var index: usize = 0;
        const prefix = "/lib/";
        const cpu_arch = @tagName(result.cpu.arch);
        const os_tag = @tagName(result.os.tag);
        const abi = @tagName(result.abi);
        @memcpy(path_buf[index..][0..prefix.len], prefix);
        index += prefix.len;
        @memcpy(path_buf[index..][0..cpu_arch.len], cpu_arch);
        index += cpu_arch.len;
        path_buf[index] = '-';
        index += 1;
        @memcpy(path_buf[index..][0..os_tag.len], os_tag);
        index += os_tag.len;
        path_buf[index] = '-';
        index += 1;
        @memcpy(path_buf[index..][0..abi.len], abi);
        index += abi.len;
        const rpath = path_buf[0..index];
        if (glibcVerFromRPath(io, rpath)) |ver| {
            result.os.version_range.linux.glibc = ver;
            return result;
        } else |err| switch (err) {
            error.GLibCNotFound => {},
            else => |e| return e,
        }
    }

    return result;
}