试图重用寄存器x86程序集时出现段错误



我有以下汇编代码,这意味着是c函数sprintf()的简单实现。到目前为止,它可以很好地解析%c%%,我现在正在努力实现%s,它可以在下面的found_string标签下找到。我试图保存%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: %dn",n);
    printf("result: %sn",t);
    return 0;
}

如果我从格式字符串中删除任何%s,该函数工作正常

你的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

最新更新