1

AT&T Assembler Syntax for gcc で次のコードを書きました

.global main
.section .data

to_gen_inner: #x f, implicit n
        pushl %ebp
        movl %esp, %ebp
        movl $0xFF00FF00, %eax
        call printregs
        lret

.set to_gen_inner_len, . - to_gen_inner

.section .text

main:
        pushl %ebp
        movl %esp, %ebp

        #allocate memory
        pushl $to_gen_inner_len
        call malloc
        popl %ecx

        pushl $to_gen_inner_len
        pushl to_gen_inner
        pushl %eax
        call copy_bytes
        popl %eax
        popl %ecx
        popl %ecx

        lcall *(%eax)

        movl %ebp, %esp
        popl %ebp
        ret

printfregs:
        .ascii "eax: %8X\nebx: %8X\necx: %8X\nedx: %8X\n\0"

printregs:
        pushl %edx
        pushl %ecx
        pushl %ebx
        pushl %eax
        pushl $printfregs
        call printf
        popl %ecx
        popl %eax
        popl %ebx
        popl %ecx
        popl %edx
        lret

copy_bytes: #dest source length
        pushl %ebp
        movl %esp, %ebp

        subl $24, %esp

        movl 8(%ebp), %ecx # dest
        movl %eax, -4(%ebp)

        movl 12(%ebp), %ebx # source
        movl %eax, -8(%ebp)

        movl 16(%ebp), %eax # length
        movl %eax, -12(%ebp)

        addl %eax, %ecx # last dest-byte
        movl %ecx, -16(%ebp)

        addl %eax, %edx # last source-byte
        movl %ecx, -20(%ebp)

        movl -4(%ebp), %eax
        movl -8(%ebp), %ebx
        movl -16(%ebp), %ecx

        copy_bytes_2:
        movb (%ebx), %dl
        movb %dl, (%eax)
        incl %eax
        incl %ebx
        cmp %eax, %ecx
        jne copy_bytes_2

        movl %ebp, %esp
        popl %ebp
        ret

実際にやりたいのは、関数コードto_gen_innerを malloc で割り当てているメモリにコピーしてから、そこにジャンプすることです。このコードは、セグメンテーション違反を生成します。gdb サイス:

Program received signal SIGSEGV, Segmentation fault.
main () at speicher3.S:32
32              lcall *(%eax)
Current language:  auto; currently asm
(gdb) disas $pc-5 $pc+5
Dump of assembler code from 0x80483eb to 0x80483f5:
0x080483eb <main+23>:   add    %al,(%eax)
0x080483ed <main+25>:   pop    %eax
0x080483ee <main+26>:   pop    %ecx
0x080483ef <main+27>:   pop    %ecx
0x080483f0 <main+28>:   lcall  *(%eax)
0x080483f2 <main+30>:   mov    %ebp,%esp
0x080483f4 <main+32>:   pop    %ebp
End of assembler dump.
(gdb) disas $pc-6 $pc+5
Dump of assembler code from 0x80483ea to 0x80483f5:
0x080483ea <main+22>:   add    %al,(%eax)
0x080483ec <main+24>:   add    %bl,0x59(%eax)
0x080483ef <main+27>:   pop    %ecx
0x080483f0 <main+28>:   lcall  *(%eax)
0x080483f2 <main+30>:   mov    %ebp,%esp
0x080483f4 <main+32>:   pop    %ebp
End of assembler dump.
(gdb)

私は実際に理由を知りません。私はすでにlcallとlretを使用していますが、これは絶対呼び出しと考えられています.callとretを使用すると、どちらも機能しませんでした.同じエラーです。

何が間違っているのかわかりません。誰でも私を助けてもらえますか?

4

1 に答える 1

6

次の問題があります。

  • copy_bytes への呼び出し用にスタックをセットアップするときは、pushl $to_gen_inner ではなく、pushl to_gen_inner が必要です (後者は to_gen_inner が指すメモリの内容をプッシュします)。

  • copy_bytes 内のローカル スタックフレームに値をコピーするときは、常に EAX を書き込むのではなく、パラメータを読み取ったばかりのレジスタに書き込む必要があります。

  • lcall *(%eax) は、EAX が指すメモリからアドレスを読み取り、そこにジャンプすることを想定しています。さらに、最初の 16 がセグメントである 48 バイトを読み取ることが期待されます。あなたの lcall を call *%eax; に置き換えました。また、それに応じて lrets を rets に置き換えました。

  • printregs への呼び出しは相対呼び出しとしてアセンブルされます。これは、実行中の命令がアセンブルされたときと同じターゲットへの相対オフセットにないため、失敗します。私はそれを

    movl $printregs, %ecx
    call *%ecx
    

(これは %ecx を破棄します)

  • 最後に、to_gen_inner は入り口でスタックフレームをセットアップしますが、出口でそれを破棄しません。

これらをすべて修正すると、コードは次のようになります。

.global main
.section .data

to_gen_inner: #x f, implicit n
        pushl %ebp
        movl %esp, %ebp
        movl $0xFF00FF00, %eax
        movl $printregs, %ecx
        call *%ecx
        movl %ebp, %esp
        popl %ebp        
        ret

.set to_gen_inner_len, . - to_gen_inner

.section .text

main:
        pushl %ebp
        movl %esp, %ebp

        #allocate memory
        pushl $to_gen_inner_len
        call malloc
        popl %ecx

        pushl $to_gen_inner_len
        pushl $to_gen_inner
        pushl %eax
        call copy_bytes
        popl %eax
        popl %ecx
        popl %ecx

        call *%eax

        movl %ebp, %esp
        popl %ebp
        ret

printfregs:
        .ascii "eax: %8X\nebx: %8X\necx: %8X\nedx: %8X\n\0"

printregs:
        pushl %edx
        pushl %ecx
        pushl %ebx
        pushl %eax
        pushl $printfregs
        call printf
        popl %ecx
        popl %eax
        popl %ebx
        popl %ecx
        popl %edx
        ret

copy_bytes: #dest source length
        pushl %ebp
        movl %esp, %ebp

        subl $24, %esp

        movl 8(%ebp), %ecx # dest
        movl %ecx, -4(%ebp)

        movl 12(%ebp), %ebx # source
        movl %ebx, -8(%ebp)

        movl 16(%ebp), %eax # length
        movl %eax, -12(%ebp)

        addl %eax, %ecx # last dest-byte
        movl %ecx, -16(%ebp)

        addl %eax, %edx # last source-byte
        movl %ecx, -20(%ebp)

        movl -4(%ebp), %eax
        movl -8(%ebp), %ebx
        movl -16(%ebp), %ecx

        copy_bytes_2:
        movb (%ebx), %dl
        movb %dl, (%eax)
        incl %eax
        incl %ebx
        cmp %eax, %ecx
        jne copy_bytes_2

        movl %ebp, %esp
        popl %ebp
        ret

...ここでビルドして実行します。それが役立つことを願っています。

于 2009-03-12T21:39:17.243 に答える