From 1d6980cf22ac45c513e7baf97a84a3f6be06ab70 Mon Sep 17 00:00:00 2001 From: Xaver Fabian Date: Wed, 18 Feb 2026 15:01:17 +0100 Subject: [PATCH] Extended the parser to handle endbr isntructions. Furthermore, call and return instructions will now additonally generate a callstart and retstart instruction that we use to identify calls and returns. Last, support for quad directive was added and special handling was implemented. This is used for jump table implementations to get the correctly mapped addresses from them. --- src/gas_parser.pl | 5 +++-- src/x86_table.pl | 3 +++ src/x86_to_muasm.pl | 23 +++++++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/gas_parser.pl b/src/gas_parser.pl index 41a75c7..1f017b5 100644 --- a/src/gas_parser.pl +++ b/src/gas_parser.pl @@ -196,7 +196,8 @@ process_directive('.asciz', direc(cons, String)). process_directive('.ascii', direc(cons, String)) --> blanks, string(String), ignore_rest. - +process_directive('.quad', direc(init, label(Name))) --> blanks, idcodes(Cs), { atom_codes(Name, Cs) }, ignore_rest, !. +% Its not a label. its an identifier to a label similar to instruction % TODO: how to process? process_directive('.bss', '#') --> ignore_rest. process_directive('.data', '#') --> ignore_rest. @@ -223,7 +224,7 @@ skip_directive('.cfi_def_cfa'). skip_directive('.cfi_def_cfa_offset'). skip_directive('.cfi_def_cfa_register'). -skip_directive('.quad'). +%skip_directive('.quad'). skip_directive('.local'). skip_directive('.uleb128'). % TODO: Generate number unsigned skip_directive('.sleb128'). % TODO: Generate signed number diff --git a/src/x86_table.pl b/src/x86_table.pl index 0d0a378..3d00a6d 100644 --- a/src/x86_table.pl +++ b/src/x86_table.pl @@ -25,6 +25,9 @@ ins(lfence, o, 0, spbarr). ins(mfence, o, 0, spbarr). % TODO: Different memory fence ? ins(sfence, o, 0, spbarr). % TODO: Different store fence ? +% Intel CET endbr32 and endbr64 instructions +ins(endbr32, o, 0, endbr). +ins(endbr64, o, 0, endbr). ins(leave, o, 0, leave). ins(clflush, o, 0, clflush). % ins(bt, o, 2, skip). % TODO: Set the carry flag to the select bit (2 operands) diff --git a/src/x86_to_muasm.pl b/src/x86_to_muasm.pl index 2edd90b..01f5093 100644 --- a/src/x86_to_muasm.pl +++ b/src/x86_to_muasm.pl @@ -84,6 +84,16 @@ ( Ign = true -> H = H1, M1 = M0 % TODO: wrong! ; fill_mem([N], InitMem, H1, H, M1, M0) ). +% If labels are written to memory. Happens for example for a jump table +% Set_mem is used because load(ax,8+jump_table). Notice the idx into the table is 8. Next would be 16. If we use +% fill_mem without specifying where to start, there would be a mismatch. So we just fill the whole memory for 8 bytes +% Since this is generated from quads directive this should generally be fine +emit_(direc(init, label(Id)), Xs, Dic, (Name, Ign), IgnNames, InitMem, (H0, H1, H2), memlocs(M0,A), MemLocs) := + ~emit(Xs, Dic, (Name, Ign), IgnNames, InitMem, (H0 ,H, H2), memlocs(M1,A), MemLocs) :- !, + ( Ign = true -> H = H1, M1 = M0 % TODO: wrong! + ; set_mem(8, Id, InitMem, H1, H, M1, M0)%, fill_mem([Id], InitMem, H1, H, M1, M0) + ). + emit_(direc(cons, Values), Xs, Dic, (Name, Ign), IgnNames, InitMem, (H0, H1, H2), memlocs(M0, A), MemLocs) := ~emit(Xs, Dic, (Name, Ign), IgnNames, InitMem, (H0, H, H2), memlocs(M1, A), MemLocs) :- !, ( Ign = true -> H = H1, M1 = M0 % TODO: wrong! @@ -106,6 +116,9 @@ % Translate one instruction (or label) tr_ins(symbol(N)) := symbol(N). +% For a label in memory +tr_ins(direc(init, label(Label0))) := R :- !, R = [lookup_label(Label0, Label), direc(init, label(Label))], + assertz_fact(label(Label0)). tr_ins(direc(A, N)) := direc(A, N). tr_ins(symbol_direc(A, N)) := symbol_direc(A, N). tr_ins(label_ins(Label0,Ins_x86)) := R :- !, R = ~append(~tr_ins(label(Label0)), ~tr_ins(Ins_x86)). @@ -244,11 +257,11 @@ tr_in([A],[A1],R,R0), R0 = [load(A1, sp/\ (~spmask)), (sp<-sp+8)]. % Return from call -tr_ins_(ret, [void]) := R :- !, R = [~tr_ins_(pop, [tmp]), jmp(tmp)]. -tr_ins_(ret, [0]) := R :- !, R = [~tr_ins_(pop, [tmp]), jmp(tmp)]. -tr_ins_(ret, []) := R :- !, R = [~tr_ins_(pop, [tmp]), jmp(tmp)]. +tr_ins_(ret, [void]) := R :- !, R = [retstart, ~tr_ins_(pop, [tmp]), jmp(tmp)]. +tr_ins_(ret, [0]) := R :- !, R = [retstart, ~tr_ins_(pop, [tmp]), jmp(tmp)]. +tr_ins_(ret, []) := R :- !, R = [retstart, ~tr_ins_(pop, [tmp]), jmp(tmp)]. % Do a call % TODO: Support if a register is given, by jumping to the number that it points to -tr_ins_(call, [A]) := R :- !, R = [~tr_ins_(push, [pc+2]), ~tr_ins_(jmp, [A])]. +tr_ins_(call, [A]) := R :- !, R = [callstart, ~tr_ins_(push, [pc+2]), ~tr_ins_(jmp, [A])]. % Restore stack pointer from BP and pop BP tr_ins_(leave, []) := R :- !, R = [(sp <- bp), ~tr_ins_(pop, [bp])]. % @@ -258,6 +271,8 @@ tr_ins_(skip, []) := skip :- !. % Speculative barrier tr_ins_(spbarr, []) := spbarr :- !. +% Endbranch instruction +tr_ins_(endbr, []) := endbr :- !. % Stop tr_ins_(stop_ins, []) := stop_ins :- !. % Jump (to a register or label)