2

elf64コンパイルを使用していて、パラメーターを取得してコンソールに書き出そうとしています。

関数を./testwooopとして呼び出しています

gdbを使用してステップスルーした後、問題はないようです。すべてが正常にセットアップされています。

rax:0x4 rbx:0x1 rcx:文字列を指し、x / 6cb$rcxは'w''o''o''o''p'0x0 rdx:0x5<---長さを正しく決定します

int 80h raxに-14が含まれ、コンソールに何も出力されない場合。.dataで文字列を定義すると、機能します。gdbは、同じ方法で$rcxの値を表示します。

何か案は?これが私の完全な情報源です

    %define LF      0Ah
    %define stdout      1
    %define sys_exit    1
    %define sys_write   4


    global _start

    section .data

    usagemsg: db "test {string}",LF,0

    testmsg: db "wooop",0

    section .text

    _start:

    pop rcx     ;this is argc
    cmp rcx, 2      ;one argument
    jne usage
    pop rcx
    pop rcx               ; argument now in rcx
    test    rcx,rcx
    jz usage

    ;mov rcx, testmsg    ;<-----uncomment this to print ok!

    call print
    jmp exit


    usage:
    mov rcx, usagemsg
    call print
    jmp exit


    calclen:

    push rdi
    mov rdi, rcx
    push rcx
    xor rcx,rcx
    not rcx
    xor al,al
    cld
    repne scasb
    not rcx  
    lea rdx, [rcx-1]
    pop rcx
    pop rdi
    ret

    print:

    push rax
    push rbx
    push rdx

    call calclen

    mov rax, sys_write
    mov rbx, stdout
    int 80h
    pop rdx
    pop rbx
    pop rax
    ret

    exit:
    mov rax, sys_exit
    mov rbx, 0
    int 80h

ありがとう

編集:以下のようにシステムコールの作成方法を変更した後、正常に動作します。助けてくれてありがとう!

sys_writeは1になりました
sys_exitは60
になりましたstdoutはrbxではなくrdiに
なります書き込みする文字列はrsiに設定され、rcxint80hは
syscallに置き換えられません

4

2 に答える 2

5

私はまだ 32 ビット ハードウェアを実行しているので、これは勝手な推測です。ご存じのとおり、64 ビットのシステム コール番号はまったく異なり、int 80h の代わりに「syscall」が使用されます。ただし、int 80h および 32 ビットのシステム コール番号は引き続き使用でき、64 ビット レジスタは 32 ビットに切り捨てられます。あなたのテストは、これが .data のアドレスで機能することを示していますが、「スタック アドレス」では -14 (-EFAULT - 不良アドレス) を返します。私が考えることができる唯一のことは、スタック上にある場合、rcx を ecx に切り詰めると「不良アドレス」になるということです。スタックが 64 ビット コードのどこにあるのかわかりません。これは理にかなっていますか?

「適切な」64ビットシステムコール番号とレジスタ、および「syscall」で試して、それが役立つかどうかを確認します。

ベスト、フランク

于 2012-07-23T18:48:08.973 に答える
2

おっしゃる通り、コンパイルのターゲットとして ELF64 を使用しています。残念ながら、これはあなたの最初の間違いです。たとえば、Linux で「古い」システム コール インターフェイスを使用するint 80hことは、32 ビット タスクを実行している場合にのみ可能です。明らかに、ソースを ELF32 として単純にアセンブルすることもできますが、64 ビット モードでタスクを実行する場合のすべての利点、つまり余分なレジスタと 64 ビット操作が失われます。

64 ビット タスクでシステム コールを行うには、「新しい」システム コール インターフェイスを使用する必要があります。システムコール自体は、syscall命令で実行されます。カーネルはレジスタrcxr11. システムの番号はレジスタraxで指定され、呼び出しの引数はrdirsirdx、およびr10で渡されます。syscall の数は 32 ビット モードのものとは異なることに注意してください。これらは、通常、ディストリビューションに格納されている 内またはどこにでも見つけることができます。r8r9unistd_64.h/usr/include/asm

于 2012-07-23T20:09:48.897 に答える