6

所以,我理解缓冲区的一般抽象概念:它是内存中的分配,在数据被处理之前保存数据。我正在尝试完成一个作业问题,该问题需要我将 ASCII 字符串写入过程中的缓冲区。所以,我知道我应该在调用它时将数组的地址传递给过程,例如......

main PROC
mov  EAX, packed           ; pass a packed decimal to EAX
mov  ESI, OFFSET ascArray  ; pass the offset of an empty array to ESI
call PackedToAsc           ; call the function

因此,该函数应该返回“指向带有 ASCII 十进制字符串的缓冲区的指针”。我可能在这里很愚蠢,但我不太清楚在这种情况下缓冲区到底是什么。

  • 它是一个数组吗?
  • 我是否需要在该.data部分中声明它?
  • 如何在过程中声明指向 ASCII 字符串的指针?
  • 在这种情况下,缓冲区是什么意思?

更实际的是,我需要在程序完成时访问数据放入的缓冲区,但我不知道该怎么做。

编辑   ——我在 x86 中,我正在使用 MASM。

4

3 回答 3

4

假设 x86,这取决于您的缓冲区是否以其中的数据开头。它还取决于您的缓冲区是否为可变大小。

以第一种情况为例,您知道您的缓冲区永远不会超过 20 个字节,您可以在数据部分(NASM 语法)中声明它:

buffer: times 20 db 0

在数据部分中声明0了您现在可以使用的 20 个字节。如果您不需要使用数据进行初始化,则使用 .bss 部分(NASM 语法):

buffer: resb 20

它告诉 NASM 保留 20 个字节。

但是,如果缓冲区的大小是可变的,事情就不那么容易了。您必须从操作系统动态分配内存,这非常依赖于操作系统。你基本上有2个选择:

  • 使用 C 库malloc:这可能更容易或更难,具体取决于平台调用约定。这里有一个合理的参考
  • 使用您的系统调用:所有系统都提供了一些获取更多内存的方法,但没有一个像malloc. 它们通常涉及向您的进程添加另一页内存并让您自己管理它。这是 malloc 在内部所做的,如果您不能使用 C 库,这是唯一的选择。
于 2012-11-20T14:52:33.707 回答
4

是的,缓冲区只是一个数组,在汇编中是一个字节序列。

您有 3 个主要选项来分配它,就像在 C 中一样:

  • 静态存储:像 Cstatic char buf[100];

      section .bss                   ; this might not be proper MASM syntax
       my_buffer:  db   100 dup(?)   ; but this is definitely MASM
    

    :在标签名称和之间放置 adb使其只是一个普通标签,如 NASM,而不是具有隐含操作数大小的 MASM“变量”。(如果 MASM 允许您在 .data / .bss 部分执行此操作。它可能不会。)

    100 dup意思是将下一件事重复100次。 ?表示未初始化的存储。它实际上将在像 Windows 这样的操作系统下运行的程序中归零,因为它不能让程序看到内核数据或同一台机器上的其他进程留下的陈旧数据。所以100 dup(0)也可以工作,也许可以更好地描述你想要的东西,特别是如果你的代码在没有先写的情况下读取了这些字节中的任何一个。

  • 动态存储:call malloc,或直接调用 OS 函数,如mmapVirtualAlloc。您可以从分配它的函数返回指向它的指针。

  • 自动存储(在堆栈上):就像一个 C 局部变量。当分配函数返回时自动解除分配。非常便宜和容易,除非您知道它们需要数兆字节,否则将其用于暂存缓冲区。

处理缓冲区的最简单方法是接受指向已分配缓冲区的指针,并让调用者选择要传递的缓冲区。

例如,一个大写 ASCII 字母的函数可能只需要一个 src 和 dst 指针。如果您希望它就地运行,您可以只传递相同的输入和输出指针,如果它被编写为支持它的话。它不必关心内存管理,它只是在两个缓冲区之间运行。

像 C 这样的函数strdup会创建一个字符串的新副本,而这只对动态存储有意义。将字符串复制到静态缓冲区并返回它不会很好,因为该静态缓冲区只有一个实例。下一次调用它会覆盖旧的内容。


在堆栈上分配缓冲区:

堆栈上的可变大小缓冲区没有问题;您只需要一种事后清理堆栈的方法。使用 EBP / RBP 制作堆栈框架是一种简单的方法。考虑这个示例函数,它根据需要分配一个缓冲区,并使用它来保存字符串反转函数的输出,以便将其传递给print函数。您可以看到编译器在这种情况下做了什么

void string_reverse(char *d, const char*s, int len);
void print(const char*s, int len);  // modify this to an fwrite or whatever.

void print_reversed(const char *s, int len) {
    char buf[len];
    string_reverse(buf, s, len);
    print(buf, len);
}

string_reverse如果不需要 16 字节堆栈对齐并且它不会破坏它的堆栈 arg ,那么这就是您可以手动执行的操作。(ABI / 调用约定并不能保证这些事情中的任何一个,所以我们正在利用我们正在调用的函数的特殊知识来简化print_reversed。)

; MSVC __fastcall convention
; args: ecx, edx    (const char *string,  size_t length)
print_reversed PROC
    push   ebp
    mov    ebp, esp         ; make a stack frame

    sub    esp, edx         ; reserve space for a buffer
    and    esp, -16         ; and realign the stack
    ; allocate buf[length] on the stack, address = esp
      ; mov eax, esp       ; if you want to copy it somewhere

        ;sub    esp, 12          ; ensure 16-byte stack alignment before CALL

    push   edx              ; 3rd arg and later args go on the stack
    mov    edx, ecx         ; 2nd arg = string
    lea    ecx, [esp+4]     ; 1st arg = output buffer = what we allocated.  (PUSH offset ESP by 4, LEA corrects for that)

    call    string_reverse   ; (dst=buf (ECX),  src=string (EDX), length=length (stack))
      ; clean up the stack after the call and set up args for print
    pop    edx              ; assuming string_reverse doesn't modify its stack arg
    mov    ecx, esp         ; esp is once again pointing to our buffer
    call   print            ; print(ECX=buf, EDX=length)

      ; lea     esp, [ebp-8]  ; if you needed to push stuff after EBP, restore this way
      ; pop  ebx  / pop esi / pop ebp
    
    leave                   ; mov esp, ebp / pop ebp to clean up the stack frame
    ret
ENDP

这是大多数 C 编译器实现alloca或 C99 可变长度数组的方式。

于 2018-05-22T05:37:48.273 回答
-2

我使用这种方法在缓冲区获取字符并与其他字符串比较

CompareText macro colorScreen,string1,ScoreofLabel,loop_1,endText,notText,backprint

    mov h3,cx
    ClescrColor colorScreen                                     
    mov cx,h3

    printstr string1

    lea SI,string1[0]
    loop_1:       
        mov AH,01 
        int 16H
        jz backprint

    mov AH,00      
    int 16H       
    mov AH, [SI]   
    inc SI    

    cmp ah,36
        jne endText
    mov ah,13           

    endText:
    cmp AL, AH
        jne notText
    cmp AL, 13    
        jne loop_1


    jmp ScoreofLabel
    notText:
        mov si,62


endm 

希望对你有帮助

于 2018-05-22T04:34:54.870 回答