2017-02-10 57 views
-1

У меня есть следующий код Assembly:RET вызывает Segfault в сборке

.text 
.global main 
main: 
    push %r13 
    push %r14 
    push %r15 
    jmp rest 
x:  
    .data 
    y0: .quad 0 
    .text 
    mov %r14, y0 
    mov $format,%rdi 
    push y0 
    popq %rsi 
    movq %rsi, %r15 
    call printf 
    mov $format,%rdi 
    mov $10,%rsi 
    call printf 
    ret 
rest:  
    movq $5, %r9 
    pushq %r9 
    popq %rsi 
    movq %rsi, %r14 
    jmp x 
    mov $0,%rax 
    pop %r15 
    pop %r14 
    pop %r13 
    ret 
.data 
format: 
.byte 37 
.byte 108 
.byte 117 
.byte 0 

Я надеялся, что в отставке сделает программу переходить туда, где это было: однако, я получаю ошибку сегментации. Почему это?

+1

Напоминание, как 'pushq% r9'' popq% rsi', похоже, было бы проще, заменив на 'mov% r9,% rsi' –

+1

. Я рекомендую вам выполнить свой код в отладчике, таком как _GDB_ –

+0

. характер вашего первого вопроса. Если у вас есть другой вопрос, пожалуйста, создайте новый вопрос. Ваши изменения делают комментарии и ответы бессмысленными. Я снова изменил свое изменение на оригинальную версию. –

ответ

2

Эти проблемы почти всегда, вызванные сбоем очистки стека. То же самое верно и в вашем случае.

Вы начинаете с:

main: 
    push %r13 
    push %r14 
    push %r15 
    jmp rest 

В течение rest вы затем

jmp x 

В пределах x вы это делаете:

mov $format,%rdi 
mov $10,%rsi 
call printf 
ret 

Это оставляет вас три вещи, сидя на стеке, что вы не справились. Когда этот ret выполнен, он перемещает предыдущее значение %r15 в указатель инструкции и segfaults.

ret не будет возвращаться из скачка. Он возвращается к инструкции, следующей за call.

+0

Большое вам спасибо! Я обновил свой код, основываясь на вашем ответе (нажав $ 0, чтобы он выскочил вместо% r15), но я в замешательстве, почему он все еще не работает. –

+0

Потому что вы выдвигаете больше вещей в стек, чем вы отступаете. Ваши СОЗ всегда должны быть равны вашим PUSH, или вы должны настроить SP/ESP/RSP, чтобы разматывать стек вручную. Указатель возврата для вашего вызова хранится в стеке. Если указатель стека не указывает на него при ударе RET, он будет загружать все верхнее значение в стеке в EIP/RIP, что почти всегда вызывает segfault. –