flat assembler
Message board for the users of flat assembler.

Index > Windows > Traversing a string

Author
Thread Post new topic Reply to topic
TmX



Joined: 02 Mar 2006
Posts: 841
Location: Jakarta, Indonesia
TmX 18 Jul 2011, 07:35
I have a string "Hello world", and I want to print each element per line.

Code:
format PE console 4.0

include 'win32a.inc'

entry start

section '.data' data readable
myStr db "Hello world", 0
fmt db "%s\n",0

section '.code' readable executable
start:
      mov ecx, 0
  repeat 10
           mov eax, [myStr+ ecx] 
              cinvoke printf, fmt, eax
            inc ecx
     end repeat
  invoke ExitProcess,0

section '.idata' data import readable writeable
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll'
import kernel32,ExitProcess,'ExitProcess'
import msvcrt,printf,'printf'    


The error message says:
Quote:

mov eax, [myStr+ ecx]
error: operand sizes do not match.


Any idea? Question
Post 18 Jul 2011, 07:35
View user's profile Send private message Reply with quote
ouadji



Joined: 24 Dec 2008
Posts: 1081
Location: Belgium
ouadji 18 Jul 2011, 07:43
Code:
;eax == dword ... [myStr+ecx] == byte (because: byte *myStr)

;dword != byte => operand sizes do not match

movzx eax,[myStr+ecx]
    

_________________
I am not young enough to know everything (Oscar Wilde)- Image
Post 18 Jul 2011, 07:43
View user's profile Send private message Send e-mail Reply with quote
TmX



Joined: 02 Mar 2006
Posts: 841
Location: Jakarta, Indonesia
TmX 18 Jul 2011, 08:23
Now it compiles, but crashes Confused
Post 18 Jul 2011, 08:23
View user's profile Send private message Reply with quote
bitshifter



Joined: 04 Dec 2007
Posts: 796
Location: Massachusetts, USA
bitshifter 18 Jul 2011, 08:40
I am guessing ECX is getting trashed by printf since it is not an ABI protected register.
Try using EBX or some other protected one...
Also "%s" is to print string but you want to print char "%c" or just use putchar instead if you like...

EDIT: Is this what your trying to do?
Code:
format PE console 4.0

include 'win32a.inc' 

entry start 

section '.data' data readable 
myStr db "Hello world", 0 
fmt db "%c",13,10,0

section '.code' readable executable 
start: 
        mov ebx, 0
        repeat 11
                mov eax, dword[myStr+ ebx]
                cinvoke printf, fmt, eax
                inc ebx
        end repeat
        invoke getchar
        invoke ExitProcess,0 

section '.idata' data import readable writeable 
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll' 
import kernel32,ExitProcess,'ExitProcess' 
import msvcrt,printf,'printf',getchar,'getchar'
    


Last edited by bitshifter on 20 Jul 2011, 07:44; edited 1 time in total
Post 18 Jul 2011, 08:40
View user's profile Send private message Reply with quote
ouadji



Joined: 24 Dec 2008
Posts: 1081
Location: Belgium
ouadji 18 Jul 2011, 11:12
Code:
start:  mov esi,myStr
        repeat 11
          lodsb
          cinvoke printf, fmt, eax
        end repeat
        invoke getchar
        invoke ExitProcess,0

start:  mov esi,myStr
@@:     lodsb
        or al,al
        jz @F
        cinvoke printf, fmt, eax
        jmp @B
@@:     invoke getchar
        invoke ExitProcess,0
    

_________________
I am not young enough to know everything (Oscar Wilde)- Image
Post 18 Jul 2011, 11:12
View user's profile Send private message Send e-mail Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 18 Jul 2011, 12:12
wtf is that?
Code:
myStr db "Hello world", 0
fmt db "%s\n",0 ;maybe db 13,10 can be cool!!!

section '.code' readable executable
start:
        mov ecx, 0 
        repeat 10   
                mov eax, [myStr+ ecx] 
                cinvoke printf, fmt, eax
                inc ecx 
        end repeat ;jmp can do that
        invoke ExitProcess,0 
    


i think it can be good to do it with a string reconstruction, and cinvoke only one time.

