hlorenzi / customasm

💻 An assembler for custom, user-defined instruction sets! https://hlorenzi.github.io/customasm/web/
Apache License 2.0
704 stars 55 forks source link

le() causes negative numbers to become positive #174

Closed Ruichka closed 1 year ago

Ruichka commented 1 year ago

If a negative value is passed onto a le() function, the minus sign gets dropped, causing the end result to be the positive number with a reversed byte order instead of the negative number with a reversed byte order.

This happens even if a reversal can't happen since the size of the value is 1 byte.

Example code that produces the bug:

#ruledef
{
    addq a, {val: i32} => le(val)
    addb a, {val: i8} => le(val)
    addq_be a, {val: i32} => val 
    addb_be a, {val: i8} => val
}

; 4 bytes with le
addq a, 0x0f
addq a, -0x0f
; expected:
; 0f 00 00 00
; f1 ff ff ff
; real output:
; 0f 00 00 00
; 0f 00 00 00
; negative number became positive and then got byte order reversed

; 1 byte with le
addb a, 0x0f
addb a, -0x0f
; expected:
; 0f
; f1
; real output:
; 0f
; 0f
; negative number became positive, no byte order change since only 1 byte

; 4 bytes without le
addq_be a, 0x0f
addq_be a, -0x0f
; expected:
; 0f 00 00 00
; ff ff ff f1
; real output:
; 0f 00 00 00
; ff ff ff f1
; works correctly!

; 1 byte without le
addb_be a, 0x0f
addb_be a, -0x0f
; expected:
; 0f
; f1
; real output:
; 0f
; f1
; works correctly!
chrisgbk commented 1 year ago

Seems you can workaround it by explicitly slicing the value in the argument passed to le(...)

#ruledef
{
    addq a, {val: i32} => le(val`32)
    addb a, {val: i8} => le(val`8)
    addq_be a, {val: i32} => val 
    addb_be a, {val: i8} => val
}
 outp | addr | data (base 16)

  0:0 |    0 | 0f 00 00 00 ; addq a, 0x0f
  4:0 |    4 | f1 ff ff ff ; addq a, -0x0f
  8:0 |    8 | 0f          ; addb a, 0x0f
  9:0 |    9 | f1          ; addb a, -0x0f
  a:0 |    a | 00 00 00 0f ; addq_be a, 0x0f
  e:0 |    e | ff ff ff f1 ; addq_be a, -0x0f
 12:0 |   12 | 0f          ; addb_be a, 0x0f
 13:0 |   13 | f1          ; addb_be a, -0x0f

which makes no sense to me that this fixes it, but it does.

chrisgbk commented 1 year ago

Concatenating literally nothing no matter the order also fixes it.

#ruledef
{
    addq a, {val: i32} => le(val@0`0)
    addb a, {val: i8} => le(0`0@val)
    addq_be a, {val: i32} => val 
    addb_be a, {val: i8} => val
}
 outp | addr | data (base 16)

  0:0 |    0 | 0f 00 00 00 ; addq a, 0x0f
  4:0 |    4 | f1 ff ff ff ; addq a, -0x0f
  8:0 |    8 | 0f          ; addb a, 0x0f
  9:0 |    9 | f1          ; addb a, -0x0f
  a:0 |    a | 00 00 00 0f ; addq_be a, 0x0f
  e:0 |    e | ff ff ff f1 ; addq_be a, -0x0f
 12:0 |   12 | 0f          ; addb_be a, 0x0f
 13:0 |   13 | f1          ; addb_be a, -0x0f
hlorenzi commented 1 year ago

This is a really good catch, since I overlooked the possibility of creating a "sized negative value" (since le(-0x0f) errors, for example). But using the automatic slicing feature of typed instruction parameters allows you to create them.