I'm really more than a novice to assembler and I'd need some help in doing a simple thing: having in ecx and edx respectively the starting address of a null terminated string to be copied and the first byte of the area where to copy it, how can I accomplish the copy???

Posted on 2003-02-16 09:15:32 by yaa
If what you mean is you have the address of one string in ecx, and the address of another string in edx, and you want to copy both strings to another buffer then do something like this...
push edx [color=green]; lstrcpy will mess up edx so we perserve it[/color]

invoke lstrcpy, pszDestination, ecx
pop edx [color=green]; restore edx[/color]
invoke lstrcat, pszDestination, edx [color=green]; notice we use lstrcat, not lstrcpy[/color]

if you mean you want to copy whatever string is pointed to by ecx, to edx then do this...

invoke lstrcpy, edx, ecx
Posted on 2003-02-16 09:19:50 by BubbaFate
BubbaFate I have the string to be copied in ecx and memory area where to copy it in edx. The string to be copied is null terminated. As said I simply need to copy the string (starting address in ecx) to a memory area (starting address in edx) stopping when the first null char is reached.

Posted on 2003-02-16 09:24:06 by yaa
ya, i edited my post =)
Posted on 2003-02-16 09:44:22 by BubbaFate
Thx BubbaFate. It was so simple.
Wanting to use the STOSB instruction or another assembly instruction (no C function or win32 API) how could it be done?
Thank you again.

Posted on 2003-02-16 09:52:29 by yaa
i think you can do something like this...
    mov   edi, ecx ; load destination register with pointer to destination string

mov esi, edx ; load source register with pointer to source string
@@: lodsb ; copy byte pointed to by esi to al, and increment esi
stosb ; copy al to byte pointed to by edi, and increment edi
test al,al ; did we just copy a null char?
jnz @B ; if not copy the next char

I'm no optimization genie, but i think the lodsb/stosb instructions are slower than just copying the string yourself.
Posted on 2003-02-16 10:32:52 by BubbaFate
Not the fastest, but a small version:

s1 is the address of the string to copy, s2 is the destination address.

lea esi, [s1]
lea edi, [s2]
repnz movsb

if you use ecx and edx for the addresses of the source and dest.

mov esi, ecx
mov edi, edx
repnz movsb
Posted on 2003-02-17 06:04:11 by DarkEmpire
Optimized for 32 bit. Expects Source in esi and Destination in edi

Posted on 2003-02-17 07:34:17 by pelaillo
pelaillo I don't know if I ask for too much, but I'd appreciate if you could explain the code that you posted. I love to understand things and your code is by far too complex for my poor knowledge of the assemlby language.


Posted on 2003-02-17 08:48:38 by yaa
Hi yaa,
The code takes four bytes from the memory location pointed by esi and copy them to the location pointed by edi.
Being copied four by four, the problem is to know where the zero terminator is located.
The binary trick to locate one byte zero in a dword is taken from an Agner Fog's strlen function (AFAIK).

see yaa ;)
Posted on 2003-02-17 11:18:49 by pelaillo
pelaillo could you just explain the meaning of the following two lines?

lea edx,

and eax,80808080h


Posted on 2003-02-17 14:52:52 by yaa
This is how I look at it...

For explanation purposes im using the string [color=blue]"?ou", 0[/color] (you'll see why i used that strange character later)

Basically the function is loading 4 bytes of a string into a register... so in that register the data looks like this...

eax = 00[b]75[/b]6F[b]FF[/b]
^ ^ ^ ^
0 u o ?

Now we need to determine if a null character is in the register (in this case there is)

First thing we do is subtract 1 from each character code.

eax = 00756FFF
^ ^
|-----|--bit 8 set for the null char and ?

What does this accomplish? Well if the character code is any number between 81h - 0h then bit 8 will be set...
here is a breakout

80h - 1 = 7F = [color=red]0[/color]111 1111 <-- bit 8 not set for numbers below 81h
81h - 1 = 80 = [color=red]1[/color]000 0000
82h - 1 = 81 = [color=red]1[/color]000 0001
FFh - 1 = FE = [color=red]1[/color]111 1110
00h - 1 = FF = [color=red]1[/color]111 1111 <-- this case is whats special, if char = 0 then bit 8 = set
01h - 1 = 00 = [color=red]0[/color]000 0000 <-- bit 8 not set for numbers above 0

Now we can test for bit 8 and determine if any of the characters were 81h - 0h, but thats not enough. We need
to be able to test for 0h only.

Secondly we xor what we had before with what we got aftwards.

eax = FF746EFE
^00756FFF <-- org value stored in edx
|-- bit 8 set

Ok, forget about every bit but bit 8. Remember before that if you subtract 1 from any number between 81h - 0h
bit 8 is set? Well of the numbers 81h - 0h the only number where bit 8 is not set is the number 0...

81h = [color=red]1[/color]000 0001 <-- bit 8 set
82h = [color=red]1[/color]000 0010 <-- bit 8 set
FFh = [color=red]1[/color]111 1111 <-- bit 8 set
00h = [color=red]0[/color]000 0000 <-- bit 8 not set, special case !! only number where bit 8 is not set

So, what does xor mean? It means only keep a bit if its set on one operand and not set on the other...

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

Now when you put it all together...
eax - 1 = bit 8 set if character code is 81h - 0h
xor eax, edx = in edx (which is prev eax value) bit 8 is not set for character codes 0h-79h, so when you xor
these two registers bit 8 will be different for a character code only when that character code is 0...

bit bit
8 8
set not
--- ---
00h 00h = 0 is the only number that doesn't have bit 8 set, but after subtracting 1 it does.

So back to our example...

We and whatever value we come up with in eax with 80808080h (80 = 1000 0000, aka only bit 8 set)

eax = FF010101

So you see bit 8 is set ONLY when a null character was in eax, this is because 0 is the only number where
bit 8 is not set, but when you subtract 1 it is set.

Now the jz instruction falls through because eax is not zero.

Set up multiple examples, and then step through the code with a debugger... its a lot easier to understand
when you actually see it happen.
Posted on 2003-02-17 16:37:33 by BubbaFate
Ahhhhhhhh :eek: :eek: :eek:

I shouldn't have asked. Thx BubbaFate. :alright:

Posted on 2003-02-17 16:44:01 by yaa

Optimized for 32 bit. Expects Source in esi and Destination in edi

Posted on 2003-02-17 16:54:12 by The Svin
For PPro, PII and PIII we have:

Align 16
[B]00403160[/B] 8B 06 mov eax, dword ptr [esi] ;D0
00403162 83 C6 04 add esi,4 ;D1
00403165 89 07 mov dword ptr [edi],eax ;D0
00403167 8D 90 FF FE FE FE lea edx,[eax-1010101h] ;D1
0040316D 83 C7 04 add edi,4 ;D0
[B]00403170[/B] 33 C2 xor eax,edx ;[B]D0[/B] rather then D1
00403172 25 80 80 80 80 and eax,80808080h ;D0
00403177 74 E7 je sz_copy(403160h) ;D1
00403179 23 C2 and eax,edx ;D0
0040317B 74 E3 je sz_copy(403160h) ;D1
0040317D C3 ret

See my note here:http://www.asmcommunity.net/board/showthread.php?threadid=10792&perpage=15&pagenumber=2

Posted on 2003-02-17 18:37:04 by lingo12
Thanks The Svin and Lingo12 :alright:

This is a great board !
Posted on 2003-02-18 11:53:26 by pelaillo