Segfault在尝试重用注册x86程序集时

时间:2013-05-08 23:05:06

标签: assembly x86 segmentation-fault cpu-registers att

我有以下汇编代码,这是C函数sprintf()的简单实现。到目前为止,它在解析%c%%时工作得很好,我现在正在努力实现%s,它可以在标题found_string下面找到。我试图通过执行pushl %eax来保存%ecx寄存器(在主循环中使用),因此我可以使用它来迭代我的参数字符串而不会干扰主循环,然后{{ 1}}当我完成时。

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 后会发生段错误。我也试过使用%eax寄存器,但老实说我不知道​​为什么它会失败。我是否错误地执行了保存/恢复过程?什么是更好的方法呢?

这是我编译的C代码:

found_string

如果我从格式字符串中删除任何#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; } ,则该函数可以正常工作。

1 个答案:

答案 0 :(得分:2)

你的restore %ecx for usage in main loop行永远不会被触及,因为早些时候你有这个:

   cmpb $0,(%ecx)
   jz back_loop

大概你想为restore %ecx...块创建一个标签,然后跳转到那里。它可能看起来像这样:

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 found_string_end
    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
found_string_end:
    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