在gCS中复制和调用x86 AT& T-Assembler中的函数

时间:2009-03-12 18:16:03

标签: gcc assembly x86

我在AT& T汇编语法中为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 sais:

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,它也没有用,同样的错误。

我不知道自己做错了什么。有人可以帮帮我吗?

1 个答案:

答案 0 :(得分:6)

您有以下问题:

  • 设置堆栈以调用copy_bytes时,你想要pushl $ to_gen_inner而不是pushl to_gen_inner(后者将内存的内容推送到to_gen_inner指向)

  • 将值复制到copy_bytes内的本地堆栈帧时,需要将刚刚读取参数的寄存器写入,而不是始终写入EAX

  • lcall *(%eax)希望从EAX指向的内存中读取一个地址,并跳转到那里。此外,它预计读取48个字节,前16个是段。我用呼叫*%eax替换了你的lcall;也相应地用rets替换了这些lrets。

  • 对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

...我在这里建立并运行。希望有所帮助。