user1678401
user1678401

Reputation: 55

Assembler memory allocation

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

Answers (1)

David C. Rankin
David C. Rankin

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

Related Questions