Skip to content

Commit

Permalink
[WIP] Added support for x86/x86-64 EVEX encoding.
Browse files Browse the repository at this point in the history
  • Loading branch information
postmodern committed Feb 27, 2025
1 parent c319389 commit ac16c98
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 3 deletions.
70 changes: 67 additions & 3 deletions lib/ronin/asm/x86/encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,76 @@ def write_vex_three_byte(type: , w: nil, l: nil, m_mmmm: , pp: , r: nil, x: nil,
#
# Writes a EVEX encoding to the output stream.
#
# @raise [NotImplementedError]
# @param [0b001, 0b010, 0b011, 0b101, 0b110, nil] mmm
#
# @note This method is not implemented yet!
# @param [0b00, 0b01, 0b10, 0b11] pp
#
# @param [1, 0, nil] w
#
# @param [Operand, 0b00, 0b01, 0b10, nil] ll
#
# @param [Operand, 0b0000, nil] vvvv
#
# @param [0, nil] v
#
# @param [0, nil] rr
#
# @param [0, nil] _B
#
# @param [0, nil] x
#
# @param [Operand, 0, 1, nil] b
#
# @param [Operand, 0, nil] aaa
#
# @param [Operand, 0] z
#
# @param [1, 2, 4, 8, 16, 32, 64, nil] disp8xN
#
# @return [4]
# The number of bytes written.
#
# @see https://en.wikipedia.org/wiki/EVEX_prefix
#
def write_evex(mmm: , pp: , w: nil, ll: nil, vvvv: nil, v: nil, rr: nil, _B: nil, x: nil, b: nil, aaa: , z: , disp8xN: nil)
raise(NotImplementedError,"x86/x86-64 EVEX encoding is not yet implemented!")
byte1 = 0b01100010
byte2 = 0
# bit 3 is hardcoded
byte3 = 0b00000100
byte4 = 0

# EVEX.R is encoded as an inverted value
byte2 |= 0b10010000 if r == 0

# EVEX.X is encoded as an inverted value
byte2 |= 0b01000000 if x == 0

# EVEX.B is encoded as an inverted value
byte2 |= 0b00100000 if _B == 0

byte2 |= mmm if mmm > 0

byte3 |= (w << 7) if w == 1

if vvvv
# VEX.vvvv is encoded as the inverted value of the extra operand
byte3 |= ((~vvvv.to_i & 0b1111) << 3)
end

byte3 |= pp if pp > 0

# TODO: set to 1 if z is a {k}{z} operand.
# byte4 |= z << 7
byte4 |= (ll << 4) if ll
# TODO: if b is an operand, check for "source broadcast" or
# "rounding "control".
byte4 |= 0b10000 if b == 1
byte4 |= 0b01000 if v == 0

# TODO: figure out how to encode aaa when it's an operand
byte4 |= aaa

write_byte(byte1) + write_byte(byte2) + write_byte(byte3) + write_byte(byte4)
end

end
Expand Down
86 changes: 86 additions & 0 deletions lib/ronin/asm/x86_64/encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,92 @@ def write_vex_three_byte(type: , w: nil, l: nil, m_mmmm: , pp: , r: nil, x: nil,
write_byte(byte1) + write_byte(byte2) + write_byte(byte3)
end

#
# Writes a EVEX encoding to the output stream.
#
# @param [0b001, 0b010, 0b011, 0b101, 0b110, nil] mmm
#
# @param [0b00, 0b01, 0b10, 0b11] pp
#
# @param [1, 0, nil] w
#
# @param [Operand, 0b00, 0b01, 0b10, nil] ll
#
# @param [Operand, 0b0000, nil] vvvv
#
# @param [Operand, 0, nil] v
#
# @param [Operand, 0, nil] rr
#
# @param [Operand, 0, nil] _B
#
# @param [Operand, 0, nil] x
#
# @param [Operand, 0, 1, nil] b
#
# @param [Operand, 0, nil] aaa
#
# @param [Operand, 0] z
#
# @param [1, 2, 4, 8, 16, 32, 64, nil] disp8xN
#
# @return [4]
# The number of bytes written.
#
# @see https://en.wikipedia.org/wiki/EVEX_prefix
#
def write_evex(mmm: , pp: , w: nil, ll: nil, vvvv: nil, v: nil, rr: nil, _B: nil, x: nil, b: nil, aaa: , z: , disp8xN: nil)
byte1 = 0b01100010
byte2 = 0
# bit 3 is hardcoded
byte3 = 0b00000100
byte4 = 0

# EVEX.R is encoded as the inverted version of REX.R
unless (r.kind_of?(Register) && r.number.bit_length == 4)
byte2 |= 0b10010000
end

# EVEX.X is encoded as the inverted version of REX.X
unless (x.kind_of?(Memory) && x.index && x.index.number.bit_length == 4)
byte2 |= 0b01000000
end

# EVEX.B is encoded as the inverted version of REX.B
unless ((_B.kind_of?(Register) && _B.number.bit_length == 4) ||
(_B.kind_of?(Memory) && _B.base.number.bit_length == 4))
byte2 |= 0b00100000
end

byte2 |= mmm if mmm > 0

byte3 |= (w << 7) if w == 1

if vvvv
# VEX.vvvv is encoded as the inverted value of the extra operand
byte3 |= ((~vvvv.to_i & 0b1111) << 3)
end

byte3 |= pp if pp > 0

# TODO: set to 1 if z is a {k}{z} operand.
# byte4 |= z << 7
byte4 |= (ll << 4) if ll
# TODO: if b is an operand, check for "source broadcast" or
# "rounding "control".
byte4 |= 0b10000 if b == 1
byte4 |= 0b01000 if v == 0

if (v.kind_of?(Register) && v.number.bit_length == 4)
byte4 |= 0b1000
end

# TODO: figure out how to encode aaa when it's an operand
byte4 |= aaa

write_byte(byte1) + write_byte(byte2) + write_byte(byte3) + write_byte(byte4)
end

end
end
end
Expand Down

0 comments on commit ac16c98

Please sign in to comment.