node/lib/metasm/metasm/cpu/ia32/encode.rb
def encode_instr_op(program, i, op)
		base      = op.bin.dup
		oi        = op.args.zip(i.args)
		set_field = lambda { |f, v|
			v ||= 0		# ST => ST(0)
			fld = op.fields[f]
			base[fld[0]] |= v << fld[1]
		}

		size = i.prefix[:sz] || @size

		#
		# handle prefixes and bit fields
		#
		pfx = i.prefix.map { |k, v|
			case k
			when :jmp;  {:jmp => 0x3e, :nojmp => 0x2e}[v]
			when :lock; 0xf0
			when :rep;  {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v]
			when :jmphint; {'hintjmp' => 0x3e, 'hintnojmp' => 0x2e}[v]
			when :seg; [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][v.val]
			end
		}.compact.pack 'C*'

		if op.name == 'movsx' or op.name == 'movzx'
			pfx << 0x66 if size == 48-i.args[0].sz
		elsif op.name == 'crc32'
			pfx << 0x66 if size == 48-i.args[1].sz
		else
			opsz = op.props[:argsz]
			oi.each { |oa, ia|
				case oa
				when :reg, :reg_eax, :modrm, :mrm_imm
					raise EncodeError, "Incompatible arg size in #{i}" if ia.sz and opsz and opsz != ia.sz
					opsz = ia.sz
				end
			}
			pfx << 0x66 if (op.props[:opsz] and size == 48 - op.props[:opsz]) or
					(not op.props[:argsz] and opsz and size == 48 - opsz)
			opsz ||= op.props[:opsz]
		end
		opsz ||= size

		if op.props[:adsz] and size == 48 - op.props[:adsz]
			pfx << 0x67
			adsz = 48 - size
		end
		adsz ||= size
		# addrsize override / segment override
		if mrm = i.args.grep(ModRM).first
			if not op.props[:adsz] and ((mrm.b and mrm.b.sz == 48 - adsz) or (mrm.i and mrm.i.sz == 48 - adsz))
				pfx << 0x67
				adsz = 48 - adsz
			end
			pfx << [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][mrm.seg.val] if mrm.seg
		end


		#
		# encode embedded arguments
		#
		postponed = []
		oi.each { |oa, ia|
			case oa
			when :reg, :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :eeet, :regfp, :regmmx, :regxmm, :regymm
				# field arg
				set_field[oa, ia.val]
				pfx << 0x66 if oa == :regmmx and op.props[:xmmx] and ia.sz == 128
			when :vexvreg, :vexvxmm, :vexvymm
				set_field[:vex_vvvv, ia.val ^ 0xf]
			when :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp0
				# implicit
			else
				postponed << [oa, ia]
			end
		}

		if !(op.args & [:modrm, :modrmmmx, :modrmxmm, :modrmymm]).empty?
			# reg field of modrm
			regval = (base[-1] >> 3) & 7
			base.pop
		end

		# convert label name for jmp/call/loop to relative offset
		if op.props[:setip] and op.name[0, 3] != 'ret' and i.args.first.kind_of? Expression
			postlabel = program.new_label('post'+op.name)
			target = postponed.first[1]
			target = target.rexpr if target.kind_of? Expression and target.op == :+ and not target.lexpr
			postponed.first[1] = Expression[target, :-, postlabel]
		end

		pfx << op.props[:needpfx] if op.props[:needpfx]

		#
		# append other arguments
		#
		ret = EncodedData.new(pfx + base.pack('C*'))

		postponed.each { |oa, ia|
			case oa
			when :farptr; ed = ia.encode(@endianness, "a#{opsz}".to_sym)
			when :modrm, :modrmmmx, :modrmxmm, :modrmymm
				if ia.kind_of? ModRM
					ed = ia.encode(regval, @endianness)
					if ed.kind_of?(::Array)
						if ed.length > 1
							# we know that no opcode can have more than 1 modrm
							ary = []
							ed.each { |m|
								ary << (ret.dup << m)
							}
							ret = ary
							next
						else
							ed = ed.first
						end
					end
				else
					ed = ModRM.encode_reg(ia, regval)
				end
			when :mrm_imm; ed = ia.imm.encode("a#{adsz}".to_sym, @endianness)
			when :i8, :u8, :u16; ed = ia.encode(oa, @endianness)
			when :i; ed = ia.encode("a#{opsz}".to_sym, @endianness)
			when :i4xmm, :i4ymm; ed = ia.val << 4	# u8
			else raise SyntaxError, "Internal error: want to encode field #{oa.inspect} as arg in #{i}"
			end

			if ret.kind_of?(::Array)
				ret.each { |e| e << ed }
			else
				ret << ed
			end
		}

		# we know that no opcode with setip accept both modrm and immediate arg, so ret is not an ::Array
		ret.add_export(postlabel, ret.virtsize) if postlabel

		ret
	end
