aboutsummaryrefslogtreecommitdiff
path: root/src/link/Elf/file.zig
blob: 3b9790dffac31913252d4e84390fc8654eb3e0d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
pub const File = union(enum) {
    zig_module: *ZigModule,
    linker_defined: *LinkerDefined,
    object: *Object,
    // shared_object: *SharedObject,

    pub fn index(file: File) Index {
        return switch (file) {
            inline else => |x| x.index,
        };
    }

    pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {
        return .{ .data = file };
    }

    fn formatPath(
        file: File,
        comptime unused_fmt_string: []const u8,
        options: std.fmt.FormatOptions,
        writer: anytype,
    ) !void {
        _ = unused_fmt_string;
        _ = options;
        switch (file) {
            .zig_module => |x| try writer.print("{s}", .{x.path}),
            .linker_defined => try writer.writeAll("(linker defined)"),
            .object => |x| try writer.print("{}", .{x.fmtPath()}),
            // .shared_object => |x| try writer.writeAll(x.path),
        }
    }

    pub fn isAlive(file: File) bool {
        return switch (file) {
            .zig_module => true,
            .linker_defined => true,
            inline else => |x| x.alive,
        };
    }

    /// Encodes symbol rank so that the following ordering applies:
    /// * strong defined
    /// * weak defined
    /// * strong in lib (dso/archive)
    /// * weak in lib (dso/archive)
    /// * common
    /// * common in lib (archive)
    /// * unclaimed
    pub fn symbolRank(file: File, sym: elf.Elf64_Sym, in_archive: bool) u32 {
        const base: u3 = blk: {
            if (sym.st_shndx == elf.SHN_COMMON) break :blk if (in_archive) 6 else 5;
            // if (file == .shared or in_archive) break :blk switch (sym.st_bind()) {
            if (in_archive) break :blk switch (sym.st_bind()) {
                elf.STB_GLOBAL => 3,
                else => 4,
            };
            break :blk switch (sym.st_bind()) {
                elf.STB_GLOBAL => 1,
                else => 2,
            };
        };
        return (@as(u32, base) << 24) + file.index();
    }

    pub fn resolveSymbols(file: File, elf_file: *Elf) void {
        switch (file) {
            inline else => |x| x.resolveSymbols(elf_file),
        }
    }

    pub fn resetGlobals(file: File, elf_file: *Elf) void {
        switch (file) {
            .linker_defined => unreachable,
            inline else => |x| x.resetGlobals(elf_file),
        }
    }

    pub fn setAlive(file: File) void {
        switch (file) {
            .zig_module, .linker_defined => {},
            inline else => |x| x.alive = true,
        }
    }

    pub fn markLive(file: File, elf_file: *Elf) void {
        switch (file) {
            .zig_module, .linker_defined => unreachable,
            inline else => |x| x.markLive(elf_file),
        }
    }

    pub fn globals(file: File) []const Symbol.Index {
        return switch (file) {
            inline else => |x| x.globals(),
        };
    }

    pub const Index = u32;

    pub const Entry = union(enum) {
        null: void,
        zig_module: ZigModule,
        linker_defined: LinkerDefined,
        object: Object,
        // shared_object: SharedObject,
    };
};

const std = @import("std");
const elf = std.elf;

const Allocator = std.mem.Allocator;
const Elf = @import("../Elf.zig");
const LinkerDefined = @import("LinkerDefined.zig");
const Object = @import("Object.zig");
// const SharedObject = @import("SharedObject.zig");
const Symbol = @import("Symbol.zig");
const ZigModule = @import("ZigModule.zig");