所以,我理解缓冲区的一般抽象概念:它是内存中的一个分配,它在处理之前保存数据。我正在尝试完成一个家庭作业问题,这个问题要求我将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。
答案 0 :(得分:3)
假设x86,这取决于你的缓冲区是否以数据开头。它还取决于您的缓冲区是否可变大小。
第一种情况,你知道你的缓冲区永远不会超过20个字节,你可以在数据部分声明它(NASM语法):
buffer: times 20 db 0
在数据部分中声明您现在可以使用的20 0
个字节。如果您不需要使用数据初始化,则使用.bss部分(NASM语法):
buffer: resb 20
告诉NASM保留20个字节。
但是,如果缓冲区的大小是可变的,那么事情就不那么容易了。您必须从操作系统动态分配内存,这与操作系统非常相关。你基本上有两个选择:
malloc
:这可能更容易或更难,具体取决于平台调用约定。有一个合理的参考here malloc
那样漂亮或简单。它们通常涉及向您的流程添加另一页内存并让您自己管理它。这是malloc在内部执行的操作,如果您不能使用C库,则是唯一的选择。答案 1 :(得分:0)
我使用此方法在缓冲区中获取char并与其他字符串进行比较
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
我希望能帮到你
答案 2 :(得分:0)
是的,缓冲区只是一个数组,在汇编中是一个字节序列。
分配它有3个主要选项,就像在C:
中一样 静态存储空间:与C static char buf[100];
section .bss ; this might not be proper MASM syntax
my_buffer: db 100 dup(?) ; but this is definitely MASM
在标签名称和:
之间加上db
使它只是一个简单的标签,如NASM,而不是MASM"变量"带有隐含的操作数大小。
动态存储:call malloc
,或直接调用操作系统功能,如mmap
或VirtualAlloc
。您可以从分配它的函数返回指向它的指针。
自动存储(在堆栈上):类似于C本地变量。 分配函数返回时自动释放。非常便宜和简单,使用它作为临时缓冲区,除非你知道它们需要多兆字节。
处理缓冲区的最简单方法是接受指向已经分配的缓冲区的指针,并让调用者选择要传递的缓冲区。
例如,一个大写ASCII字母的函数可以只取一个src和dst指针。如果你希望它就地操作,你只需传递相同的输入和输出指针,如果它被写入以支持它。它不必关心内存管理,它只是在两个缓冲区之间运行。
像C strdup
这样的函数创建了一个字符串的新副本,这只对动态存储有意义。将字符串复制到静态缓冲区并返回它将无法正常工作,因为该静态缓冲区只有一个实例。下一次调用它将覆盖旧内容。
在堆栈上分配缓冲区:
堆栈上的可变大小缓冲区没问题;你只需要一种方法来清理堆栈。使用EBP / RBP制作堆栈框架是一种简单的方法。考虑这个示例函数,它根据需要分配一个大的缓冲区,并使用它来保存字符串反转函数的输出,以便它可以将它传递给print
函数。您可以看到what compilers do in this case。
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可变长度数组的方法。