# returns all forms of the encoding of instruction i using opcode op
# program may be used to create a new label for relative jump/call
returns all forms of the encoding of instruction i using opcode op
program may be used to create a new label for relative jump/call
returns all forms of the encoding of instruction i using opcode op program may be used to create a new label for relative jump / call
def encode_instr_op(program, i, op)
		base      = op.bin.dup
		oi        = op.args.zip(i.args)
		set_field = lambda { |f, v|
			v ||= 0		
			fld = op.fields[f]
			base[fld[0]] |= v << fld[1]
		}
		size = i.prefix[:sz] || @size
		 handle prefixes and bit fields
		pfx = i.prefix.map { |k, v|
			case k
			when :jmp;  {:jmp => 0x3e, :nojmp => 0x2e}[v]
			when :lock; 0xf0
			when :rep;  {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v]
			when :jmphint; {'hintjmp' => 0x3e, 'hintnojmp' => 0x2e}[v]
			when :seg; [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][v.val]
			end
		}.compact.pack 'C*'
		if op.name == 'movsx' or op.name == 'movzx'
			pfx << 0x66 if size == 48-i.args[0].sz
		elsif op.name == 'crc32'
			pfx << 0x66 if size == 48-i.args[1].sz
		else
			opsz = op.props[:argsz]
			oi.each { |oa, ia|
				case oa
				when :reg, :reg_eax, :modrm, :mrm_imm
					raise EncodeError, "Incompatible arg size in {i}" if ia.sz and opsz and opsz != ia.sz
					opsz = ia.sz
				end
			}
			pfx << 0x66 if (op.props[:opsz] and size == 48 - op.props[:opsz]) or
					(not op.props[:argsz] and opsz and size == 48 - opsz)
			opsz ||= op.props[:opsz]
		end
		opsz ||= size
		if op.props[:adsz] and size == 48 - op.props[:adsz]
			pfx << 0x67
			adsz = 48 - size
		end
		adsz ||= size
		 addrsize override / segment override
		if mrm = i.args.grep(ModRM).first
			if not op.props[:adsz] and ((mrm.b and mrm.b.sz == 48 - adsz) or (mrm.i and mrm.i.sz == 48 - adsz))
				pfx << 0x67
				adsz = 48 - adsz
			end
			pfx << [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][mrm.seg.val] if mrm.seg
		end
		 encode embedded arguments
		postponed = []
		oi.each { |oa, ia|
			case oa
			when :reg, :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :eeet, :regfp, :regmmx, :regxmm, :regymm
				 field arg
				set_field[oa, ia.val]
				pfx << 0x66 if oa == :regmmx and op.props[:xmmx] and ia.sz == 128
			when :vexvreg, :vexvxmm, :vexvymm
				set_field[:vex_vvvv, ia.val ^ 0xf]
			when :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp0
				 implicit
			else
				postponed << [oa, ia]
			end
		}
		if !(op.args & [:modrm, :modrmmmx, :modrmxmm, :modrmymm]).empty?
			 reg field of modrm
			regval = (base[-1] >> 3) & 7
			base.pop
		end
		 convert label name for jmp/call/loop to relative offset
		if op.props[:setip] and op.name[0, 3] != 'ret' and i.args.first.kind_of? Expression
			postlabel = program.new_label('post'+op.name)
			target = postponed.first[1]
			target = target.rexpr if target.kind_of? Expression and target.op == :+ and not target.lexpr
			postponed.first[1] = Expression[target, :-, postlabel]
		end
		pfx << op.props[:needpfx] if op.props[:needpfx]
		 append other arguments
		ret = EncodedData.new(pfx + base.pack('C*'))
		postponed.each { |oa, ia|
			case oa
			when :farptr; ed = ia.encode(@endianness, "a{opsz}".to_sym)
			when :modrm, :modrmmmx, :modrmxmm, :modrmymm
				if ia.kind_of? ModRM
					ed = ia.encode(regval, @endianness)
					if ed.kind_of?(::Array)
						if ed.length > 1
							 we know that no opcode can have more than 1 modrm
							ary = []
							ed.each { |m|
								ary << (ret.dup << m)
							}
							ret = ary
							next
						else
							ed = ed.first
						end
					end
				else
					ed = ModRM.encode_reg(ia, regval)
				end
			when :mrm_imm; ed = ia.imm.encode("a{adsz}".to_sym, @endianness)
			when :i8, :u8, :u16; ed = ia.encode(oa, @endianness)
			when :i; ed = ia.encode("a{opsz}".to_sym, @endianness)
			when :i4xmm, :i4ymm; ed = ia.val << 4	 u8
			else raise SyntaxError, "Internal error: want to encode field {oa.inspect} as arg in {i}"
			end
			if ret.kind_of?(::Array)
				ret.each { |e| e << ed }
			else
				ret << ed
			end
		}
		 we know that no opcode with setip accept both modrm and immediate arg, so ret is not an ::Array
		ret.add_export(postlabel, ret.virtsize) if postlabel
		ret
	end
