【问题标题】:Assembler memory allocation汇编程序内存分配
【发布时间】:2016-01-30 15:34:37
【问题描述】:

我试图解决这个问题几天。我不知道如何分配内存以将字符串复制到另一个位置。代码如下:

caesarAsm proc 字符串:DWORD,键:DWORD,stringLength:DWORD ;在这个过程中,我有一个使用凯撒密码加密字符串值的代码 mov eax, 字符串 ret caesarAsm endp

然后在我使用该功能时的CPP文件中:

caesar1(word, 13, strlen(word))

它改变了 word 的值,因为它是通过引用传递的。在我做之前,我希望它什么都不做:

word = caesar1(word, 13, strlen(word))

我一直在尝试解决这个问题,在整个 Internet 上搜索,但没有发现任何帮助。我想这个解决方案很简单,但我找不到它。我试图用 ESI 和 EDI 寄存器做某事。 我想我必须分配新内存然后将字符串复制到这个分配的位置。怎么做?

【问题讨论】:

  • 使用Windows提供的one of the memory allocation functions
  • 我试过了。这些功能中没有一个对我有用(或者我不知道如何使用它们)。
  • 一般情况下,要么使用C runtime提供的功能,要么使用相关的系统调用。
  • 难道不能用 x86 汇编函数来实现吗?
  • 一般情况下,.bss 部分会保留内存来保存复制的字符串。 (例如str2 resb 19 在标签str2 下保留19 个字节的内存)然后您将第一个字符串的地址加载到esi 和您的目标字符串在edi 并使用rep movsb 从源复制到目标.

标签: memory assembly masm


【解决方案1】:

根据 cmets 中的讨论,复制字符串的基本方法是在 .bss 中声明标签并保留保存字符串副本所需的字节数。这是使用英特尔语法,因为我没有可用的 MASM。例如,您可以在 .data 中声明您的原始字符串。例如:

section .data
    str_str1 db 'string one to copy', 0

section .bss
    str_str2 resb 19

对于副本,将str_str1的地址加载到esi中,将str_str2的地址加载到edi中。在cx 中加载要复制的字符数,然后调用rep movsbcx 中指定的字节数从esi 移动到edi。例如:

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

这会将str_str 复制到str_str2。然后您可以添加代码以打印它们等。Nasm 提供了一种简单的宏语言来帮助执行重复性任务,例如读取调用和写入调用(尤其是缩进、间距、打印等) nasm 语法中的完整示例是:

; 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 编译/链接

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

输出

$ ./bin/str_cpy_32

  string_1: string one to copy
  string_2: string one to copy

查看 MASM 语法差异并进行必要的更改。你应该没有理由不能完成完全相同的事情。

确定字符串大小 - 32 位

如前所述,要确定未知字符串的长度,字符串本身必须以空字符结尾,以提供要测试的结束标记字符。字符串地址放置在edi 中,然后您有效地检查每个字符是否为零(数字零,而不是字符零),长度取决于到达空终止字符所需的迭代次数:

; 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

当然,您不必将其用作函数,您可以将代码放在汇编程序的主体中,但由于它是您经常使用的东西,因此将其用作函数会有所帮助。

【讨论】:

  • 我在 .data 部分找到了可以使用 DW 为文本创建位置的信息。但是当我开始程序时,我不知道我的字符串的长度。如何从 proc caesarAsm 中获取它?我可以使用可变长度在过程中分配内存吗?
  • 对于未在数据中声明且无法从偏移量中获取长度的字符串,您需要遍历字符串,直到找到 0 空终止符。我会看看我是否有一个 32 位函数并在示例中发布。
  • 我将长度保存在 stringLength : DWORD 中,但我不知道如何在 .code 部分中分配 stringLength-bytes 的内存。
  • 最简单的方法就是在 .data 或 .bss 中为 DWORD 保留空间,并为该地址分配一个标签。在需要初始化值的数据中,'0000' 就可以了,然后在计算完长度后将长度写入标签地址。
  • 我只想说,当人们告诉您使用 Windows 内存分配功能时,您应该提到您使用的是 Linux。 “他们不会工作”不像“我没有使用 Windows”那样提供信息。更令人怀疑的是,您谈到将 Visual Studio 与 MASM 结合使用。但您的代码绝对是特定于 Linux 的。
猜你喜欢
  • 2018-05-11
  • 2019-06-11
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
相关资源
最近更新 更多