dangerous: resize width field on Operand

This commit is contained in:
janis 2025-11-02 17:27:30 +01:00
parent 6dff42cfa5
commit d46837903b
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
2 changed files with 79 additions and 63 deletions

View file

@ -213,11 +213,11 @@ codegen_arg_to_operand:
xor rax, rax xor rax, rax
mov eax, 0 ; Operand.len = 0 mov eax, 0 ; Operand.len = 0
shl eax, 16 shl eax, 16
or eax, 8 ; Operand.width = 8 or eax, 8 ; Operand.width = 8
shl eax, 4
or eax, edi ; Operand.register
shl eax, 8 shl eax, 8
or eax, OPERAND_REGISTER ; Operand.kind or eax, edi ; Operand.register
shl eax, 8
or eax, OPERAND_REGISTER ; Operand.kind
mov rdx, 0 ; Operand.value = 0 mov rdx, 0 ; Operand.value = 0
jmp .epilogue jmp .epilogue
@ -233,8 +233,8 @@ codegen_arg_to_operand:
xor rax, rax xor rax, rax
mov eax, 0 ; Operand.len = 0 mov eax, 0 ; Operand.len = 0
shl eax, 16 shl eax, 16
or eax, 8 ; Operand.width = 8 or eax, 8 ; Operand.width = 8
shl eax, 4 shl eax, 8
; or eax, 0 ; Operand.register = undef ; or eax, 0 ; Operand.register = undef
shl eax, 8 shl eax, 8
or eax, OPERAND_RBP_OFFSET ; Operand.kind or eax, OPERAND_RBP_OFFSET ; Operand.kind
@ -352,7 +352,7 @@ codegen_allocate_place:
mov eax, 0 ; Operand.len = 0 mov eax, 0 ; Operand.len = 0
shl eax, 16 shl eax, 16
or eax, esi ; Operand.width or eax, esi ; Operand.width
shl eax, 4 shl eax, 8
; or eax, 0 ; Operand.register = undef ; or eax, 0 ; Operand.register = undef
shl eax, 8 shl eax, 8
or eax, OPERAND_RBP_OFFSET ; Operand.kind or eax, OPERAND_RBP_OFFSET ; Operand.kind
@ -393,7 +393,7 @@ codegen_allocate_value:
shl eax, 16 shl eax, 16
mov rsi, [rsp + 8] ; width mov rsi, [rsp + 8] ; width
or eax, esi ; Operand.width or eax, esi ; Operand.width
shl eax, 4 shl eax, 8
or eax, ebx ; Operand.register or eax, ebx ; Operand.register
shl eax, 8 shl eax, 8
or eax, OPERAND_REGISTER ; Operand.kind or eax, OPERAND_REGISTER ; Operand.kind
@ -435,17 +435,13 @@ codegen_free_operand:
cmp rbx, rax cmp rbx, rax
jne .done ; operand not at top of stack, can't free jne .done ; operand not at top of stack, can't free
mov al, byte [rsi + 1] ; Operand.width movzx rax, word [rsi + 2] ; Operand.width
shr al, 4
movzx rax, al
sub rbx, rax sub rbx, rax
mov dword [rdi + 0], ebx ; current_stack_size -= width mov dword [rdi + 0], ebx ; current_stack_size -= width
jmp .done jmp .done
.free_reg: .free_reg:
xor rax, rax movzx rax, byte [rsi + 1] ; Operand.register
mov al, byte [rsi + 1] ; Operand.register_and_width
and al, 0x0F ; get register index
mov bx, word [rdi + 48] ; register_bitset mov bx, word [rdi + 48] ; register_bitset
btr bx, ax btr bx, ax
jnc .panic ; trying to free unallocated register jnc .panic ; trying to free unallocated register
@ -1055,14 +1051,7 @@ codegen_expr:
call vec_extend call vec_extend
; construct return operand ; construct return operand
; Operand { kind: REGISTER, register_and_width: (register | (width << 4)), len: 0, value: 0 } mov rax, [rel OPERAND_RAX]
mov eax, 0 ; len = 0
shl eax, 16
or eax, 8 ; width = 8
shl eax, 4
or eax, 0 ; register = rax
shl eax, 8
or eax, OPERAND_REGISTER ; kind
mov rdx, 0 ; value = 0 mov rdx, 0 ; value = 0
jmp .done jmp .done
@ -1071,10 +1060,9 @@ codegen_expr:
mov [rsp + 16], rax ; scratch = *AstNode mov [rsp + 16], rax ; scratch = *AstNode
mov byte [rsp + 32], OPERAND_IMMEDIATE ; Operand.kind mov byte [rsp + 32], OPERAND_IMMEDIATE ; Operand.kind
mov bl, 8 ; width = 8 mov byte [rsp + 33], 0 ; Operand.register = undef
shl bl, 4 ; register = undef mov word [rsp + 34], 8 ; Operand.width = 8
mov byte [rsp + 33], bl ; Operand.register_and_width mov word [rsp + 36], 0 ; Operand.len = 0
mov word [rsp + 34], 0 ; Operand.len = 0
mov rbx, [rax + 8] ; AstNode.data mov rbx, [rax + 8] ; AstNode.data
mov [rsp + 40], rbx ; Operand.value mov [rsp + 40], rbx ; Operand.value
@ -1166,10 +1154,10 @@ codegen_expr:
lea rsi, [rsp + 48] ; right operand lea rsi, [rsp + 48] ; right operand
call codegen_free_operand call codegen_free_operand
mov rdx, [rsp + 48] ; right operand ; move scratch to rhs, but preserve width
and rdx, 0xF000 ; Operand.width movzx rdx, word [rsp + 48 + 2] ; rhs.width
mov word [rsp + 64 + 2], dx ; scratch.width
mov rax, [rsp + 64] ; scratch value mov rax, [rsp + 64] ; scratch value
or rax, rdx ; preserve width
mov rdx, [rsp + 72] mov rdx, [rsp + 72]
mov [rsp + 48], rax ; right operand mov [rsp + 48], rax ; right operand
mov [rsp + 56], rdx mov [rsp + 56], rdx
@ -1332,7 +1320,7 @@ codegen_expr:
call vec_get call vec_get
mov rdx, [rax + 8] ; offset mov rdx, [rax + 8] ; offset
neg rdx neg rdx
mov rax, qword [rel OPERAND_RBP_OFFSET] mov rax, qword [rel OPERAND_RBP]
mov [rsp + 16], rax mov [rsp + 16], rax
mov [rsp + 24], rdx mov [rsp + 24], rdx
@ -1372,7 +1360,8 @@ codegen_expr:
;; start-structs ;; start-structs
;; struct Operand { ;; struct Operand {
;; kind: u8 ;; kind: u8
;; register_and_width: u8, ;; register: u8,
;; width: u16,
;; len: u16, ;; len: u16,
;; value: u64, ;; value: u64,
;; } ;; }
@ -1387,12 +1376,22 @@ section .rdata
OPERAND_IMMEDIATE equ 5 ; e.g. 0x10 OPERAND_IMMEDIATE equ 5 ; e.g. 0x10
OPERAND_CONSTANT equ 6 ; e.g. OPERAND_CONSTANT OPERAND_CONSTANT equ 6 ; e.g. OPERAND_CONSTANT
OPERAND_LABEL equ 7 ; e.g. label_1234 OPERAND_LABEL equ 7 ; e.g. label_1234
OPERAND_REGISTER_PLACE equ 8 ; e.g. [rax]
OPERAND_RBP_PLACE equ 9 ; e.g. mov rax, [rbp - 8]; mov [rax], src
;; end-consts ;; end-consts
WIDTH_BYTE db 'byte ' WIDTH_BYTE db 'byte '
WIDTH_WORD db 'word ' WIDTH_WORD db 'word '
WIDTH_DWORD db 'dword ' WIDTH_DWORD db 'dword '
WIDTH_QWORD db 'qword ' WIDTH_QWORD db 'qword '
; Operand { kind: REGISTER, register: 0, width: 8, len: 0, padding: 0, value: 0 }
align 8
OPERAND_RAX dq 0x0008_0001, 0
align 8
OPERAND_RDX dq 0x0008_0301, 0
align 8
OPERAND_RBP dq 0x0008_0002, 0
section .text section .text
;; rdi: *text ;; rdi: *text
@ -1424,14 +1423,39 @@ codegen_write_operand:
je .constant je .constant
cmp bl, OPERAND_LABEL cmp bl, OPERAND_LABEL
je .label je .label
cmp bl, OPERAND_REGISTER_PLACE
je .reg_p
cmp bl, OPERAND_RBP_PLACE
je .rbp_offset
jmp .panic jmp .panic
.reg_p:
mov rbx, rsi
mov byte [rsp + 16], '['
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
call vec_push
movzx rdi, byte [rbx + 1] ; Operand.register
movzx rsi, word [rbx + 2] ; Operand.width
lea rdx, [rsp + 16] ; buffer
call get_register_name
mov rdi, [rsp] ; *text
mov rsi, rax ; buffer
call vec_extend
mov byte [rsp + 16], ']'
mov rdi, [rsp] ; *text
lea rsi, [rsp + 16]
call vec_push
.register: .register:
mov rbx, rsi mov rbx, rsi
mov rdi, [rbx + 1] ; register_and_width movzx rdi, byte [rbx + 1] ; Operand.register
mov rsi, rdi movzx rsi, word [rbx + 2] ; Operand.width
and dil, 0x0F ; low 4 bits = register
shr rsi, 4 ; high 4 bits = width
lea rdx, [rsp + 16] ; buffer lea rdx, [rsp + 16] ; buffer
call get_register_name call get_register_name
@ -1444,8 +1468,7 @@ codegen_write_operand:
.rsp_offset: .rsp_offset:
; {width} [rbp {+/-} offset] ; {width} [rbp {+/-} offset]
mov rsi, [rsp + 8] ; op mov rsi, [rsp + 8] ; op
mov sil, byte [rsi + 1] ; Operand.register_and_width movzx rsi, word [rsi + 2] ; Operand.width
shr sil, 4 ; width
mov rdi, [rsp] ; *text mov rdi, [rsp] ; *text
call codegen_write_width call codegen_write_width
mov rbx, rax mov rbx, rax
@ -1521,8 +1544,8 @@ codegen_write_operand:
; write address name ; write address name
mov rax, [rsp + 8] ; op mov rax, [rsp + 8] ; op
mov rdi, [rsp] ; *text mov rdi, [rsp] ; *text
mov rsi, [rax + 8] ; op.value mov rsi, [rax + 8] ; Operand.value
mov rdx, [rax + 2] ; op.len mov rdx, [rax + 4] ; Operand.len
mov dx, dx ; low 16 bits mov dx, dx ; low 16 bits
call vec_extend call vec_extend
@ -1607,10 +1630,10 @@ codegen_move_rbp_slot_src:
; construct dst Operand ; construct dst Operand
mov byte [rsp + 0], OPERAND_RBP_OFFSET ; Operand.kind mov byte [rsp + 0], OPERAND_RBP_OFFSET ; Operand.kind
mov byte [rsp + 1], 0x80 ; Operand.register_and_width (width=8) mov byte [rsp + 1], 0 ; Operand.register = undef
mov word [rsp + 2], 0 ; Operand.len = 0 mov word [rsp + 2], 8 ; Operand.width = 8
mov dword [rsp + 4], 0 ; padding mov word [rsp + 4], 0 ; Operand.len = 0
mov qword [rsp + 8], rdx ; Operand.value = rbp offset mov qword [rsp + 8], rdx ; Operand.value = rbp offset
mov rdx, rsi mov rdx, rsi
lea rsi, [rsp + 0] ; dst lea rsi, [rsp + 0] ; dst
@ -1849,19 +1872,17 @@ codegen_move_dst_src:
jg .panic ; unsupported dst kind jg .panic ; unsupported dst kind
; if dst.width != src.width ; if dst.width != src.width
mov cl, byte [rsi + 1] ; dst.register_and_width mov cx, word [rsi + 2] ; dst.width
mov bl, byte [rdx + 1] ; src.register_and_width mov bx, word [rdx + 2] ; src.width
shr cl, 4 cmp cx, bx
shr bl, 4
cmp cl, bl
jne .panic ; mismatched widths jne .panic ; mismatched widths
; if dst.width == 8 && src.kind == OPERAND_ADDRESS ; ; if dst.width == 8 && src.kind == OPERAND_ADDRESS
xor rbx, rbx ; xor rbx, rbx
cmp cl, 8 ; cmp cx, 8
cmovne rbx, [rdx + 0] ; cmovne rbx, [rdx + 0]
cmp bl, OPERAND_ADDRESS ; cmp bl, OPERAND_ADDRESS
je .panic ; address can only be moved to full-sized destinations ; je .panic ; address can only be moved to full-sized destinations
cmp byte [rsi + 0], OPERAND_REGISTER cmp byte [rsi + 0], OPERAND_REGISTER
je .do_move ; if dst == register, do move je .do_move ; if dst == register, do move
@ -1935,11 +1956,3 @@ section .rdata
MUL_ dq "mul " MUL_ dq "mul "
DIV_ dq "div " DIV_ dq "div "
; Operand { kind: REGISTER, register: 0, width: 8, len: 0, padding: 0, value: 0 }
align 8
OPERAND_RAX dq 0x0000_8001, 0
align 8
OPERAND_RDX dq 0x0000_8301, 0
align 8
OPERAND_RBP_OFFSET dq 0x0000_8002, 0

View file

@ -64,6 +64,8 @@ pub const OPERAND_ADDRESS: u32 = 4;
pub const OPERAND_IMMEDIATE: u32 = 5; pub const OPERAND_IMMEDIATE: u32 = 5;
pub const OPERAND_CONSTANT: u32 = 6; pub const OPERAND_CONSTANT: u32 = 6;
pub const OPERAND_LABEL: u32 = 7; pub const OPERAND_LABEL: u32 = 7;
pub const OPERAND_REGISTER_PLACE: u32 = 8;
pub const OPERAND_RBP_PLACE: u32 = 9;
pub const TOKEN_EOF: u8 = 0; pub const TOKEN_EOF: u8 = 0;
pub const TOKEN_LET: u8 = 1; pub const TOKEN_LET: u8 = 1;
pub const TOKEN_IF: u8 = 2; pub const TOKEN_IF: u8 = 2;
@ -247,7 +249,8 @@ pub struct FunctionCtx {
#[derive(Debug)] #[derive(Debug)]
pub struct Operand { pub struct Operand {
pub kind: u8, pub kind: u8,
pub register_and_width: u8, pub register: u8,
pub width: u16,
pub len: u16, pub len: u16,
pub value: u64, pub value: u64,
} }