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
119
120
121
122
123
124
125
126
127
128
129
130
131
|
const std = @import("std");
const assert = std.debug.assert;
/// All integers are in big-endian format (needs a byteswap).
pub const ExecHdr = extern struct {
magic: u32,
text: u32,
data: u32,
bss: u32,
syms: u32,
/// You should truncate this to 32 bits on 64 bit systems, then but the actual 8 bytes
/// in the fat header.
entry: u32,
spsz: u32,
pcsz: u32,
comptime {
assert(@sizeOf(@This()) == 32);
}
/// It is up to the caller to discard the last 8 bytes if the header is not fat.
pub fn toU8s(self: *@This()) [40]u8 {
var buf: [40]u8 = undefined;
var i: u8 = 0;
inline for (std.meta.fields(@This())) |f| {
std.mem.writeIntSliceBig(u32, buf[i..][0..4], @field(self, f.name));
i += 4;
}
return buf;
}
};
pub const Sym = struct {
/// Big endian in the file
value: u64,
type: Type,
name: []const u8,
pub const undefined_symbol: Sym = .{
.value = undefined,
.type = .bad,
.name = "undefined_symbol",
};
/// The type field is one of the following characters with the
/// high bit set:
/// T text segment symbol
/// t static text segment symbol
/// L leaf function text segment symbol
/// l static leaf function text segment symbol
/// D data segment symbol
/// d static data segment symbol
/// B bss segment symbol
/// b static bss segment symbol
/// a automatic (local) variable symbol
/// p function parameter symbol
/// f source file name components
/// z source file name
/// Z source file line offset
/// m for '.frame'
pub const Type = enum(u8) {
T = 0x80 | 'T',
t = 0x80 | 't',
L = 0x80 | 'L',
l = 0x80 | 'l',
D = 0x80 | 'D',
d = 0x80 | 'd',
B = 0x80 | 'B',
b = 0x80 | 'b',
a = 0x80 | 'a',
p = 0x80 | 'p',
f = 0x80 | 'f',
z = 0x80 | 'z',
Z = 0x80 | 'Z',
m = 0x80 | 'm',
/// represents an undefined symbol, to be removed in flush
bad = 0,
pub fn toGlobal(self: Type) Type {
return switch (self) {
.t => .T,
.b => .B,
.d => .D,
else => unreachable,
};
}
};
};
pub const HDR_MAGIC = 0x00008000;
pub inline fn _MAGIC(f: anytype, b: anytype) @TypeOf(f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7))) {
return f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7));
}
pub const A_MAGIC = _MAGIC(0, 8); // 68020
pub const I_MAGIC = _MAGIC(0, 11); // intel 386
pub const J_MAGIC = _MAGIC(0, 12); // intel 960 (retired)
pub const K_MAGIC = _MAGIC(0, 13); // sparc
pub const V_MAGIC = _MAGIC(0, 16); // mips 3000 BE
pub const X_MAGIC = _MAGIC(0, 17); // att dsp 3210 (retired)
pub const M_MAGIC = _MAGIC(0, 18); // mips 4000 BE
pub const D_MAGIC = _MAGIC(0, 19); // amd 29000 (retired)
pub const E_MAGIC = _MAGIC(0, 20); // arm
pub const Q_MAGIC = _MAGIC(0, 21); // powerpc
pub const N_MAGIC = _MAGIC(0, 22); // mips 4000 LE
pub const L_MAGIC = _MAGIC(0, 23); // dec alpha (retired)
pub const P_MAGIC = _MAGIC(0, 24); // mips 3000 LE
pub const U_MAGIC = _MAGIC(0, 25); // sparc64
pub const S_MAGIC = _MAGIC(HDR_MAGIC, 26); // amd64
pub const T_MAGIC = _MAGIC(HDR_MAGIC, 27); // powerpc64
pub const R_MAGIC = _MAGIC(HDR_MAGIC, 28); // arm64
pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 {
return switch (arch) {
.x86 => I_MAGIC,
.sparc => K_MAGIC, // TODO should sparc64 and sparcel go here?
.mips => V_MAGIC,
.arm => E_MAGIC,
.aarch64 => R_MAGIC,
.powerpc => Q_MAGIC,
.powerpc64 => T_MAGIC,
.x86_64 => S_MAGIC,
else => error.ArchNotSupportedByPlan9,
};
}
/// gets the quantization of pc for the arch
pub fn getPCQuant(arch: std.Target.Cpu.Arch) !u8 {
return switch (arch) {
.x86, .x86_64 => 1,
.powerpc, .powerpc64, .mips, .sparc, .arm, .aarch64 => 4,
else => error.ArchNotSupportedByPlan9,
};
}
|