Reputation: 55
I was trying to solve this problem for a few days. I have no idea how to allocate memory to copy string into another location. Here's the code:
caesarAsm proc string: DWORD, key: DWORD, stringLength : DWORD ; inside this procedure I have a code that ciphers string value using caesar cipher mov eax, string ret caesarAsm endp
Then in CPP file when I use the function:
caesar1(word, 13, strlen(word))
It changes the value of word as is was passed by reference. I want it to do nothing until I'll do:
word = caesar1(word, 13, strlen(word))
I was been trying to solve this problem searching all over the Internet, but I found nothing helpful. I guess that solution is simple, but I cannot find it. I was trying to do sth with ESI and EDI registers. I guess I have to allocate new memory then copy the string into this allocated location. How to do it?
Upvotes: 0
Views: 6277
Reputation: 84652
Following from the discussion in the comments, the basic approach to copy a string is to declare a label in .bss and reserve the number of bytes required to hold the copy of the string. This is using intel syntax as I do not have MASM available. As an example, you can declare your original string in .data. e.g.:
section .data
str_str1 db 'string one to copy', 0
section .bss
str_str2 resb 19
For the copy, load the address of str_str1
into esi
and the address of str_str2
in edi
. Load the number of characters to copy in cx
and then call rep movsb
to move the number of bytes specified in cx
from esi
to edi
. e.g.:
section .text
global _start
_start:
xor ecx, ecx ; clear ecx
cld ; clear direction flag (read L->R)
lea esi, [str_str1] ; load str1 in esi
lea edi, [str_str2] ; load str2 in edi
mov cx, 19 ; move 19 into cx for repeat
rep movsb ; move 19 bytes from str1 -> str2
exit:
xor edi, edi ; set zero exit code
mov eax, 1 ; set int 0x80 number to 60 (0x3c hex)
int 0x80 ; call kernel
That will copy str_str
to str_str2
. You can then add the code to print them, etc. Nasm offers a simple macro language to help with repetitive tasks like read calls and write calls (especially for indents, spacing, printing, etc) The complete example in nasm syntax is:
; Following macros simply print indents, newlines and strings to stdout
%macro indent 1
mov eax, 4
mov ebx, 1
mov ecx, tab
mov edx, %1
int 0x80
%endmacro
%macro newlns 1
mov eax, 4
mov ebx, 1
mov ecx, onln
mov edx, %1
int 0x80
%endmacro
; strn (string const) macro is overloaded to take 1 or 2 args
%macro strn 1
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, 1
int 0x80
%endmacro
%macro strn 2
mov eax, 4
mov ebx, 1
mov ecx, %1
mov edx, %2
int 0x80
%endmacro
section .data
nwln db 0xa
dnln db 0xa,0xa
onln times 8 db 0xa ; 8 newlines
tab times 8 db 0x20 ; 8 spaces
msg_str1 db 0xa, ' string_1: '
msg_str2 db 0xa, ' string_2: '
str_str1 db 'string one to copy', 0
section .bss
str_str2 resb 19
section .text
global _start
_start:
xor ecx, ecx ; clear ecx
cld ; clear direction flag (read L->R)
lea esi, [str_str1] ; load str1 in esi
lea edi, [str_str2] ; load str2 in edi
mov cx, 19 ; move 19 into cx for repeat
rep movsb ; move 19 bytes from str1 -> str2
; macros to print results & add newlines
strn msg_str1, 13 ; print str1 msg
strn str_str1, 19 ; print str1
strn msg_str2, 13 ; print str2 msg
strn str_str2, 19 ; print str2
newlns 2 ; print 2 newlines
exit:
xor edi, edi ; set zero exit code
mov eax, 1 ; set int 0x80
int 0x80 ; call kernel
Nasm compile/link
nasm -f elf -o obj/str_cpy_32.o str_cpy_32.asm
ld -m elf_i386 -o bin/str_cpy_32 obj/str_cpy_32.o
Output
$ ./bin/str_cpy_32
string_1: string one to copy
string_2: string one to copy
Look at the MASM syntax differences and make the needed changes. There should be no reason you shouldn't be able to accomplish the exact same thing.
Determining String Size - 32-bit
As discussed, to determine the length of an unknown string, the string itself must be null-terminated to provide an end sentinel character to test. The string address is placed in edi
and then you effectively check each character for zero (numeric zero, not character zero) and the length is determined by the number of iterations it takes to reach the null-terminating character:
; szstr computes the length of a string.
; edi - string address
; edx - contains string length (returned)
section .text
strsz:
xor ecx, ecx ; zero rcx
not ecx ; set rcx = -1 (uses bitwise id: ~x = -x-1)
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec ecx through NUL)
not ecx ; rev all bits of negative -> absolute value
dec ecx ; -1 to skip the null-term, ecx contains length
mov edx, ecx ; size returned in edx, ready to call write
ret
Of course, you do not have to use it as a function, you can just put the code in the body of your assembly program, but since it is something you use often, it helps to use it as a function.
Upvotes: 1