then, use a data buffer somewhere to compose the string to write (pick elements of string1, and interlace with repetitions of fmt.
then, the result would be a string like that:
Quote:

H
e
l
l
o

W
o
r
l
d

and will be possible to save as a text file, directlly useable anywhere.


something like this:
Code:
str db "Hello world", 0
fmt db 13,10,0
alotofbytes=35793 ;a random value chosen for its sound in french Laughing
new rb alotofbytes ;i'd prefer something like ES dynamic ram allocation, and more like proposed by our friends, using string instrucitons Smile.

section '.code' readable executable
start:
        call buildstring 
        cinvoke printf,new ;print the constructed string
        invoke ExitProcess,0 

;;;;;;;;;;;;;;;;;
buildstring:
        push es ds 
        pop es
        mov esi,str
        mov edi,new
@@:
        lodsb
        or al,al
        je @f
        stosb
        call .interlace
        jmp @b
@@:
        stosb ;end the string with 0
        pop es
        ret
;;;;;;;;;;;;;;;;;;
.interlace:
        mov eax,[fmt];load and insert the crlf sequence
        stosb ;just to don't use the 16 bit instruction stosw
        xchg al,ah ;use only 32 or 8 bits instructions
        stosb ;3 instructions instead of just two
        ret
    
Post 18 Jul 2011, 12:12
View user's profile Send private message Visit poster's website Reply with quote
ouadji



Joined: 24 Dec 2008
Posts: 1081
Location: Belgium
ouadji 18 Jul 2011, 12:44
Quote:

don't use the 16 bit instruction stosw
why ?
Code:
fmt dw 0x0A0D

buildstring:
        push es ds 
        pop es
        mov esi,str
        mov edi,new

@@:     lodsb
        or al,al
        jz @F
        stosb
        mov ax,[fmt]
        stosw
        jmp @B

@@:     stosb
        pop es
        ret 
    

_________________
I am not young enough to know everything (Oscar Wilde)- Image
Post 18 Jul 2011, 12:44
View user's profile Send private message Send e-mail Reply with quote
asmMe



Joined: 14 Jun 2011
Posts: 18
asmMe 18 Jul 2011, 12:52
here's a 29 byte buildstring

Code:
buildstring:
        push    es ds
        pop     es
        mov     esi, myStr
        mov     edi, new
        mov     eax, 0x000A0D00      
    @@:
        lodsb
        or      al, al
        jz      @f
        stosd                                    ;stores byte + CR\LF in one go
        dec     edi
        jmp     @b
    @@:                                          ;terminating 0 already written
        pop es
        ret
    
Post 18 Jul 2011, 12:52
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 18 Jul 2011, 13:03
in fact, as mbr-tsr first coded, he want fmt to be "%s/n", then, only mov eax,dword[fmt] and stosd are needed in the buildstring.interlace subroutine.

i tested the code, the problem seems to be the ES segment parts.
maybe we should do it with only the DS segment.
Post 18 Jul 2011, 13:03
View user's profile Send private message Visit poster's website Reply with quote
ouadji



Joined: 24 Dec 2008
Posts: 1081
Location: Belgium
ouadji 18 Jul 2011, 13:23

28 bytes Razz

Code:
buildstring:
        push    es ds
        pop     es
        mov     esi,mystr
        mov     edi,new
        mov     eax,0x000A0D00

@@:     lodsb
        stosd
        dec     edi
        cmp     byte[esi],0
        jne     @B

        pop es
        retd
    

_________________
I am not young enough to know everything (Oscar Wilde)- Image
Post 18 Jul 2011, 13:23
View user's profile Send private message Send e-mail Reply with quote
ctl3d32



Joined: 30 Dec 2009
Posts: 206
Location: Brazil
ctl3d32 18 Jul 2011, 13:25
Let me have some fun too:
Code:
format PE console 4.0
entry start

include 'win32a.inc'

HEAP_CREATE_ENABLE_EXECUTE = 0x00040000

section '.bss' readable writeable

  hHeap      dd ?
  hBuffer    dd ?
  BufferSize dd ?

section '.data' data readable 

  myStr   db 'Hello world',0
  fmt     db '%s',0

section '.code' readable executable 

  start:

        stdcall GetBufferNeededSize,myStr
        mov     [BufferSize],eax
        invoke  HeapCreate,HEAP_CREATE_ENABLE_EXECUTE,[BufferSize],512
        mov     [hHeap],eax
        invoke  HeapAlloc,[hHeap],HEAP_ZERO_MEMORY,[BufferSize]
        mov     [hBuffer],eax
        stdcall StringTransverse,[hBuffer],myStr

        cinvoke printf,fmt,[hBuffer]

        invoke  getchar
        invoke  ExitProcess,0

proc StrGetLength uses ecx edi,szString
        ;GET STRING LENGTH INCLUDING NULL TERMINATOR
        xor     eax,eax
        mov     ecx,0xffffffff
        mov     edi,[szString]
        repne   scasb
        not     ecx
        mov     eax,ecx
        ret
endp

proc GetBufferNeededSize uses ebx,szString
        ;GET SIZE OF BUFFER TO BE RESERVED
        stdcall StrGetLength,[szString]
        dec     eax
        mov     ebx,3
        mul     ebx
        inc     eax
        ret
endp

proc StringTransverse uses ebx ecx,Buffer,szString
        ;TRANSVERSE THE STRING
        mov     esi,[szString]
        mov     ebx,[Buffer]
        xor     ecx,ecx
     @@:
        lodsb
        test    al,al
        je      .finish
        mov     byte[ebx+ecx],al
        mov     word[ebx+ecx+1],0x0A0D ;CRLF
        add     ecx,3
        jmp     @b
  .finish:
        ret
endp

section '.idata' data import readable writeable 

  library kernel32,'kernel32.dll',\
          msvcrt,'msvcrt.dll'

  include 'api\kernel32.inc'

  import msvcrt,\
         printf,'printf',\
         getchar,'getchar'
    


Last edited by ctl3d32 on 18 Jul 2011, 15:11; edited 1 time in total
Post 18 Jul 2011, 13:25
View user's profile Send private message Reply with quote
TmX



Joined: 02 Mar 2006
Posts: 841
Location: Jakarta, Indonesia
TmX 18 Jul 2011, 15:10
edfed wrote:
wtf is that?
Code:
myStr db "Hello world", 0
fmt db "%s\n",0 ;maybe db 13,10 can be cool!!!

section '.code' readable executable
start:
        mov ecx, 0 
        repeat 10   
                mov eax, [myStr+ ecx] 
                cinvoke printf, fmt, eax
                inc ecx 
        end repeat ;jmp can do that
        invoke ExitProcess,0 
    


i think it can be good to do it with a string reconstruction, and cinvoke only one time.

then, use a data buffer somewhere to compose the string to write (pick elements of string1, and interlace with repetitions of fmt.
then, the result would be a string like that:
Quote:

H
e
l
l
o

W
o
r
l
d

and will be possible to save as a text file, directlly useable anywhere.


something like this:
Code:
str db "Hello world", 0
fmt db 13,10,0
alotofbytes=35793 ;a random value chosen for its sound in french Laughing
new rb alotofbytes ;i'd prefer something like ES dynamic ram allocation, and more like proposed by our friends, using string instrucitons Smile.

section '.code' readable executable
start:
        call buildstring 
        cinvoke printf,new ;print the constructed string
        invoke ExitProcess,0 

;;;;;;;;;;;;;;;;;
buildstring:
        push es ds 
        pop es
        mov esi,str
        mov edi,new
@@:
        lodsb
        or al,al
        je @f
        stosb
        call .interlace
        jmp @b
@@:
        stosb ;end the string with 0
        pop es
        ret
;;;;;;;;;;;;;;;;;;
.interlace:
        mov eax,[fmt];load and insert the crlf sequence
        stosb ;just to don't use the 16 bit instruction stosw
        xchg al,ah ;use only 32 or 8 bits instructions
        stosb ;3 instructions instead of just two
        ret
    


Please bear with me. My background are HLLs like C or Java, and I'm still not used to 'think' in assembly yet Embarassed
Post 18 Jul 2011, 15:10
View user's profile Send private message Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4624
Location: Argentina
LocoDelAssembly 18 Jul 2011, 15:23
Code:
format PE console 4.0

include 'win32a.inc'

entry start

section '.data' data readable
myStr db "Hello world", 0
fmt db "%c", 10, 0

section '.code' readable executable
start:
        mov ebx, 0
        repeat 11
                mov al, [myStr+ ebx]
                cinvoke printf, fmt, eax
                inc ebx
        end repeat
        cinvoke getchar
        invoke ExitProcess,0

section '.idata' data import readable writeable
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll'
import kernel32,ExitProcess,'ExitProcess'
import msvcrt,printf,'printf', getchar, 'getchar'    
Notice that I've changed the fmt string since "%s" expects a pointer to string, not a char. Also "\n" does not actually exists, C compilers change it to character 10 before writing the string to the executable ("13, 10" is used by Windows API but it is not needed when using functions from msvcrt.dll).

Note however, that "repeat" is not a run-time thing, you are expanding the same code 11 times so you could have used this to not use a register for counting:
Code:
start:
        repeat 11
                mov     al, [myStr+ % - 1]
                cinvoke printf, fmt, eax  ; Don't worry, printf will only use the lower byte of the dword
        end repeat
        cinvoke getchar
        invoke ExitProcess,0    

But I'd do this way:
Code:
format PE console 4.0

include 'win32a.inc'

entry start

section '.data' data readable
myStr db "Hello world", 0
myStr.sizeof = $ - myStr
fmt db "%c", 10, 0

section '.code' readable executable
start:

        mov     ebx, -myStr.sizeof ; Other options are ESI, EDI, EBP, the rest of the registers can't be used because they are destroyed when printf returns
print:
        mov     al, [myStr + myStr.sizeof + ebx]
        cinvoke printf, fmt, eax  ; Don't worry, printf will only use the lower byte of the dword
        inc     ebx
        jnz     print

        cinvoke getchar ; Just to wait freeze the console until <enter> is pressed
        invoke ExitProcess,0

section '.idata' data import readable writeable
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll'
import kernel32,ExitProcess,'ExitProcess'
import msvcrt,printf,'printf', getchar, 'getchar'    
Post 18 Jul 2011, 15:23
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4330
Location: Now
edfed 18 Jul 2011, 15:49
using the solution of ouadji, and deleting the push and pops, i have this result:
Code:
use32
mystr equ 0
new equ 0
buildstring:
        mov edi,new
        mov esi,mystr
        mov eax,000a0d00h
@@:
        lodsb
        stosd
        dec edi
        or al,al
        jne @b
        ret
                      
    

and it compiles in 23 bytes

and in a fun test code, i have this:
Code:
format PE console 4.0

include 'c:/fasmw/include/win32a.inc'

entry start

section '.data' data readable writable
exitdelay dd 800
spacetimes dd 0
.inc dd 8
.style dd "+-><"
mystr db  " Hell","o wo","rld",0
fmt db 13,10
alotofbytes=35793 ;a random value chosen for its sound in french Laughing
new rb alotofbytes ;i'd prefer something like ES dynamic ram allocation, and more like proposed by our friends, using string instrucitons Smile.
db 0
section '.code' readable executable
start:
@@:
        call buildstring
        cinvoke printf,new ;print the constructed string
        call pong
        dec [exitdelay]
        jne @b
        invoke ExitProcess,0
;;;;;;;;;;;;;;;;;;;
pong:
        mov eax,[spacetimes.inc]
        add [spacetimes],eax
        jl .neg
        cmp [spacetimes],59
        jl .ok
.neg:
        neg [spacetimes.inc]
        sub [spacetimes],eax
.ok:
        ret
;;;;;;;;;;;;;;;;;;
buildstring:
        mov edi,new
        mov esi,mystr
        mov eax,000a0d00h
@@:
        lodsb
        stosd
        dec edi
        call .spaces
        or al,al
        jne @b
;        call .spaces
        ret
;;;;;;;;;;;;;;;;;;;
.spaces:
        push eax
        ror dword[spacetimes.style],8
        mov al,byte[spacetimes.style]
        mov ecx,[spacetimes]
        cmp ecx,0
        jle @f
        rep stosb
@@:
        pop eax
        ret
;;;;;;;;;;;;;;;;;;
section '.idata' data import readable writeable
library kernel32,'kernel32.dll',msvcrt,'msvcrt.dll'
import kernel32,ExitProcess,'ExitProcess'
import msvcrt,printf,'printf'
    

that outputs that:
Quote:

Code:
++++++++++++++++++++++++H
------------------------e
>>>>>>>>>>>>>>>>>>>>>>>>l
<<<<<<<<<<<<<<<<<<<<<<<<l
++++++++++++++++++++++++o
------------------------
>>>>>>>>>>>>>>>>>>>>>>>>w
<<<<<<<<<<<<<<<<<<<<<<<<o
++++++++++++++++++++++++r
------------------------l
>>>>>>>>>>>>>>>>>>>>>>>>d
<<<<<<<<<<<<<<<<<<<<<<<<
--------------------------------H
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>e
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<l
++++++++++++++++++++++++++++++++l
--------------------------------o
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<w
++++++++++++++++++++++++++++++++o
--------------------------------r
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>l
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<d
++++++++++++++++++++++++++++++++
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>H
    

Post 18 Jul 2011, 15:49
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.