0

我有以下汇编代码,它是 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从格式字符串中删除任何内容,则该函数可以正常工作。

4

1 回答 1

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
于 2013-05-08T23:53:03.990 回答