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
                 |