m3ntal
Joined: 08 Dec 2013
Posts: 296
|
An attempt to convert X86 string operations to ARM: LODS, STOS, MOVS, SCAS, CMPS and ultimately to translate FASM to native ARM. FASM uses lots of these in its source code.
Is the disassembly correct? First, they mov r11, index size then call _string.a to get direction flag and adjust sizes. Replace @flags=77h with global eflags variable. On entry, r1/ecx=count. ; CONVERT X86 STRING TO ARM: LODS, STOS,
; MOVS, ETC. ASSEMBLE WITH FASMARM:
include 'arm.inc'
lodsb
rep stosd
scasw
cmpsd
movs byte [edi], [esi]
stos dword [edi]
rep scas word [edi]
rep movs byte [edi], [esi]
rep cmps byte [esi], [edi]
_string.a:
push r12, lr
mul r1, r1, r11 ; get total size
mov r12, @flags ; get flags
ldr r12, [r12] ; if direction
tst r12, FLAG.D ; flag (DF=1),
rsbne r11, 0 ; negate element size
rsbne r1, 0 ; negate size
pop r12, pc Disassembly: 00000000 E3A0B001 mov r11, 1
00000004 EB000032 bl 0D4h
00000008 E6D6000B ldrb r0, [r6], r11
0000000C E3510000 cmp r1, 0
00000010 0A000004 beq 28h
00000014 E3A0B004 mov r11, 4
00000018 EB00002D bl 0D4h
0000001C E08700FB strd r0, [r7], r11
00000020 E051100B subs r1, r1, r11
00000024 1AFFFFFC bne 1Ch
00000028 E3A0B002 mov r11, 2
0000002C EB000028 bl 0D4h
00000030 E097C0BB ldrh r12, [r7], r11
00000034 E150000C cmp r0, r12
00000038 E3A0B004 mov r11, 4
0000003C EB000024 bl 0D4h
00000040 E087C0DB ldrd r12, [r7], r11
00000044 E086A0DB ldrd r10, [r6], r11
00000048 E15C000A cmp r12, r10
0000004C E3A0B001 mov r11, 1
00000050 EB00001F bl 0D4h
00000054 E6D6000B ldrb r0, [r6], r11
00000058 E6C7000B strb r0, [r7], r11
0000005C E3A0B004 mov r11, 4
00000060 EB00001B bl 0D4h
00000064 E08700FB strd r0, [r7], r11
00000068 E3510000 cmp r1, 0
0000006C 0A000006 beq 8Ch
00000070 E3A0B002 mov r11, 2
00000074 EB000016 bl 0D4h
00000078 E097C0BB ldrh r12, [r7], r11
0000007C E150000C cmp r0, r12
00000080 1A000001 bne 8Ch
00000084 E051100B subs r1, r1, r11
00000088 1AFFFFFA bne 78h
0000008C E3510000 cmp r1, 0
00000090 0A000005 beq 0ACh
00000094 E3A0B001 mov r11, 1
00000098 EB00000D bl 0D4h
0000009C E6D6000B ldrb r0, [r6], r11
000000A0 E6C7000B strb r0, [r7], r11
000000A4 E051100B subs r1, r1, r11
000000A8 1AFFFFFB bne 9Ch
000000AC E3510000 cmp r1, 0
000000B0 0A000007 beq 0D4h
000000B4 E3A0B001 mov r11, 1
000000B8 EB000005 bl 0D4h
000000BC E6D7C00B ldrb r12, [r7], r11
000000C0 E6D6A00B ldrb r10, [r6], r11
000000C4 E15C000A cmp r12, r10
000000C8 1A000001 bne 0D4h
000000CC E051100B subs r1, r1, r11
000000D0 1AFFFFF9 bne 0BCh
000000D4 E92D5000 stmdb sp!, {r12,lr}
000000D8 E0010B91 mul r1, r1, r11
000000DC E3A0C077 mov r12, 77h
000000E0 E59CC000 ldr r12, [r12]
000000E4 E39CCB01 orrs r12, r12, 400h
000000E8 126BB000 rsbne r11, r11, 0
000000EC 12611000 rsbne r1, r1, 0
000000F0 E8BD9000 ldmia sp!, {r12,pc} ARM.inc: Search for "string". ;;;;;;;;;;;;;;;;;;;; ARM.INC ;;;;;;;;;;;;;;;;;;;;;
; USEFUL MACROS FOR FASMARM: MOVE IMMEDIATE
; (MOV/MVN, ROTATION, MOVW/MOVT), LITERAL TABLE,
; PC RELATIVE LOAD, LDR =I/&I UPGRADE (FOR GAS/GCC
; COMPATIBILITY), AUTOMATIC LITERALS IN FUNCTIONS,
; MOV+DATA [M]/I/[A+B*C] UPGRADE (ADD/SUB/CMP/ETC),
; X86 STRING OPERATIONS (REP STOS/MOVS/ETC)
is.i? fix eqtype 0 ; is immediate?
is.r? fix \ ; is register?
in <r0,r1,r2,r3,r4,r5,r6,r7,\ ; name in list?
r8,r9,r10,r11,r12,r13,r14,r15>
@r fix r12 ; spare
@sr fix r11 ; source
@dr fix r10 ; destiny
macro nop { mov r0, r0 }
macro nops n { times n nop }
; load/store multiple to/from memory.
; registers are processed sequentially
; regardless of order. example:
; push r0-r3, r5, r6, r7, v7-v8, lr
; pop r0-r3, r5, r6, r7, v7-v8, pc
macro push [r] { common stmfd sp!, \{ r \} }
macro pop [r] { common ldmfd sp!, \{ r \} }
; pushx/popx all general purpose registers
; or pusha/popa all argument registers
macro pushx { push r0-r12 }
macro popx { pop r0-r12 }
macro pusha { push a1-a4 }
macro popa { pop a1-a4 }
;;;;;;;;;;;;;;;;;;; TRANSFER ;;;;;;;;;;;;;;;;;;;;;
macro jmp l { bal l } ; never use b
macro go l { bal l }
macro call l { bl l }
macro je l { beq l }
macro jne l { bne l }
macro jz l { beq l }
macro jnz l { bne l }
;;;;;;;;;;;;;;;;;; ARITHMETIC ;;;;;;;;;;;;;;;;;;;;
macro inc r { adds r, 1 }
macro dec r { subs r, 1 }
;;;;;;;;;;;;;;;;;; SMART-MOVE ;;;;;;;;;;;;;;;;;;;;
; "Smart-Move" immediate with PC relative
; load from nearby literal table - ldr r,
; [pc, p-$-8] - or optional movw/movt
; for FASMARM. =i prefix for "move 32BIT
; immediate" (compatible with GAS/GCC).
; =& for PC relative load
literals equ ; literal table
literals.i=-1 ; offset
; define literal 32BIT number. attach line/data
; definition: literals=itself+dw x
macro .literal x {
literals equ literals, dw x
literals.i=literals.i+4
}
; store literal table or initialize
macro .literals {
local ..literals
?LITERALS \ ; address
equ ..literals
match j, literals \{ ; expand into a,b,c
irp i, j \\{ ; expand each line
i ; dw 1, dw 2, dw 3
\\}
restore ?LITERALS
\}
match , literals \{ ; initialize
literals equ \ ; first lines...
align 4,\
?LITERALS:,\ ; begin
literals.i=0 ; offset
\}
}
;;;;;;;;;;;;;;;;; MOVE IMMEDIATE ;;;;;;;;;;;;;;;;;
use.mov? fix \
(i>=0 & i<=255)\ ; use mov?
| (i=-1 | i=$FFFFFFFF)\ ; use mvn?
| (i and $FFFFF00F)=0\ ; use mov+ror?
| (i and $FFFF00FF)=0\ ; FF00h
| (i and $FFF00FFF)=0\ ; FF000h
| (i and $FF00FFFF)=0\ ; FF0000h
| (i and $F00FFFFF)=0\ ; FF00000h
| (i and $00FFFFFF)=0 ; FF000000h
; move wide/top 32BIT
use.movwt? equ 0 ; 1 if CPU>=ARM.v6T2
macro movwt r, i {
i=i and 0FFFFh
movw r, i ; low 16BIT
i=(i shr 16) \
and 0FFFFh
if i<>0 ; high 16BIT?
movt r, i
end if
}
; generic move 32BIT immediate (worst
; case scenerio)
macro movi r, i {
local n
n=i and 0FFh
mov r, n ; mov r, b&FFh
n=(i and 0FF00h)
if n<>0 ; if 16+BIT...
orr r, n ; orr r, r, b&FF00h
end if
n=(i and 0FF0000h)
if n<>0
orr r, n ; orr r, r, b&FF0000h
end if
n=(i and 0FF000000h)
if n<>0
orr r, n ; orr r, r, i&FF000000h
end if
}
;;;;;;;;;;;;;;; LDR =I/&I UPGRADE ;;;;;;;;;;;;;;;;
; upgrade ldr instruction to match sequences.
; =i for "move 32BIT immediate"; mov/mvn,
; constant rotation or movw/movt (if supported,
; CPU>=ARM.v6T2). &i for explicit PC relative
; load from literal table:
; ldr r, [pc, p-$-8+4] ; ldr r, &77777777h
; .literal 77777777h
macro ldr [p] {
common
local i, x
define ?s 0
match r=, &n, p \{ ; ldr r, &i
x=(?LITERALS+\ ; PC relative
literals.i)-$-8+4 ; address
ldr r, [pc, x] ; load
.literal n ; store i
define ?s 1 ; matched
\}
match =0 \ ; else
r=,==n, ?s p \{ ; ldr r, =i
i=(n)
if use.mov? ; use mov?
mov r, i
else if use.movwt? ; use movw/movt?
movwt r, i ; CPU>=ARM.v6T2
else ; worst case
movi r, i ; scenerio: mov+orr
end if
define ?s 1 ; matched
\}
if ?s eq 0 ; else, use
ldr p ; original ldr
end if ; instruction
}
;;;;;;;;;;;;;;; AUTOMATIC LITERALS ;;;;;;;;;;;;;;;
; upgrade function/proc to insert literal table.
; note: custom inheritance in FASM's language
; supersedes C++/Java's concept of OOP
; macro function [p] {
; common
; function p ; function=itself/previous
; .literals ; +this/new
; }
; macro endf {
; .literals ; endf=this/new
; endf ; +itself/previous
; }
;;;;;;;;;;;;;;;;;;; @GET/@SET ;;;;;;;;;;;;;;;;;;;;
; low-level get/set helper macros. usage:
; @get r1, r2 ; r=r/[m]/i
; @get r1, 10000h
; @get r1, [r2]
; @get r1, [20000h]
; @get r1, [r2+30000h]
; @get r1, [30000h+r2]
; @get r1, [r2+r3*4]
; @set [r1], r2 ; [m]=r
; @set [20000h], r1
; @set [r1+30000h], r2
; @set [40000h+r1], r2
; @set [r1+r2*4], r3
macro @get r, x {
define ?s 0
match \
[a], x \{
match \
[b+i], x \\{
match \
I*S, i \\\{ ; [a+b*c]
if S eq 4
ldr r, [b, I, lsl 2]
else
'Error'
end if
define ?s 1
\\\}
if ?s eq 0 ; [a+b]
if b is.r? \ ; [r+r]
& i is.r?
ldr r, [b, i]
else if b is.r? \ ; [r+i]
& i is.i?
ldr @r, =i
ldr r, [b, @r]
else if i is.r? \ ; [i+r]
& b is.i?
ldr @r, =b
ldr r, [@r, i]
else
'Error'
end if
end if
define ?s 1
\\}
if ?s eq 0
if a is.r? ; [r]
ldr r, [a]
else ; [m]
ldr @r, =a
ldr r, [@r]
end if
end if
define ?s 1
\}
if ?s eq 0
if x is.r? ; r
mov r, x
else ; i
ldr r, =x
end if
end if
}
macro @set x, r {
define ?s 0
match \
[a], x \{
match \
[b+i], x \\{
match \
I*S, i \\\{ ; [a+b*c]
if S eq 4
str r, [b, I, lsl 2]
else
'Error'
end if
define ?s 1
\\\}
if ?s eq 0 ; [a+b]
if b is.r? \ ; [r+r]
& i is.r?
str r, [b, i]
else if b is.r? \ ; [r+i]
& i is.i?
ldr @r, =i
str r, [b, @r]
else if i is.r? \ ; [i+r]
& b is.i?
ldr @r, =b
str r, [@r, i]
else
'Error'
end if
end if
define ?s 1
\\}
if ?s eq 0
if a is.r? ; [r]
str r, [a]
else ; [m]
match [i j], x
\\{ 'Error' \\}
ldr @r, =a
str r, [@r]
end if
end if
\}
if ?s eq 0
'Error'
end if
}
;;;;;;;;;;;;;;; MOV [M]/I UPGRADE ;;;;;;;;;;;;;;;;
; upgrade mov to support r/[r]/[m]/i. examples:
; mov r1, r2
; mov r1, 80000000h
; mov r1, [r2]
; mov [r1], r2
; mov r1, [r2+r3]
; mov [r1+r2*4], r3
; mov r1, [r2+123ABCh]
macro mov [p] {
common
define ?s 0
match r=,[m], p \{ ; r, [m]
if m is.r?
ldr r, [m]
else
@get r, [m]
end if
define ?s 1
\}
match =0,\ ; [m], r
[m]=,r, ?s p \{
if m is.r?
str r, [m]
else
@set [m], r
end if
define ?s 1
\}
if ?s eq 0 ; else
mov p ; standard mov
end if
}
;;;;;;;;;;;;;;; DATA [M]/I UPGRADE ;;;;;;;;;;;;;;;
; upgrade all data processing instructions to
; support r/[r]/[m]/i. examples:
; add r1, r2
; orr r1, 80000000h
; and r1, [r2]
; bic [r1], r2
; sub r1, [r2+r3]
; cmp [r1+r2*4], r3
; mvn r1, [r2+123ABCh]
macro @dp name, [p] {
common
define ?s 0
match r=,[m], p \{
mov @sr, [m]
name r, @sr
define ?s 1
\}
match =0 \
[m]=,r, ?s p \{
mov @dr, [m]
name @dr, r
mov [m], @dr
define ?s 1
\}
if ?s eq 0
name p
end if
}
macro and [p] { common @dp ands, p }
macro eor [p] { common @dp eors, p }
macro sub [p] { common @dp subs, p }
macro rsb [p] { common @dp rsbs, p }
macro add [p] { common @dp adds, p }
macro adc [p] { common @dp adcs, p }
macro sbc [p] { common @dp sbcs, p }
macro rsc [p] { common @dp rscs, p }
macro tst [p] { common @dp tst, p }
macro teq [p] { common @dp teq, p }
macro cmp [p] { common @dp cmp, p }
macro cmn [p] { common @dp cmn, p }
macro bic [p] { common @dp bics, p }
macro mvn [p] { common @dp mvn, p }
; optional: restore definitions (ie, if using
; these names for a virtual machine)
; purge @get, @set
;;;;;;;;;;;;;;; REP STOS/MOVS/ETC ;;;;;;;;;;;;;;;;
; convert X86 style string: lods/stos/movs/cmps
; /scas to ARM:
; lodsb
; rep stosd
; scasw
; cmpsd
; movs byte [edi], [esi]
; stos dword [edi]
; rep scas word [edi]
; rep movs byte [edi], [esi]
; rep cmps byte [esi], [edi]
; flags; replace 77h with global flags variable
@flags fix 77h
FLAG.C=0
FLAG.Z=1 shl 6
FLAG.S=1 shl 7
FLAG.I=1 shl 9
FLAG.D=1 shl 10
FLAG.O=1 shl 11
macro @set.flag f {
push r10
mov r10, [@flags]
orr r10, FLAG.#f
mov [@flags], r10
pop r10
}
macro @zero.flag f {
push r10-r11
mov r10, [@flags]
mvn r11, FLAG.#f
and r10, r11
mov [@flags], r10
pop r10-r11
}
macro stc { @set.flag C }
macro clc { @zero.flag C }
macro std { @set.flag D }
macro cld { @zero.flag D }
; get direction flag and adjust element s/ize
macro @string.a s {
mov r11, s
call _string.a
}
; load/store/etc
macro @string.x name, r {
name r0, [r], r11
}
macro @string.s name, r, s {
@string.a s
@string.x name, r
}
macro lods [p] {
common
define ?s 0
match type [=esi], p \{
if type eq byte
@string.s ldrb, r6, 1
else if type eq word
@string.s ldrh, r6, 2
else if type eq dword
@string.s ldrd, r6, 4
else
'Error'
end if
define ?s 1
\}
if ?s eq 0
'Error'
end if
}
lodsb fix lods byte [esi]
lodsw fix lods word [esi]
lodsd fix lods dword [esi]
macro stos [p] {
common
define ?s 0
match type [=edi], p \{
if type eq byte
@string.s strb, r7, 1
else if type eq word
@string.s strh, r7, 2
else if type eq dword
@string.s strd, r7, 4
else
'Error'
end if
define ?s 1
\}
if ?s eq 0
'Error'
end if
}
stosb fix stos byte [edi]
stosw fix stos word [edi]
stosd fix stos dword [edi]
macro movs [p] {
common
define ?s 0
match type [=edi]=,[=esi], p \{
if type eq byte
@string.a 1
ldrb r0, [r6], r11
strb r0, [r7], r11
else if type eq word
@string.a 2
ldrh r0, [r6], r11
strh r0, [r7], r11
else if type eq dword
@string.a 4
ldrd r0, [r6], r11
strd r0, [r7], r11
else
'Error'
end if
define ?s 1
\}
if ?s eq 0
'Error'
end if
}
movsb fix movs byte [edi], [esi]
movsw fix movs word [edi], [esi]
movsd fix movs dword [edi], [esi]
macro scas [p] {
common
define ?s 0
match type [=edi], p \{
if type eq byte
@string.a 1
ldrb r12, [r7], r11
else if type eq word
@string.a 2
ldrh r12, [r7], r11
else if type eq dword
@string.a 4
ldrd r12, [r7], r11
else
'Error'
end if
cmp r0, r12
define ?s 1
\}
if ?s eq 0
'Error'
end if
}
scasb fix scas byte [edi]
scasw fix scas word [edi]
scasd fix scas dword [edi]
macro cmps [p] {
common
define ?s 0
match type [=esi]=,[=edi], p \{
if type eq byte
@string.a 1
ldrb r12, [r7], r11
ldrb r10, [r6], r11
else if type eq word
@string.a 2
ldrh r12, [r7], r11
ldrh r10, [r6], r11
else if type eq dword
@string.a 4
ldrd r12, [r7], r11
ldrd r10, [r6], r11
else
'Error'
end if
cmp r12, r10
define ?s 1
\}
if ?s eq 0
'Error'
end if
}
cmpsb fix cmps byte [esi], [edi]
cmpsw fix cmps word [esi], [edi]
cmpsd fix cmps dword [esi], [edi]
; repeat string operation
macro rep [p] {
common
local ..s, ..e, n
n=0
cmp r1, 0
je ..e
define ?s 0
match \
name type [a]=,[b], p \{
if type eq byte
n=1
else if type eq word
n=2
else if type eq dword
n=4
else
'Error' type
end if
@string.a n
..s:
if name eq movs
if ~a eq edi | ~b eq esi
'Error'
end if
if type eq byte
@string.x ldrb, r6
@string.x strb, r7
else if type eq word
@string.x ldrh, r6
@string.x strh, r7
else if type eq dword
@string.x ldrd, r6
@string.x strd, r7
end if
subs r1, r11
jnz ..s
else if name eq cmps
if ~a eq esi | ~b eq edi
'Error'
end if
if n=1
ldrb r12, [r7], r11
ldrb r10, [r6], r11
else if n=2
ldrh r12, [r7], r11
ldrh r10, [r6], r11
else if n=4
ldrd r12, [r7], r11
ldrd r10, [r6], r11
end if
cmp r12, r10
jne ..e
subs r1, r11
jnz ..s
else
'Error'
end if
define ?s 1
\}
match =0 \
name type [a], ?s p \{
if type eq byte
n=1
else if type eq word
n=2
else if type eq dword
n=4
else
'Error' type
end if
@string.a n
..s:
if name eq lods
if ~a eq esi
'Error' a
end if
if n=1
@string.x ldrb, r6
else if n=2
@string.x ldrh, r6
else if n=4
@string.x ldrd, r6
end if
subs r1, r11
jnz ..s
else if name eq stos
if ~a eq edi
'Error' a
end if
if n=1
@string.x strb, r7
else if n=2
@string.x strh, r7
else if n=4
@string.x strd, r7
end if
subs r1, r11
jnz ..s
else if name eq scas
if ~a eq edi
'Error' a
end if
if n=1
ldrb r12, [r7], r11
else if n=2
ldrh r12, [r7], r11
else if n=4
ldrd r12, [r7], r11
end if
cmp r0, r12
jne ..e
subs r1, r11
jnz ..s
else
'Error' name
end if
define ?s 1
\}
if ?s eq 0
'Error'
end if
..e:
}
Last edited by m3ntal on 27 Jun 2014, 02:52; edited 2 times in total
|