Dream of my own C compiler
This commit is contained in:
55
packages/tcc/src/CType.zig
Normal file
55
packages/tcc/src/CType.zig
Normal file
@@ -0,0 +1,55 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const Sym = @import("Sym.zig");
|
||||
|
||||
const Type = packed struct(u32) {
|
||||
basic_type: enum(u4) {
|
||||
void,
|
||||
byte,
|
||||
short,
|
||||
int,
|
||||
llong,
|
||||
ptr,
|
||||
func,
|
||||
@"struct",
|
||||
float,
|
||||
double,
|
||||
ldouble,
|
||||
bool,
|
||||
qlong,
|
||||
qfloat,
|
||||
},
|
||||
unsigned: bool = false,
|
||||
defsign: bool = false,
|
||||
array: bool = false,
|
||||
bitfield: bool = false,
|
||||
constant: bool = false,
|
||||
@"volatile": bool = false,
|
||||
vla: bool = false,
|
||||
long: bool = false,
|
||||
@"extern": bool = false,
|
||||
static: bool = false,
|
||||
typedef: bool = false,
|
||||
@"inline": bool = false,
|
||||
_unused: u4 = 0,
|
||||
extra: Extra = .empty,
|
||||
|
||||
pub const Extra = packed struct(u12) {
|
||||
bit_pos: u6,
|
||||
bit_size: u6,
|
||||
|
||||
pub const empty: Extra = @bitCast(0);
|
||||
pub const @"union": Extra = @bitCast(1);
|
||||
pub const @"enum": Extra = @bitCast(2);
|
||||
pub const enum_val: Extra = @bitCast(3);
|
||||
};
|
||||
|
||||
pub fn isFloat(self: Type) bool {
|
||||
const bt = self.basic_type;
|
||||
return bt == .ldouble or bt == .double or bt == .float or bt == .qfloat;
|
||||
}
|
||||
};
|
||||
|
||||
t: Type,
|
||||
ref: *Sym,
|
||||
50
packages/tcc/src/Elf.zig
Normal file
50
packages/tcc/src/Elf.zig
Normal file
@@ -0,0 +1,50 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const Section = @import("Section.zig");
|
||||
|
||||
cur_text_section: *Section,
|
||||
|
||||
// --- x86_64 RELOCATIONS ---
|
||||
|
||||
pub const R_X86_64_NONE = 0;
|
||||
pub const R_X86_64_64 = 1;
|
||||
pub const R_X86_64_PC32 = 2;
|
||||
pub const R_X86_64_GOT32 = 3;
|
||||
pub const R_X86_64_PLT32 = 4;
|
||||
pub const R_X86_64_COPY = 5;
|
||||
pub const R_X86_64_GLOB_DAT = 6;
|
||||
pub const R_X86_64_JUMP_SLOT = 7;
|
||||
pub const R_X86_64_RELATIVE = 8;
|
||||
pub const R_X86_64_GOTPCREL = 9;
|
||||
pub const R_X86_64_32 = 10;
|
||||
pub const R_X86_64_32S = 11;
|
||||
pub const R_X86_64_16 = 12;
|
||||
pub const R_X86_64_PC16 = 13;
|
||||
pub const R_X86_64_8 = 14;
|
||||
pub const R_X86_64_PC8 = 15;
|
||||
pub const R_X86_64_DTPMOD64 = 16;
|
||||
pub const R_X86_64_DTPOFF64 = 17;
|
||||
pub const R_X86_64_TPOFF64 = 18;
|
||||
pub const R_X86_64_TLSGD = 19;
|
||||
pub const R_X86_64_TLSLD = 20;
|
||||
pub const R_X86_64_DTPOFF32 = 21;
|
||||
pub const R_X86_64_GOTTPOFF = 22;
|
||||
pub const R_X86_64_TPOFF32 = 23;
|
||||
pub const R_X86_64_PC64 = 24;
|
||||
pub const R_X86_64_GOTOFF64 = 25;
|
||||
pub const R_X86_64_GOTPC32 = 26;
|
||||
pub const R_X86_64_GOT64 = 27;
|
||||
pub const R_X86_64_GOTPCREL64 = 28;
|
||||
pub const R_X86_64_GOTPC64 = 29;
|
||||
pub const R_X86_64_GOTPLT64 = 30;
|
||||
pub const R_X86_64_PLTOFF64 = 31;
|
||||
pub const R_X86_64_SIZE32 = 32;
|
||||
pub const R_X86_64_SIZE64 = 33;
|
||||
pub const R_X86_64_GOTPC32_TLSDESC = 34;
|
||||
pub const R_X86_64_TLSDESC_CALL = 35;
|
||||
pub const R_X86_64_TLSDESC = 36;
|
||||
pub const R_X86_64_IRELATIVE = 37;
|
||||
pub const R_X86_64_RELATIVE64 = 38;
|
||||
pub const R_X86_64_GOTPCRELX = 41;
|
||||
pub const R_X86_64_REX_GOTPCRELX = 42;
|
||||
17
packages/tcc/src/Gen.zig
Normal file
17
packages/tcc/src/Gen.zig
Normal file
@@ -0,0 +1,17 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const Elf = @import("Elf.zig");
|
||||
const Section = @import("Section.zig");
|
||||
const Sym = @import("Sym.zig");
|
||||
|
||||
nocode_wanted: u32,
|
||||
ind: u32,
|
||||
|
||||
pub fn greloca(self: *Self, elf: *Elf, section: *Section, maybe_sym: ?*Sym, offset: u64, relocation: u32, addend: i64) void {
|
||||
if (self.nocode_wanted > 0 and section == elf.cur_text_section) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
57
packages/tcc/src/SValue.zig
Normal file
57
packages/tcc/src/SValue.zig
Normal file
@@ -0,0 +1,57 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const CType = @import("CType.zig");
|
||||
const Sym = @import("Sym.zig");
|
||||
|
||||
type: CType,
|
||||
r: Register,
|
||||
r2: Register = .{ .register = Register.@"const" },
|
||||
c: CValue = std.mem.zeroes(CValue),
|
||||
sym: ?*Sym = null,
|
||||
|
||||
pub const Register = packed struct(u16) {
|
||||
location: Location = .{},
|
||||
_unused: u2 = 0,
|
||||
flags: Flags = .{},
|
||||
|
||||
pub const Location = packed struct(u6) {
|
||||
value: u6 = 0,
|
||||
|
||||
pub inline fn isRegister(self: @This()) bool {
|
||||
return self.value < @"const".value;
|
||||
}
|
||||
|
||||
pub const @"const": @This() = .{ .value = 0x30 };
|
||||
pub const llocal: @This() = .{ .value = 0x31 };
|
||||
pub const local: @This() = .{ .value = 0x32 };
|
||||
pub const cmp: @This() = .{ .value = 0x33 };
|
||||
pub const jmp: @This() = .{ .value = 0x34 };
|
||||
pub const jmpi: @This() = .{ .value = 0x35 };
|
||||
};
|
||||
|
||||
pub const Flags = packed struct(u8) {
|
||||
lval: bool = false,
|
||||
sym: bool = false,
|
||||
mustcast: bool = false,
|
||||
mustbound: bool = false,
|
||||
lval_type: packed struct(u3) {
|
||||
byte: bool = false,
|
||||
short: bool = false,
|
||||
unsigned: bool = false,
|
||||
} = .{},
|
||||
bounded: bool = false,
|
||||
};
|
||||
};
|
||||
|
||||
pub const CValue = extern union {
|
||||
ld: c_longdouble,
|
||||
d: f64,
|
||||
f: f32,
|
||||
i: u64,
|
||||
str: extern struct {
|
||||
size: u32,
|
||||
data: ?*anyopaque,
|
||||
},
|
||||
tab: [4]u32,
|
||||
};
|
||||
22
packages/tcc/src/Section.zig
Normal file
22
packages/tcc/src/Section.zig
Normal file
@@ -0,0 +1,22 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const Sym = @import("Sym.zig");
|
||||
|
||||
/// Current data offset.
|
||||
data_offset: usize,
|
||||
/// Allocated section data.
|
||||
data: []u8,
|
||||
|
||||
pub fn realloc(self: *Self, new_size: usize) void {
|
||||
var size = self.data.len;
|
||||
if (size == 0) {
|
||||
size = 1;
|
||||
}
|
||||
while (size < new_size) {
|
||||
size *= 2;
|
||||
}
|
||||
const data: [*]u8 = std.c.realloc(self.data.ptr, size).?;
|
||||
@memset(data[self.data.len..size], 0);
|
||||
self.data = data[0..size];
|
||||
}
|
||||
65
packages/tcc/src/Sym.zig
Normal file
65
packages/tcc/src/Sym.zig
Normal file
@@ -0,0 +1,65 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const CType = @import("CType.zig");
|
||||
const SValue = @import("SValue.zig");
|
||||
|
||||
v: u32,
|
||||
r: SValue.Register,
|
||||
a: SymAttr,
|
||||
u: extern union {
|
||||
s: extern struct {
|
||||
c: u32,
|
||||
u: extern union {
|
||||
sym_scope: u32,
|
||||
jnext: u32,
|
||||
f: FuncAttr,
|
||||
auxtype: u32,
|
||||
},
|
||||
},
|
||||
enum_val: u64,
|
||||
d: ?*u32,
|
||||
},
|
||||
type: CType,
|
||||
w: extern union {
|
||||
next: ?*Self,
|
||||
asm_label: u32,
|
||||
},
|
||||
prev: ?*Self,
|
||||
prev_tok: ?*Self,
|
||||
|
||||
pub const SymAttr = packed struct(u16) {
|
||||
/// log2(align) + 1 (0 means unspecified)
|
||||
aligned: u5 = 0,
|
||||
@"packed": bool = false,
|
||||
weak: bool = 0,
|
||||
visibility: Visibility = .default,
|
||||
dllexport: bool = false,
|
||||
dllimport: bool = false,
|
||||
_unused: u5 = 0,
|
||||
};
|
||||
|
||||
pub const Visibility = enum(u2) {
|
||||
default = 0,
|
||||
internal = 1,
|
||||
hidden = 2,
|
||||
protected = 3,
|
||||
};
|
||||
|
||||
pub const FuncAttr = packed struct(u32) {
|
||||
func_call: enum(u3) {
|
||||
cdecl = 0,
|
||||
stdcall = 1,
|
||||
fastcall1 = 2,
|
||||
fastcall2 = 3,
|
||||
fastcall3 = 4,
|
||||
fastcallw = 5,
|
||||
},
|
||||
func_type: enum(u2) {
|
||||
new = 1,
|
||||
old = 2,
|
||||
ellipsis = 3,
|
||||
},
|
||||
func_args: u8,
|
||||
_unused: u19,
|
||||
};
|
||||
17
packages/tcc/src/tcc.zig
Normal file
17
packages/tcc/src/tcc.zig
Normal file
@@ -0,0 +1,17 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const include_stack_size = 32;
|
||||
pub const ifdef_stack_size = 64;
|
||||
pub const vstack_size = 256;
|
||||
pub const string_max_size = 1024;
|
||||
pub const pack_stack_size = 8;
|
||||
|
||||
pub const tok_hash_size = 16384;
|
||||
pub const tok_alloc_incr = 512;
|
||||
pub const tok_max_size = 4;
|
||||
|
||||
pub fn err(comptime fmt: []const u8, args: anytype) noreturn {
|
||||
// TODO Full implementation of original tcc_error
|
||||
std.log.err(fmt, args);
|
||||
std.posix.exit(1);
|
||||
}
|
||||
339
packages/tcc/src/x86_64.zig
Normal file
339
packages/tcc/src/x86_64.zig
Normal file
@@ -0,0 +1,339 @@
|
||||
const std = @import("std");
|
||||
const Self = @This();
|
||||
|
||||
const tcc = @import("tcc.zig");
|
||||
|
||||
const CType = @import("CType.zig");
|
||||
const Elf = @import("Elf.zig");
|
||||
const Gen = @import("Gen.zig");
|
||||
const SValue = @import("SValue.zig");
|
||||
const Sym = @import("Sym.zig");
|
||||
|
||||
/// Number of available registers.
|
||||
pub const register_count = 25;
|
||||
/// Whether function parameters must be evaluated in reverse order.
|
||||
pub const invert_function_parameters = true;
|
||||
/// Pointer size in bytes
|
||||
pub const pointer_size = 8;
|
||||
/// `long double` size in bytes
|
||||
pub const long_double_size = 16;
|
||||
/// `long double` alignment in bytes
|
||||
pub const long_double_alignment = 16;
|
||||
/// Maximum alignment for `aligned` attribute
|
||||
pub const max_align = 16;
|
||||
|
||||
pub const RegisterClass = packed struct(u32) {
|
||||
/// Generic int register.
|
||||
int: bool = false,
|
||||
/// Generic float register.
|
||||
float: bool = false,
|
||||
rax: bool = false,
|
||||
rcx: bool = false,
|
||||
rdx: bool = false,
|
||||
/// Only for long double.
|
||||
st0: bool = false,
|
||||
r8: bool = false,
|
||||
r9: bool = false,
|
||||
r10: bool = false,
|
||||
r11: bool = false,
|
||||
xmm0: bool = false,
|
||||
xmm1: bool = false,
|
||||
xmm2: bool = false,
|
||||
xmm3: bool = false,
|
||||
xmm4: bool = false,
|
||||
xmm5: bool = false,
|
||||
xmm6: bool = false,
|
||||
xmm7: bool = false,
|
||||
_pad: u14 = 0,
|
||||
|
||||
pub const empty: RegisterClass = .{};
|
||||
/// Function return: integer register.
|
||||
pub const iret: RegisterClass = .{ .rax = true };
|
||||
/// Function return: second integer register.
|
||||
pub const lret: RegisterClass = .{ .rdx = true };
|
||||
/// Function return: float register.
|
||||
pub const fret: RegisterClass = .{ .xmm0 = true };
|
||||
/// Function return: second float register.
|
||||
pub const qret: RegisterClass = .{ .xmm0 = true };
|
||||
};
|
||||
|
||||
pub const Register = packed struct(u8) {
|
||||
r: enum(u5) {
|
||||
rax = 0,
|
||||
rcx = 1,
|
||||
rdx = 2,
|
||||
rsp = 4,
|
||||
rsi = 6,
|
||||
rdi = 7,
|
||||
|
||||
r8 = 8,
|
||||
r9 = 9,
|
||||
r10 = 10,
|
||||
r11 = 11,
|
||||
|
||||
xmm0 = 16,
|
||||
xmm1 = 17,
|
||||
xmm2 = 18,
|
||||
xmm3 = 19,
|
||||
xmm4 = 20,
|
||||
xmm5 = 21,
|
||||
xmm6 = 22,
|
||||
xmm7 = 23,
|
||||
|
||||
st0 = 24,
|
||||
},
|
||||
mem: bool = false,
|
||||
_unused: u2 = 0,
|
||||
|
||||
/// Function return: integer register.
|
||||
pub const iret: Register = .{ .r = .rax };
|
||||
/// Function return: second integer register.
|
||||
pub const lret: Register = .{ .r = .rdx };
|
||||
/// Function return: float register.
|
||||
pub const fret: Register = .{ .r = .xmm0 };
|
||||
/// Function return: second float register.
|
||||
pub const qret: Register = .{ .r = .xmm1 };
|
||||
|
||||
pub inline fn fromInt(value: u8) Register {
|
||||
return @bitCast(value);
|
||||
}
|
||||
|
||||
pub const mem_mask = 0x20;
|
||||
};
|
||||
|
||||
pub inline fn rexBase(value: u8) u8 {
|
||||
return (value >> 3) & 0b1;
|
||||
}
|
||||
|
||||
pub inline fn regValue(value: u8) u8 {
|
||||
return value & 0b111;
|
||||
}
|
||||
|
||||
pub const register_classes = [register_count]RegisterClass{
|
||||
.{ .int = true, .rax = true },
|
||||
.{ .int = true, .rcx = true },
|
||||
.{ .int = true, .rdx = true },
|
||||
.empty,
|
||||
.empty,
|
||||
.empty,
|
||||
.empty,
|
||||
.empty,
|
||||
.{ .r8 = true },
|
||||
.{ .r9 = true },
|
||||
.{ .r10 = true },
|
||||
.{ .r11 = true },
|
||||
.empty,
|
||||
.empty,
|
||||
.empty,
|
||||
.empty,
|
||||
.{ .float = true, .xmm0 = true },
|
||||
.{ .float = true, .xmm1 = true },
|
||||
.{ .float = true, .xmm2 = true },
|
||||
.{ .float = true, .xmm3 = true },
|
||||
.{ .float = true, .xmm4 = true },
|
||||
.{ .float = true, .xmm5 = true },
|
||||
.{ .xmm6 = true },
|
||||
.{ .xmm7 = true },
|
||||
.{ .st0 = true },
|
||||
};
|
||||
|
||||
func_sub_sp_offset: u64,
|
||||
func_ret_seb: i32,
|
||||
|
||||
pub fn g(gen: *Gen, elf: *Elf, c: u8) void {
|
||||
if (gen.nocode_wanted > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ind1 = gen.ind + 1;
|
||||
if (ind1 > elf.cur_text_section.data.len) {
|
||||
elf.cur_text_section.realloc(ind1);
|
||||
}
|
||||
elf.cur_text_section.data[gen.ind] = c;
|
||||
gen.ind = ind1;
|
||||
}
|
||||
|
||||
pub fn o(gen: *Gen, elf: *Elf, c: u32) void {
|
||||
while (c > 0) {
|
||||
g(gen, elf, @truncate(c));
|
||||
c >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genLE16(gen: *Gen, elf: *Elf, v: u16) void {
|
||||
g(gen, elf, @truncate(v));
|
||||
g(gen, elf, @truncate(v >> 8));
|
||||
}
|
||||
|
||||
pub fn genLE32(gen: *Gen, elf: *Elf, v: u32) void {
|
||||
g(gen, elf, @truncate(v));
|
||||
g(gen, elf, @truncate(v >> 8));
|
||||
g(gen, elf, @truncate(v >> 16));
|
||||
g(gen, elf, @truncate(v >> 24));
|
||||
}
|
||||
|
||||
pub fn genLE64(gen: *Gen, elf: *Elf, v: u64) void {
|
||||
g(gen, elf, @truncate(v));
|
||||
g(gen, elf, @truncate(v >> 8));
|
||||
g(gen, elf, @truncate(v >> 16));
|
||||
g(gen, elf, @truncate(v >> 24));
|
||||
g(gen, elf, @truncate(v >> 32));
|
||||
g(gen, elf, @truncate(v >> 40));
|
||||
g(gen, elf, @truncate(v >> 48));
|
||||
g(gen, elf, @truncate(v >> 56));
|
||||
}
|
||||
|
||||
pub fn orex(gen: *Gen, elf: *Elf, ll: u8, _r: SValue.Register, _r2: SValue.Register, b: u32) void {
|
||||
const r: u8 = if (_r.location.isRegister()) _r.location.value else 0;
|
||||
const r2: u8 = if (_r2.location.isRegister()) _r2.location.value else 0;
|
||||
if (ll > 0 or rexBase(r) > 0 or rexBase(r2) > 0) {
|
||||
o(gen, elf, 0x40 | rexBase(r) | (rexBase(r2) << 2) | (ll << 3));
|
||||
}
|
||||
o(b);
|
||||
}
|
||||
|
||||
/// Output a symbol and patch all calls to it.
|
||||
pub fn gsymAddr(elf: *Elf, _t: u32, a: u32) void {
|
||||
var t = _t;
|
||||
while (t > 0) {
|
||||
const ptr = (elf.cur_text_section.data.ptr + t)[0..4];
|
||||
const n = std.mem.readInt(u32, ptr, .little);
|
||||
std.mem.writeInt(u32, ptr, a - t - 4);
|
||||
t = n;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gsym(gen: *Gen, elf: *Elf, t: u32) void {
|
||||
gsymAddr(elf, t, gen.ind);
|
||||
}
|
||||
|
||||
pub fn is64Type(t: CType.Type) bool {
|
||||
return t.basic_type == .ptr or t.basic_type == .func or t.basic_type == .llong;
|
||||
}
|
||||
|
||||
/// Instruction + 4 bytes of data. Return the address of the data. */
|
||||
pub fn oad(gen: *Gen, elf: *Elf, c: u32, s: u32) u32 {
|
||||
if (gen.nocode_wanted) {
|
||||
return s;
|
||||
}
|
||||
|
||||
o(gen, elf, c);
|
||||
const t = gen.ind;
|
||||
genLE32(gen, elf, s);
|
||||
return t;
|
||||
}
|
||||
|
||||
/// Generate jmp to a label.
|
||||
pub inline fn gjmp2(gen: *Gen, elf: *Elf, instr: u32, lbl: u32) void {
|
||||
oad(gen, elf, instr, lbl);
|
||||
}
|
||||
|
||||
pub fn genAddr32(gen: *Gen, elf: *Elf, r: SValue.Register, sym: ?*Sym, _c: u32) void {
|
||||
var c = _c;
|
||||
if (r.flags.sym) {
|
||||
gen.greloca(elf, elf.cur_text_section, sym, gen.ind, Elf.R_X86_64_32S, c);
|
||||
c = 0;
|
||||
}
|
||||
genLE32(gen, elf, c);
|
||||
}
|
||||
|
||||
pub fn genAddr64(gen: *Gen, elf: *Elf, r: SValue.Register, sym: ?*Sym, _c: u64) void {
|
||||
var c = _c;
|
||||
if (r.flags.sym) {
|
||||
gen.greloca(elf, elf.cur_text_section, sym, gen.ind, Elf.R_X86_64_64, c);
|
||||
c = 0;
|
||||
}
|
||||
genLE64(gen, elf, c);
|
||||
}
|
||||
|
||||
pub fn genAddrPC32(gen: *Gen, elf: *Elf, r: SValue.Register, sym: ?*Sym, _c: u32) void {
|
||||
var c = _c;
|
||||
if (r.flags.sym) {
|
||||
gen.greloca(elf, elf.cur_text_section, sym, gen.ind, Elf.R_X86_64_PC32, c - 4);
|
||||
c = 4;
|
||||
}
|
||||
genLE32(gen, elf, c - 4);
|
||||
}
|
||||
|
||||
pub fn genGotPCRel(gen: *Gen, elf: *Elf, r: SValue.Register, sym: ?*Sym, c: u32) void {
|
||||
gen.greloca(elf, elf.cur_text_section, sym, gen.ind, Elf.R_X86_64_GOTPCREL, -4);
|
||||
genLE32(gen, elf, 0);
|
||||
if (c > 0) {
|
||||
orex(gen, elf, 1, r, .{}, 0x81);
|
||||
o(0xC0 + regValue(r.location.value));
|
||||
genLE32(gen, elf, c);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genModRMImpl(gen: *Gen, elf: *Elf, _op_reg: u8, r: SValue.Register, sym: ?*Sym, c: u32, is_got: bool) void {
|
||||
const op_reg = regValue(_op_reg) << 3;
|
||||
if (r.location == .@"const") {
|
||||
// constant memory reference
|
||||
if (!r.flags.sym) {
|
||||
o(gen, elf, 0x04 | op_reg); // [sib] | destreg
|
||||
_ = oad(gen, elf, 0x25, c); // disp32
|
||||
} else {
|
||||
o(0x05 | op_reg); // (%rip)+disp32 | destreg
|
||||
if (is_got) {
|
||||
genGotPCRel(gen, elf, r, sym, c);
|
||||
} else {
|
||||
genAddrPC32(gen, elf, r, sym, c);
|
||||
}
|
||||
}
|
||||
} else if (r.location == .local) {
|
||||
const c_byte: u8 = @truncate(c);
|
||||
if (@as(i32, @bitCast(c)) == @as(i32, @as(i8, @bitCast(c_byte)))) {
|
||||
// short reference
|
||||
o(gen, elf, 0x45 | op_reg);
|
||||
g(gen, elf, c_byte);
|
||||
} else {
|
||||
oad(gen, elf, 0x85 | op_reg, c);
|
||||
}
|
||||
} else if (Register.fromInt(r.location.value).mem) {
|
||||
if (c > 0) {
|
||||
g(gen, elf, 0x80 | op_reg | regValue(r.location.value));
|
||||
genLE32(gen, elf, c);
|
||||
} else {
|
||||
g(gen, elf, 0x00 | op_reg | regValue(r.location.value));
|
||||
}
|
||||
} else {
|
||||
g(gen, elf, 0x00 | op_reg | regValue(r.location.value));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genModRM(gen: *Gen, elf: *Elf, op_reg: u8, r: SValue.Register, sym: ?*Sym, c: u32) void {
|
||||
genModRMImpl(gen, elf, op_reg, r, sym, c, false);
|
||||
}
|
||||
|
||||
pub fn genModRM64(gen: *Gen, elf: *Elf, opcode: u32, op_reg: u8, r: SValue.Register, sym: ?*Sym, c: u32) void {
|
||||
const is_got = (op_reg & @intFromEnum(Register.mem)) != 0 and !sym.?.type.t.static;
|
||||
orex(gen, elf, 1, r, op_reg, opcode);
|
||||
genModRMImpl(gen, elf, op_reg, r, sym, c, is_got);
|
||||
}
|
||||
|
||||
pub fn load(r: SValue.Register, sv: *SValue) void {
|
||||
var fr = sv.r;
|
||||
var ft = sv.type.t;
|
||||
var fc: u32 = @truncate(sv.c.i);
|
||||
|
||||
if (fc != sv.c.i and fr.flags.sym) {
|
||||
tcc.err("64-bit addend in load", .{});
|
||||
}
|
||||
|
||||
ft.defsign = false;
|
||||
ft.@"volatile" = false;
|
||||
ft.constant = false;
|
||||
|
||||
if (fr.location == .@"const" and fr.flags.sym and fr.flags.lval and !sv.sym.?.type.t.static) {
|
||||
var tr = r;
|
||||
tr.location.value |= Register.mem_mask;
|
||||
if (ft.isFloat()) {
|
||||
tr = get_reg(.int);
|
||||
tr.location.value |= Register.mem_mask;
|
||||
}
|
||||
genModRM64(gen, elf, 0x8b, tr, fr, sv.sym, 0);
|
||||
|
||||
fr = tr;
|
||||
fr.flags.lval = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user