flat assembler
Message board for the users of flat assembler.

Index > Non-x86 architectures > [ARM] Convert X86 string to ARM: LODS, STOS, MOVS, ETC

Author
Thread Post new topic Reply to topic
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 27 Jun 2014, 02:20
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.
Code:
; 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:
Code:
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".
Code:
;;;;;;;;;;;;;;;;;;;; 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
Post 27 Jun 2014, 02:20
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20361
Location: In your JS exploiting you and your system
revolution 27 Jun 2014, 02:40
"orrs r12, FLAG.D" perhaps you mean ands or tst?
Post 27 Jun 2014, 02:40
View user's profile Send private message Visit poster's website Reply with quote
m3ntal



Joined: 08 Dec 2013
Posts: 296
m3ntal 27 Jun 2014, 02:49
Yes, tst is what I meant. FLAG.D=400h, bit #10. Edited.
Post 27 Jun 2014, 02:49
View user's profile Send private message Reply with quote
nop



Joined: 01 Sep 2008
Posts: 165
Location: right here left there
nop 27 Jun 2014, 03:56
revolution wrote:
"orrs r12, FLAG.D" perhaps you mean ands or tst?
haha m3ntal was just tsting to see if you were paying atention Very Happy
Post 27 Jun 2014, 03:56
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20361
Location: In your JS exploiting you and your system
revolution 27 Jun 2014, 09:00
nop wrote:
haha m3ntal was just tsting to see if you were paying atention Very Happy
Did I pass the tst Question
Post 27 Jun 2014, 09:00
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.