0
我有以下彙編代碼,它是C函數sprintf()的簡單實現。到目前爲止,它在解析%c
和%%
時工作正常,而我現在正在執行%s
,可以在標籤found_string
下找到它。我試圖通過執行pushl %eax
來保存%ecx寄存器(在主循環中使用),所以我可以使用它遍歷我的參數字符串,而不會干擾主循環,然後在完成時使用popl %eax
。嘗試重新使用寄存器x86彙編時發生Segfault
.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
,功能工作正常。
哇,太簡單了!我不知道爲什麼我沒有看到。我一直在扯着我的頭髮。非常感謝! – ponycat 2013-05-08 23:58:24