我有以下汇编代码,它是 C 函数 sprintf() 的简单实现。到目前为止,它在解析%c
和中运行良好%%
,我现在正在实施%s
,它可以在下面的标签下找到found_string
。我正在尝试通过 do 保存 %ecx 寄存器(在主循环中使用),pushl %eax
这样我就可以使用它来遍历我的参数字符串而完全不干扰主循环,然后popl %eax
在我完成时。
.globl sprinter
.data
.escape_string: .string "%"
.char_string: .string "c"
.decimal_string: .string "d"
.octet_string: .string "o"
.string_string: .string "s"
.string_hexadecimal: .string "x"
.num_escape: .long 0
.num_characters: .long 0
.text
sprinter:
pushl %ebp
movl %esp,%ebp
movl $0,.num_characters # set num_characters to '0', otherwise successive runs of sprinter() will just keep incrementing this number
movl 8(%ebp),%edx # %edx = result-string
movl 12(%ebp),%ecx # %ecx = format-string
addl $8,%ebp # remove the parameters from the stack
movb .escape_string,%bl # add escape character to %bl and keep it there forever since we use it so much!
loop:
cmpb $0, (%ecx) # if end of string reached
jz exit # exit loop
cmpb %bl,(%ecx) # if escape character found
je found_escape_char # jump to subprodecure to handle the escape character
movb (%ecx), %al # copy current character to %al
movb %al, (%edx) # copy current character to #edx (result-string)
back_loop: # this is where we return from the subprocedure
incl %ecx # increment %ecx since we read a character from it
incl %edx # increment %edx since we wrote a character to it
incl .num_characters
jmp loop # continue loop
found_escape_char:
# let's see if the next character is a 'c'
movb .char_string,%al
cmpb %al,1(%ecx)
je found_char
# ...or, let's see if the next character is a '%'
movb .escape_string, %al
cmpb %al,1(%ecx)
je found_percent
# ...or, let's see if the next character is an 's'
movb .string_string, %al
cmpb %al,1(%ecx)
je found_string
# ...or if we didn't match anything, just write it to the result string for now (e.g. we print "%b", "%n" or other invalid codes to the result)
movb (%ecx), %al
movb %al, (%edx) # copy current character to #edx (result-string)
jmp back_loop # back into main loop
found_percent:
incl %ecx # skip the "operand" character we just found
movb %al,(%edx) # write percent sign to result
jmp back_loop # back into main loop
found_char:
incl %ecx # skip the "operand" character we just found
movb 8(%ebp),%al
movb %al,(%edx)
addl $4,%ebp # remove the parameter we consumed from the stack
jmp back_loop # back into main loop
found_string:
pushl %ecx # save %ecx, because we use it in the main loop
movl 8(%ebp),%ecx # put the string parameter into %ecx
string_loop: # this is the exact same loop as above in 'loop:', and that one works fine
cmpb $0,(%ecx)
jz back_loop
movb (%ecx),%al # copy current character to %al
movb %al,(%edx) # copy current character to %edx (result-string)
incl %ecx # increment %ecx since we read a character from it
incl %edx # increment %edx since we wrote a character to it
jmp string_loop
popl %ecx # restore %ecx for usage in main loop
addl $4,%ebp # remove the parameter we consumed from the stack
jmp back_loop # back into main loop
exit:
movl $0,(%edx) # write null character to finish off the result string
# return number of characters printed
movl .num_characters, %eax
popl %ebp
ret
不幸的是,这段代码一旦进入found_string
. 我也尝试过使用 %eax 寄存器,但老实说,我不知道它为什么会失败。我是否错误地执行了保存/恢复过程?有什么更好的方法来做到这一点?
这是我编译它的 C 代码:
#include <stdio.h>
extern int sprinter (unsigned char* res, unsigned char* string, ...);
int main (void)
{
unsigned char t[2000];
int n = sprinter(t, "this is a char: %c, this is a percent symbol: %%, this is a string: %s", 'A',"a string");
printf("numchars: %d\n",n);
printf("result: %s\n",t);
return 0;
}
如果我%s
从格式字符串中删除任何内容,则该函数可以正常工作。