def encode_instr_op ( program , i , op ) base = op . bin . dup oi = op . args . zip ( i . args ) set_field = lambda { | f , v | v ||= 0 fld = op . fields [ f ] base [ fld [ 0 ] ] |= v << fld [ 1 ] } size = i . prefix [ :sz ] || @size pfx = i . prefix . map { | k , v | case k when :jmp ; { :jmp => 0x3e , :nojmp => 0x2e } [ v ] when :lock ; 0xf0 when :rep ; { 'repnz' => 0xf2 , 'repz' => 0xf3 , 'rep' => 0xf2 } [ v ] when :jmphint ; { 'hintjmp' => 0x3e , 'hintnojmp' => 0x2e } [ v ] when :seg ; [ 0x26 , 0x2E , 0x36 , 0x3E , 0x64 , 0x65 ] [ v . val ] end } . compact . pack 'C*' if op . name == 'movsx' or op . name == 'movzx' pfx << 0x66 if size == 48 - i . args [ 0 ] . sz elsif op . name == 'crc32' pfx << 0x66 if size == 48 - i . args [ 1 ] . sz else opsz = op . props [ :argsz ] oi . each { | oa , ia | case oa when :reg , :reg_eax , :modrm , :mrm_imm raise EncodeError , "Incompatible arg size in #{i}" if ia . sz and opsz and opsz != ia . sz opsz = ia . sz end } pfx << 0x66 if ( op . props [ :opsz ] and size == 48 - op . props [ :opsz ] ) or ( not op . props [ :argsz ] and opsz and size == 48 - opsz ) opsz ||= op . props [ :opsz ] end opsz ||= size if op . props [ :adsz ] and size == 48 - op . props [ :adsz ] pfx << 0x67 adsz = 48 - size end adsz ||= size if mrm = i . args . grep ( ModRM ) . first if not op . props [ :adsz ] and ( ( mrm . b and mrm . b . sz == 48 - adsz ) or ( mrm . i and mrm . i . sz == 48 - adsz ) ) pfx << 0x67 adsz = 48 - adsz end pfx << [ 0x26 , 0x2E , 0x36 , 0x3E , 0x64 , 0x65 ] [ mrm . seg . val ] if mrm . seg end postponed = [ ] oi . each { | oa , ia | case oa when :reg , :seg3 , :seg3A , :seg2 , :seg2A , :eeec , :eeed , :eeet , :regfp , :regmmx , :regxmm , :regymm set_field [ oa , ia . val ] pfx << 0x66 if oa == :regmmx and op . props [ :xmmx ] and ia . sz == 128 when :vexvreg , :vexvxmm , :vexvymm set_field [ :vex_vvvv , ia . val ^ 0xf ] when :imm_val1 , :imm_val3 , :reg_cl , :reg_eax , :reg_dx , :regfp0 else postponed << [ oa , ia ] end } if ! ( op . args & [ :modrm , :modrmmmx , :modrmxmm , :modrmymm ] ) . empty? regval = ( base [ - 1 ] >> 3 ) & 7 base . pop end if op . props [ :setip ] and op . name [ 0 , 3 ] != 'ret' and i . args . first . kind_of? Expression postlabel = program . new_label ( 'post' + op . name ) target = postponed . first [ 1 ] target = target . rexpr if target . kind_of? Expression and target . op == :+ and not target . lexpr postponed . first [ 1 ] = Expression [ target , :- , postlabel ] end pfx << op . props [ :needpfx ] if op . props [ :needpfx ] ret = EncodedData . new ( pfx + base . pack ( 'C*' ) ) postponed . each { | oa , ia | case oa when :farptr ; ed = ia . encode ( @endianness , "a#{opsz}" . to_sym ) when :modrm , :modrmmmx , :modrmxmm , :modrmymm if ia . kind_of? ModRM ed = ia . encode ( regval , @endianness ) if ed . kind_of? ( :: Array ) if ed . length > 1 ary = [ ] ed . each { | m | ary << ( ret . dup << m ) } ret = ary next else ed = ed . first end end else ed = ModRM . encode_reg ( ia , regval ) end when :mrm_imm ; ed = ia . imm . encode ( "a#{adsz}" . to_sym , @endianness ) when :i8 , :u8 , :u16 ; ed = ia . encode ( oa , @endianness ) when :i ; ed = ia . encode ( "a#{opsz}" . to_sym , @endianness ) when :i4xmm , :i4ymm ; ed = ia . val << 4 else raise SyntaxError , "Internal error: want to encode field #{oa.inspect} as arg in #{i}" end if ret . kind_of? ( :: Array ) ret . each { | e | e << ed } else ret << ed end } ret . add_export ( postlabel , ret . virtsize ) if postlabel ret end
returns all forms of the encoding of instruction i using opcode op
program may be used to create a new label for relative jump/call
returns all forms of the encoding of instruction i using opcode op program may be used to create a new label for relative jump / call
# ST => ST(0) # # handle prefixes and bit fields # # addrsize override / segment override # # encode embedded arguments # # field arg # implicit # reg field of modrm # convert label name for jmp/call/loop to relative offset # # append other arguments # # we know that no opcode can have more than 1 modrm # u8 # we know that no opcode with setip accept both modrm and immediate arg, so ret is not an ::Array
program
i
op