将字符串参数传递给 PROC
Posted
技术标签:
【中文标题】将字符串参数传递给 PROC【英文标题】:Passing string parameter to a PROC 【发布时间】:2019-08-03 13:41:58 【问题描述】:我想调用一个函数,它将执行从大写到小写转换为用户键入的字符串,保留特殊字符。这部分有效,但仅适用于前 4 个字符,之后的所有内容都会被截断。我相信是因为我将参数定义为 DWORD:
我尝试过使用PAGE
、PARA
和BYTE
。前两个不起作用,字节表示类型不匹配。
upperToLower proc, source:dword, auxtarget:dword
mov eax, source ;Point to string
mov ebx, auxtarget ; point to destination
L1:
mov dl, [eax] ; Get a character from buffer
cmp byte ptr [eax], 0 ; End of string? (not counters)
je printString ; if true, jump to printString
cmp dl, 65 ; 65 == 'A'
jl notUpper ; if less, it's not uppercase
cmp dl, 90 ; 90 == 'Z'
jg notUpper ; if greater, it's not uppercase
xor dl, 100000b ; XOR to change upper to lower
mov [ebx], dl ; add char to target
inc eax ; Move counter up
inc ebx ; move counter up
jmp L1 ; loop
notUpper: ; not uppercase
mov [ebx], dl ; copy the letter
inc eax ;next letter
inc ebx
jmp L1
printString:
invoke WriteConsoleA, consoleOutHandle, auxtarget, sizeof auxtarget, bytesWritten, 0
ret
upperToLower endp
原型:
upperToLower PROTO,
source: dword,
auxtarget: dword
调用:
invoke upperToLower, offset buffer, offset target
缓冲区参数为:buffer db 128 DUP(?)
如何打印整个字符串,而不仅仅是前 4 个字符?
【问题讨论】:
【参考方案1】:为什么只打印 4 个字符?您将字符串写入控制台:
invoke WriteConsoleA, consoleOutHandle, auxtarget, sizeof auxtarget, bytesWritten, 0
sizeof auxtarget
参数是auxtarget
的大小,它是DWORD
(4 个字节),因此您要求只打印 4 个字节。您需要传递字符串的长度。您可以通过在 EAX 中获取结束地址并从中减去 source
指针来轻松做到这一点。结果将是您遍历的字符串的长度。
修改代码为:
printString:
sub eax, source
invoke WriteConsoleA, consoleOutHandle, auxtarget, eax, bytesWritten, 0
遵循 C 调用约定的代码版本,使用源缓冲区和目标缓冲区,测试指针以确保它们不是 NULL,使用类似的 @ 进行转换987654321@如下:
upperToLower proc uses edi esi, source:dword, dest:dword
; uses ESI EDI is used to tell assembler we are clobbering two of
; the cdecl calling convetions non-volatile registers. See:
; https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl
mov esi, source ; ESI = Pointer to string
test esi, esi ; Is source a NULL pointer?
jz done ; If it is then we are done
mov edi, dest ; EDI = Pointer to string
test edi, edi ; Is dest a NULL pointer?
jz done ; If it is then we are done
xor edx, edx ; EDX = 0 = current character index into the strings
jmp getnextchar ; Jump into loop at point of getting next character
charloop:
lea ecx, [eax - 'A'] ; cl = al-'A', and we do not care about the rest
; of the register
cmp cl, 25 ; if(c >= 'A' && c <= 'Z') c += 0x20;
lea ecx, [eax + 20h] ; without affecting flags
cmovna eax, ecx ; take the +0x20 version if it was in the
; uppercase range to start with
mov [edi + edx], al ; Update character in destination string
inc edx ; Go to next character
getnextchar:
movzx eax, byte ptr [esi + edx]
; mov al, [esi + edx] leaving high garbage in EAX is ok
; too, but this avoids a partial-register stall
; when doing the mov+sub
; in one instruction with LEA
test eax, eax ; Is the character NUL(0) terminator?
jnz charloop ; If not go back and process character
printString:
; EDI = source, EDX = length of string
invoke WriteConsoleA, consoleOutHandle, edi, edx, bytesWritten, 0
mov edx, sizeof buffer
done:
ret
upperToLower endp
采用一个参数并将源字符串更改为大写的版本可以这样完成:
upperToLower proc, source:dword
mov edx, source ; EDX = Pointer to string
test edx, edx ; Is it a NULL pointer?
jz done ; If it is then we are done
jmp getnextchar ; Jump into loop at point of getting next character
charloop:
lea ecx, [eax - 'A'] ; cl = al-'A', and we do not care about the rest
; of the register
cmp cl, 25 ; if(c >= 'A' && c <= 'Z') c += 0x20;
lea ecx, [eax + 20h] ; without affecting flags
cmovna eax, ecx ; take the +0x20 version if it was in the
; uppercase range to start with
mov [edx], al ; Update character in string
inc edx ; Go to next character
getnextchar:
movzx eax, byte ptr [edx] ; mov al, [edx] leaving high garbage in EAX is ok, too,
; but this avoids a partial-register stall
; when doing the mov+sub in one instruction with LEA
test eax, eax ; Is the character NUL(0) terminator?
jnz charloop ; If not go back and process character
printString:
sub edx, source ; EDX-source=length
invoke WriteConsoleA, consoleOutHandle, source, edx, bytesWritten, 0
done:
ret
upperToLower endp
观察
执行字符串转换的通用upperToLower
函数通常不会执行打印本身。您通常会调用 upperToLower
来仅进行转换,然后在单独的调用中将字符串输出到显示器。
【讨论】:
能否请您指导我如何提高效率? @Wolfeius :我在最新更新中使用不同的技术提供了几个示例 谢谢你。我需要一些时间来理解正在发生的所有事情,但我会尝试在这个程序的下一个部分中使用我认为我正确的一些部分。谢谢!以上是关于将字符串参数传递给 PROC的主要内容,如果未能解决你的问题,请参考以下文章
为啥我们将字符串数组作为参数传递给 main() 方法,为啥不传递任何集合类型或包装类型或原始类型?
如何将命令行参数传递给 unix/linux 系统上正在运行的进程?