2009-03-12 6 views
1

Я написал следующий код в AT & T ассемблере Синтаксис для GCCКопирование и вызов функции в x86 AT & T-ассемблере в НКУ

.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, который, как я прочитал, считается для абсолютных вызовов, с вызовом и ret, он тоже не работал, такая же ошибка.

Я не знаю, что я мог делать неправильно. Может ли кто-нибудь помочь мне?

ответ

6

У вас есть следующие проблемы:

  • при настройке стеки для вашего вызова copy_bytes, вы хотите PushL $ to_gen_inner не PUSHL to_gen_inner (последние выталкивает содержимое точек to_gen_inner памяти в)

  • при копировании значения локальной StackFrame внутри copy_bytes, вам нужно написать регистр вы только что прочитали параметр в, вместо того, чтобы всегда писать EAX

  • LCALL * (% EAX) EXPE cts, чтобы прочитать адрес из памяти, на который указывает EAX, и прыгать туда. Более того, он ожидает читать 48 байт, причем первые 16 являются сегментом. Я заменил ваш lcall на вызов *% eax; также заменил лретс ретами соответственно.

  • вызов printregs собирается как относительный вызов, который взрывается, так как исполняемая команда больше не совпадает с относительным смещением к цели, как это было, когда она была собрана. Я заменил его

    movl $printregs, %ecx 
    call *%ecx 
    

(который громит% ECX)

  • наконец, to_gen_inner устанавливает StackFrame на входе, но не может уничтожить его на выходе

Со всеми этими исправлениями код выглядит так:

.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 

... который строит и работает здесь для меня. Надеюсь, это поможет.

+0

Hm. Странный. Ваш код также работает только с вызовом *% eax (что я сделал первым). Похоже, что это не была основной причиной отказа моего кода. Так или иначе. Большое спасибо. – schoppenhauer

+0

Ah - похоже, что это вызов *% eax vs call * (% eax) - прежние ветки к адресу в% eax, последний называет адрес, содержащийся в памяти, на которую указывает% eax. Будет редактировать ответ. – moonshadow