0

私はアセンブリが初めてで、Ubuntu で nasm x86-64 を使用して C 関数 puts をアセンブリに実装しようとしています。

関数のテストを作成するまでは、すべて問題ありませんでした。再現できない動作があります。char *str = strdup(""); を送信したとき。私の puts 関数 (別名 ft_puts) に対して、私の関数は元の puts 関数のように改行を出力する代わりにエラーを返します。

これが私の puts 実装 (ft_puts.s) です。

section .data
new_line        db      10      ; new line

section     .text
global      ft_puts
extern      strlen

ft_puts:                        ; Alias int puts(const char *s)
    call    strlen
    push    rax                 ; Number of printed chars have to be returned by ft_puts

    cmp     rax, 0
    jg      print_string        ; if length > 0, print string
    cmp     rax, 0
    jz      print_newline       ; else if length == 0 (jle or <= 0, give the same result to my problem), print new line char
    jmp     error               ; else go to error

print_string:
    mov     rsi, rdi            ; string arg for write
    mov     rdi, 1              ; file_descriptor arg for write
    mov     rdx, rax            ; length arg returned by ft_strlen for write
    mov     rax, 1              ; write
    syscall

    test    rax, rax
    jle     error               ; if write failed, go to error
    jmp     print_newline       ; else print new line char

print_newline:
    mov     rsi, new_line       ; new line as string arg for write
    mov     rdx, 1              ; new line string length
    mov     rax, 1              ; write
    syscall

    test    rax, rax
    jle     error               ; if write failed, go to error
    jmp     success             ; else go to success

success:
    pop     rax                 ; Get number of chars printed by print_string
    inc     rax                 ; Add new line printed by print_newline to this number
    jmp     end

error:
    pop     rax
    mov     rax, -1             ; Return EOF (alias -1) on error
    jmp     end

end:
    ret

コードがひどい場合は申し訳ありませんが、1 週間前にアセンブリを開始しました。私は Stack Overflow を初めて使用し、ヘルプ センターからコードをテストするためのコードを提供するように言われました。したがって、ここに main.c があります。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

int ft_puts(const char *s);

int main(void)
{
    char    *str;
    int     ret[2];

    str = strdup(".");

    write(1, "[", 1);
    ret[0] = puts(str);
    write(1, "]", 1);
    write(1, "\n", 1);
    write(1, "[", 1);
    ret[1] = ft_puts(str);
    write(1, "]\n", 2);

    printf("puts return value : %d | ft_puts return value : %d\n\n", ret[0], ret[1]);
    free(str);


    str = strdup("");

    write(1, "[", 1);
    ret[0] = puts(str);
    write(1, "]", 1);
    write(1, "\n", 1);
    write(1, "[", 1);
    ret[1] = ft_puts(str);
    write(1, "]\n", 2);

    printf("puts return value : %d | ft_puts return value : %d\n", ret[0], ret[1]);
    free(str);

    return (0);
}

そして、このコードをコンパイルして実行するには:)

nasm -f elf64 ft_puts.s -o ft_puts.o
gcc -c main.c
gcc main.o ft_puts.o -o test
./test

問題は print_newline ラベルにあるようですが、見つかりません。誰かが私を助けることができれば? (私の周りのアセンブリ言語について助けを得るのは難しいです) (私の質問に C タグを含める必要があるかどうかはわかりませんが、あまりにも多くの質問があります)

4

1 に答える 1

2

2 つの問題。1 つ目は、call strlen含まれているいくつかのレジスタを上書きすることが許可されておりrdi、後で必要になります。そのため、保存して復元するには、call strlenで囲みます。push rdipop rdi

次に、ブロックrdi内で初期化しません。ブロックで行ったのと同じように、 forprint_newlineに設定する必要があります。1stdoutprint_string

PS: デバッガーの使い方を学ぶ必要があります。

于 2015-06-09T23:34:20.940 に答える