parsing mem operand
This commit is contained in:
parent
9228b7949b
commit
f87ab3afa4
|
|
@ -613,6 +613,28 @@ is_digit:
|
||||||
setb al
|
setb al
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
;; converts char $dil to a digit with radix $rsi, returning it in $edx. $al is set to 1 if the char is a valid digit, and 0 otherwise.
|
||||||
|
to_digit:
|
||||||
|
lea eax, [rsi - 2]
|
||||||
|
cmp eax, 35
|
||||||
|
jae .invalid
|
||||||
|
movzx rdi, dil
|
||||||
|
lea edx, [rdi - 65] ; 'A' = 65
|
||||||
|
and edx, -33 ; convert to uppercase
|
||||||
|
add edx, 10 ; 'A' should map to 10
|
||||||
|
lea eax, [rdi - 48] ; '0' = 48
|
||||||
|
cmp esi, 11
|
||||||
|
cmovb edx, eax ; if radix <= 10, then take the difference from '0'
|
||||||
|
cmp edi, 58
|
||||||
|
cmovb edx, eax ; or if char < '9', then take the difference from '0'
|
||||||
|
xor eax, eax
|
||||||
|
cmp edx, esi
|
||||||
|
setb al ; al = edx < radix
|
||||||
|
ret
|
||||||
|
.invalid:
|
||||||
|
xor eax, eax
|
||||||
|
ret
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
mov rax, 60
|
mov rax, 60
|
||||||
syscall
|
syscall
|
||||||
|
|
@ -628,10 +650,9 @@ exit:
|
||||||
struc operand
|
struc operand
|
||||||
.type resd 1
|
.type resd 1
|
||||||
.size resd 1
|
.size resd 1
|
||||||
.reg resb 1
|
.reg resq 1
|
||||||
.index resb 1
|
.index resq 1
|
||||||
.scale resb 1
|
.scale resd 1
|
||||||
.pad resb 1
|
|
||||||
.disp resd 1
|
.disp resd 1
|
||||||
endstruc
|
endstruc
|
||||||
|
|
||||||
|
|
@ -649,10 +670,13 @@ try_parse_reg:
|
||||||
push rbx ; buf
|
push rbx ; buf
|
||||||
push r12 ; reg_num
|
push r12 ; reg_num
|
||||||
push r13 ; size
|
push r13 ; size
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
|
||||||
xor r12d, r12d
|
xor r12d, r12d
|
||||||
xor r13d, r13d
|
xor r13d, r13d
|
||||||
|
|
||||||
lea rbx, [rel buf]
|
mov rbx, rdi
|
||||||
mov dil, byte [rbx]
|
mov dil, byte [rbx]
|
||||||
call is_alpha
|
call is_alpha
|
||||||
jnb .done
|
jnb .done
|
||||||
|
|
@ -723,8 +747,8 @@ try_parse_reg:
|
||||||
|
|
||||||
.done:
|
.done:
|
||||||
mov rax, rbx
|
mov rax, rbx
|
||||||
lea rbx, [rel buf]
|
pop rdi
|
||||||
sub rax, rbx ; number of bytes consumed
|
sub rax, rdi ; number of bytes consumed
|
||||||
|
|
||||||
movzx rdx, r12d ; reg_num
|
movzx rdx, r12d ; reg_num
|
||||||
shl rdx, 32
|
shl rdx, 32
|
||||||
|
|
@ -755,6 +779,253 @@ try_parse_reg:
|
||||||
sub r13d, eax
|
sub r13d, eax
|
||||||
jmp .r_or_e
|
jmp .r_or_e
|
||||||
|
|
||||||
|
try_parse_num:
|
||||||
|
push rbx ; buf
|
||||||
|
push r12 ; radix
|
||||||
|
push r13 ; acc
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
|
||||||
|
mov r12, 10
|
||||||
|
xor r13d, r13d
|
||||||
|
xor eax, eax
|
||||||
|
mov rbx, rdi
|
||||||
|
|
||||||
|
; eat leading - and flip sign
|
||||||
|
cmp byte [rbx], '-'
|
||||||
|
sete al
|
||||||
|
sub r13, rax
|
||||||
|
lea rbx, [rbx + rax]
|
||||||
|
|
||||||
|
; eat any leading +
|
||||||
|
cmp byte [rbx], '+'
|
||||||
|
sete al
|
||||||
|
lea rbx, [rbx + rax]
|
||||||
|
|
||||||
|
mov dil, byte [rbx]
|
||||||
|
call is_digit
|
||||||
|
jnb .not_num
|
||||||
|
|
||||||
|
cmp dil, '0'
|
||||||
|
jne .loop
|
||||||
|
inc rbx
|
||||||
|
mov dil, byte [rbx]
|
||||||
|
and dil, 0xdf ; convert to uppercase
|
||||||
|
cmp dil, 'X'
|
||||||
|
sete al
|
||||||
|
lea ecx, [eax + eax * 2]
|
||||||
|
shl ecx, 1
|
||||||
|
add r12d, ecx
|
||||||
|
cmp dil, 'O'
|
||||||
|
sete al
|
||||||
|
shl al, 1
|
||||||
|
sub r12d, eax
|
||||||
|
cmp dil, 'B'
|
||||||
|
sete al
|
||||||
|
shl al, 3
|
||||||
|
sub r12d, eax
|
||||||
|
|
||||||
|
cmp r12d, 10
|
||||||
|
setne al
|
||||||
|
lea rbx, [rbx + rax]
|
||||||
|
|
||||||
|
.loop:
|
||||||
|
mov dil, byte [rbx]
|
||||||
|
test dil, dil
|
||||||
|
jz .done
|
||||||
|
|
||||||
|
mov esi, r12d
|
||||||
|
call to_digit
|
||||||
|
mov ecx, edx
|
||||||
|
test al, al
|
||||||
|
jz .done
|
||||||
|
mov rax, r13
|
||||||
|
imul r12
|
||||||
|
add rax, rcx
|
||||||
|
mov r13, rax
|
||||||
|
inc rbx
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.done:
|
||||||
|
mov rax, rbx
|
||||||
|
pop rdi
|
||||||
|
sub rax, rdi ; number of bytes consumed
|
||||||
|
mov rdx, r13 ; acc
|
||||||
|
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.not_num:
|
||||||
|
xor rax, rax
|
||||||
|
xor rdx, rdx
|
||||||
|
pop rdi
|
||||||
|
pop r13
|
||||||
|
pop r12
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
skip_whitespace_rbx:
|
||||||
|
mov al, byte [rbx]
|
||||||
|
cmp al, ' '
|
||||||
|
ja .done
|
||||||
|
inc rbx
|
||||||
|
jmp skip_whitespace_rbx
|
||||||
|
.done:
|
||||||
|
ret
|
||||||
|
|
||||||
|
global try_parse_mem
|
||||||
|
try_parse_mem:
|
||||||
|
push rbx ; buf
|
||||||
|
push r12 ; size
|
||||||
|
push rdi
|
||||||
|
|
||||||
|
mov rbx, rdi ; buf ptr
|
||||||
|
mov r12, rsi ; output operand ptr
|
||||||
|
|
||||||
|
mov dword [r12 + operand.type], KIND_MEM
|
||||||
|
mov dword [r12 + operand.size], 0
|
||||||
|
mov qword [r12 + operand.reg], -1
|
||||||
|
mov qword [r12 + operand.index], -1
|
||||||
|
mov dword [r12 + operand.scale], 0
|
||||||
|
mov dword [r12 + operand.disp], 0
|
||||||
|
|
||||||
|
mov edi, dword [rbx]
|
||||||
|
|
||||||
|
cmp dil, '['
|
||||||
|
je .bracket
|
||||||
|
|
||||||
|
lea rbx, [rbx + 4]
|
||||||
|
|
||||||
|
cmp edi, 'byte'
|
||||||
|
je .bracket
|
||||||
|
|
||||||
|
mov dword [r12 + operand.size], 1 ; 16-bit
|
||||||
|
cmp edi, 'word'
|
||||||
|
je .bracket
|
||||||
|
|
||||||
|
lea rbx, [rbx - 4]
|
||||||
|
mov dl, byte [rbx]
|
||||||
|
inc rbx
|
||||||
|
mov edi, dword [rbx]
|
||||||
|
|
||||||
|
xor eax, eax
|
||||||
|
mov dword [r12 + operand.size], 2 ; 16-bit
|
||||||
|
cmp dl, 'q'
|
||||||
|
sete al
|
||||||
|
cmp dl, 'd'
|
||||||
|
sete dl
|
||||||
|
or al, dl
|
||||||
|
jz .not_mem
|
||||||
|
add dword [r12 + operand.size], eax ; 32-bit?
|
||||||
|
|
||||||
|
cmp edi, 'word'
|
||||||
|
jne .not_mem
|
||||||
|
lea rbx, [rbx + 4]
|
||||||
|
|
||||||
|
.bracket:
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
mov dl, byte [rbx]
|
||||||
|
cmp dl, '['
|
||||||
|
jne .not_mem
|
||||||
|
inc rbx
|
||||||
|
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
mov rdi, rbx
|
||||||
|
call try_parse_reg
|
||||||
|
add rbx, rax
|
||||||
|
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
cmp byte [rbx], '*'
|
||||||
|
jne .base
|
||||||
|
mov qword [r12 + operand.index], rdx
|
||||||
|
|
||||||
|
.scale:
|
||||||
|
inc rbx
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
mov dil, byte [rbx]
|
||||||
|
mov esi, 10
|
||||||
|
call to_digit
|
||||||
|
mov dword [r12 + operand.scale], edx
|
||||||
|
add rbx, rax
|
||||||
|
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
mov dil, byte [rbx]
|
||||||
|
cmp dil, ']'
|
||||||
|
je .done
|
||||||
|
|
||||||
|
|
||||||
|
; TODO: allow for label as displacement
|
||||||
|
.disp:
|
||||||
|
sub dil, `,`
|
||||||
|
neg dil ; sign
|
||||||
|
mov al, dil
|
||||||
|
inc al
|
||||||
|
test al, -3
|
||||||
|
jne .not_mem
|
||||||
|
movsx edi, dil
|
||||||
|
mov dword [r12 + operand.disp], edi
|
||||||
|
|
||||||
|
inc rbx
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
mov rdi, rbx
|
||||||
|
call try_parse_num
|
||||||
|
test eax, eax
|
||||||
|
jz .not_mem
|
||||||
|
add rbx, rax
|
||||||
|
mov eax, dword [r12 + operand.disp]
|
||||||
|
imul edx
|
||||||
|
mov dword [r12 + operand.disp], eax
|
||||||
|
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
cmp byte [rbx], ']'
|
||||||
|
je .done
|
||||||
|
jmp .not_mem
|
||||||
|
|
||||||
|
.base:
|
||||||
|
mov qword [r12 + operand.reg], rdx
|
||||||
|
cmp byte [rbx], ']'
|
||||||
|
je .done
|
||||||
|
cmp byte [rbx], '+'
|
||||||
|
jne .not_mem
|
||||||
|
inc rbx
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
|
||||||
|
mov rdi, rbx
|
||||||
|
call try_parse_reg
|
||||||
|
test eax, eax
|
||||||
|
jz .disp
|
||||||
|
add rbx, rax
|
||||||
|
mov qword [r12 + operand.index], rdx
|
||||||
|
|
||||||
|
call skip_whitespace_rbx
|
||||||
|
cmp byte [rbx], '*'
|
||||||
|
je .scale
|
||||||
|
cmp byte [rbx], '+'
|
||||||
|
je .disp
|
||||||
|
cmp byte [rbx], ']'
|
||||||
|
jne .not_mem
|
||||||
|
|
||||||
|
.done:
|
||||||
|
inc rbx
|
||||||
|
mov rax, rbx
|
||||||
|
pop rdi
|
||||||
|
sub rax, rdi ; number of bytes consumed
|
||||||
|
mov rdx, r12 ; output operand ptr
|
||||||
|
|
||||||
|
pop r12
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.not_mem:
|
||||||
|
xor rax, rax
|
||||||
|
pop rdi
|
||||||
|
pop r12
|
||||||
|
pop rbx
|
||||||
|
ret
|
||||||
|
|
||||||
|
|
||||||
global _entry_print_table
|
global _entry_print_table
|
||||||
_entry_print_table:
|
_entry_print_table:
|
||||||
call print_op_table
|
call print_op_table
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ unsafe extern "C" {
|
||||||
// unsafe fn parse_gpr(src: *mut Source, prefix: u8) -> (u64, u64);
|
// unsafe fn parse_gpr(src: *mut Source, prefix: u8) -> (u64, u64);
|
||||||
// unsafe fn parse_reg(src: *mut Source) -> (u64, u64);
|
// unsafe fn parse_reg(src: *mut Source) -> (u64, u64);
|
||||||
|
|
||||||
unsafe fn try_parse_reg() -> (usize, Register);
|
unsafe fn try_parse_reg(_: *const u8) -> (usize, Register);
|
||||||
|
unsafe fn try_parse_mem(_: *const u8, _: *mut Operand) -> (usize, *const Operand);
|
||||||
|
|
||||||
#[link_name = "buf"]
|
#[link_name = "buf"]
|
||||||
static mut BUF: [u8; 0x100];
|
static mut BUF: [u8; 0x100];
|
||||||
|
|
@ -15,6 +16,17 @@ struct Register {
|
||||||
num: u32,
|
num: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Operand {
|
||||||
|
kind: u32,
|
||||||
|
size: u32,
|
||||||
|
reg: Register,
|
||||||
|
index: Register,
|
||||||
|
scale: u32,
|
||||||
|
disp: i32,
|
||||||
|
}
|
||||||
|
|
||||||
impl Register {
|
impl Register {
|
||||||
fn new(num: u32, size: u32) -> Self {
|
fn new(num: u32, size: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -22,11 +34,15 @@ impl Register {
|
||||||
size: size.ilog2(),
|
size: size.ilog2(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn invalid() -> Self {
|
||||||
|
Self { num: !0, size: !0 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
|
||||||
fn write_to_buf(b: &[u8]) {
|
fn write_to_buf(b: &[u8]) {
|
||||||
assert!(b.len() <= 0x100, "Buffer overflow");
|
assert!(b.len() <= 0x100, "Buffer overflow");
|
||||||
|
|
@ -36,6 +52,61 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn parse_mem() {
|
||||||
|
let mut op = MaybeUninit::<Operand>::uninit();
|
||||||
|
// let (n, _) =
|
||||||
|
// unsafe { try_parse_mem(b"qword [rax + rbx * 2 + 0x10]\0".as_ptr(), op.as_mut_ptr()) };
|
||||||
|
// assert_eq!(
|
||||||
|
// (n, unsafe { op.assume_init_ref() }),
|
||||||
|
// (
|
||||||
|
// 28,
|
||||||
|
// &Operand {
|
||||||
|
// kind: 2,
|
||||||
|
// size: 3,
|
||||||
|
// reg: Register::new(0, 8),
|
||||||
|
// index: Register::new(3, 8),
|
||||||
|
// scale: 2,
|
||||||
|
// disp: 0x10,
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// );
|
||||||
|
|
||||||
|
let (n, _) =
|
||||||
|
unsafe { try_parse_mem(b"byte [r12 + r13 * 4 - 0x20]\0".as_ptr(), op.as_mut_ptr()) };
|
||||||
|
assert_eq!(
|
||||||
|
(n, unsafe { op.assume_init_ref() }),
|
||||||
|
(
|
||||||
|
27,
|
||||||
|
&Operand {
|
||||||
|
kind: 2,
|
||||||
|
size: 0,
|
||||||
|
reg: Register::new(12, 8),
|
||||||
|
index: Register::new(13, 8),
|
||||||
|
scale: 4,
|
||||||
|
disp: -0x20,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
let (n, _) = unsafe { try_parse_mem(b"word [r8 * 8 + 5]\0".as_ptr(), op.as_mut_ptr()) };
|
||||||
|
assert_eq!(
|
||||||
|
(n, unsafe { op.assume_init_ref() }),
|
||||||
|
(
|
||||||
|
17,
|
||||||
|
&Operand {
|
||||||
|
kind: 2,
|
||||||
|
size: 1,
|
||||||
|
reg: Register::invalid(),
|
||||||
|
index: Register::new(8, 8),
|
||||||
|
scale: 8,
|
||||||
|
disp: 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
fn parse_reg() {
|
fn parse_reg() {
|
||||||
let cases = [
|
let cases = [
|
||||||
(&b"rax"[..], (0, 8)),
|
(&b"rax"[..], (0, 8)),
|
||||||
|
|
@ -106,8 +177,7 @@ mod tests {
|
||||||
];
|
];
|
||||||
|
|
||||||
for (text, (reg, size)) in cases {
|
for (text, (reg, size)) in cases {
|
||||||
write_to_buf(text);
|
let (n, result) = unsafe { try_parse_reg(text.as_ptr()) };
|
||||||
let (n, result) = unsafe { try_parse_reg() };
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
result,
|
result,
|
||||||
Register::new(reg, size),
|
Register::new(reg, size),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue