flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > 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
[ARM] Convert X86 string to ARM: LODS, STOS, MOVS, ETC
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 r12lr
  mul r1r1r11  ; get total size
  mov r12@flags  ; get flags
  ldr r12, [r12]   ; if direction
  tst r12FLAG.D  ; flag (DF=1),
  rsbne r110     ; negate element size
  rsbne r10      ; negate size
 pop r12pc

Disassembly:

Code:
00000000 E3A0B001 mov r111
00000004 EB000032 bl 0D4h
00000008 E6D6000B ldrb r0, [r6], r11
0000000C E3510000 cmp r10
00000010 0A000004 beq 28h
00000014 E3A0B004 mov r114
00000018 EB00002D bl 0D4h
0000001C E08700FB strd r0, [r7], r11
00000020 E051100B subs r1r1r11
00000024 1AFFFFFC bne 1Ch
00000028 E3A0B002 mov r112
0000002C EB000028 bl 0D4h
00000030 E097C0BB ldrh r12, [r7], r11
00000034 E150000C cmp r0r12
00000038 E3A0B004 mov r114
0000003C EB000024 bl 0D4h
00000040 E087C0DB ldrd r12, [r7], r11
00000044 E086A0DB ldrd r10, [r6], r11
00000048 E15C000A cmp r12r10
0000004C E3A0B001 mov r111
00000050 EB00001F bl 0D4h
00000054 E6D6000B ldrb r0, [r6], r11
00000058 E6C7000B strb r0, [r7], r11
0000005C E3A0B004 mov r114
00000060 EB00001B bl 0D4h
00000064 E08700FB strd r0, [r7], r11
00000068 E3510000 cmp r10
0000006C 0A000006 beq 8Ch
00000070 E3A0B002 mov r112
00000074 EB000016 bl 0D4h
00000078 E097C0BB ldrh r12, [r7], r11
0000007C E150000C cmp r0r12
00000080 1A000001 bne 8Ch
00000084 E051100B subs r1r1r11
00000088 1AFFFFFA bne 78h
0000008C E3510000 cmp r10
00000090 0A000005 beq 0ACh
00000094 E3A0B001 mov r111
00000098 EB00000D bl 0D4h
0000009C E6D6000B ldrb r0, [r6], r11
000000A0 E6C7000B strb r0, [r7], r11
000000A4 E051100B subs r1r1r11
000000A8 1AFFFFFB bne 9Ch
000000AC E3510000 cmp r10
000000B0 0A000007 beq 0D4h
000000B4 E3A0B001 mov r111
000000B8 EB000005 bl 0D4h
000000BC E6D7C00B ldrb r12, [r7], r11
000000C0 E6D6A00B ldrb r10, [r6], r11
000000C4 E15C000A cmp r12r10
000000C8 1A000001 bne 0D4h
000000CC E051100B subs r1r1r11
000000D0 1AFFFFF9 bne 0BCh
000000D4 E92D5000 stmdb sp!, {r12,lr}
000000D8 E0010B91 mul r1r1r11
000000DC E3A0C077 mov r1277h
000000E0 E59CC000 ldr r12, [r12]
000000E4 E39CCB01 orrs r12r12400h
000000E8 126BB000 rsbne r11r110
000000EC 12611000 rsbne r1r10
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 r0r0 }
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 r1 }
macro dec r { subs r1 }

;;;;;;;;;;;;;;;;;; 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 literalsdw x
 literals.i=literals.i+4
}

; store literal table or initialize

macro .literals {
 local ..literals
 ?LITERALS \          ; address
  equ ..literals
 match jliterals \{ ; expand into a,b,c
  irp ij \\{        ; 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 ri {
 i=i and 0FFFFh
 movw ri         ; low 16BIT
 i=(i shr 16) \
  and 0FFFFh
 if i<>0           ; high 16BIT?
  movt ri
 end if
}

; generic move 32BIT immediate (worst
; case scenerio)

macro movi ri {
 local n
 n=i and 0FFh
 mov rn             ; mov r, b&FFh
 n=(i and 0FF00h)
 if n<>0              ; if 16+BIT...
  orr rn            ; orr r, r, b&FF00h
 end if
 n=(i and 0FF0000h)
 if n<>0
  orr rn            ; orr r, r, b&FF0000h
 end if
 n=(i and 0FF000000h)
 if n<>0
  orr rn            ; 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 ix
  define ?s 0
  match r=, &np \{      ; ldr r, &i
   x=(?LITERALS+\         ; PC relative
    literals.i)-$-8+4     ; address
   ldr r, [pcx]         ; 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 ri
   else if use.movwt?     ; use movw/movt?
    movwt ri            ; CPU>=ARM.v6T2
   else                   ; worst case
    movi ri             ; 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 rx {
 define ?s 0
 match \
  [a], x \{
  match \
   [b+i], x \\{
   match \
    I*Si \\\{              ; [a+b*c]
    if S eq 4
     ldr r, [bIlsl 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, [bi]
    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, [@ri]
    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 rx
  else                       ; i
   ldr r, =x
  end if
 end if
}

macro @set xr {
 define ?s 0
 match \
  [a], x \{
  match \
   [b+i], x \\{
   match \
    I*Si \\\{              ; [a+b*c]
    if S eq 4
     str r, [bIlsl 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, [bi]
    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, [@ri]
    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 @drr
   mov [m], @dr
   define ?s 1
  \}
  if ?s eq 0
   name p
  end if
}

macro and [p] { common @dp andsp }
macro eor [p] { common @dp eorsp }
macro sub [p] { common @dp subsp }
macro rsb [p] { common @dp rsbsp }
macro add [p] { common @dp addsp }
macro adc [p] { common @dp adcsp }
macro sbc [p] { common @dp sbcsp }
macro rsc [p] { common @dp rscsp }
macro tst [p] { common @dp tstp }
macro teq [p] { common @dp teqp }
macro cmp [p] { common @dp cmpp }
macro cmn [p] { common @dp cmnp }
macro bic [p] { common @dp bicsp }
macro mvn [p] { common @dp mvnp }

; 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 r10FLAG.#f
 mov [@flags], r10
 pop r10
}

macro @zero.flag f {
 push r10-r11
 mov r10, [@flags]
 mvn r11FLAG.#f
 and r10r11
 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 r11s
 call _string.a
}

; load/store/etc

macro @string.x namer {
 name r0, [r], r11
}

macro @string.s namers {
 @string.a s
 @string.x namer
}

macro lods [p] {
 common
  define ?s 0
  match type [=esi], p \{
   if type eq byte
    @string.s ldrbr61
   else if type eq word
    @string.s ldrhr62
   else if type eq dword
    @string.s ldrdr64
   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 strbr71
   else if type eq word
    @string.s strhr72
   else if type eq dword
    @string.s strdr74
   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 r0r12
   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 r12r10
   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..en
  n=0
  cmp r10
  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 ldrbr6
     @string.x strbr7
    else if type eq word
     @string.x ldrhr6
     @string.x strhr7
    else if type eq dword
     @string.x ldrdr6
     @string.x strdr7
    end if
    subs r1r11
    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 r12r10
    jne ..e
    subs r1r11
    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 ldrbr6
    else if n=2
     @string.x ldrhr6
    else if n=4
     @string.x ldrdr6
    end if
    subs r1r11
    jnz ..s

   else if name eq stos
    if ~a eq edi
     'Error' a
    end if
    if n=1
     @string.x strbr7
    else if n=2
     @string.x strhr7
    else if n=4
     @string.x strdr7
    end if
    subs r1r11
    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 r0r12
    jne ..e
    subs r1r11
    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: 15096
Location: The Unicomplex
"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
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

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: 15096
Location: The Unicomplex

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


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.