2012-07-14 2 views
2

Я написал простую программу на языке ассемблера, пытаясь запустить ее на своей 64-битной ОС Ubuntu. Тем не менее, это не удалось для ошибки «Ошибка сегментации (сброс ядра)».Ошибка сбоя сегментации (сброс ядра) в коде сборки AT & T

Вот мой код:

.section .data 
    values : 
     .int 10, 15, 20, 25, 30 ,35, 40, 45, 50, 55, 60 
    output : 
     .asciz "The value is %d\n" 
    .section .text 
    .globl main 
    main : 
     nop 
     movl $0, %edi 
    loop : 
     movl values(, %edi, 4), %eax 
     pushq %rax 
     pushq $output 
     call printf 
     addl $8, %esp 
     inc %edi 
     cmpl $11, %edi 
     jne loop 
     movl $0, %ebx 
     movl $1, %eax 
     int $0x80 
+0

Я думаю, что большинство ваших регистров 'e__' должно быть' r__'. Похоже, что это было написано как сборка x86 и принудительно перенесено на x64 без внесения всех необходимых изменений. – Mysticial

+0

Я пробовал, но это тоже не сработает. – Nmzzz

+1

Собранный как 64-битный? Тогда стек не DWORD, а QWORD выровнен, поэтому ваше добавление 8 к rsp неверно, должно быть добавлено 16 к rsp после вашего вызова printf. – Gunner

ответ

3

Есть несколько проблем в вашем коде.

От 64bit Ubuntu и pushq %rax Я полагаю, что вы пытаетесь сделать 64-битный исполняемый файл.

Если это так, то ...

здесь:

pushq %rax 
pushq $output 
call printf 
addl $8, %esp 

вы не правильно сбалансировать стек после вызова функции. Вы все еще помните, что это 64-битный код? Вам нужно добавить к rsp, а не esp. Кроме того, если вы нажмете 2 8-байтовых параметра, вам нужно удалить ровно 2 8-байтовых параметра, а это значит, что вам нужно добавить 16, а не 8.

Но это даже хуже. В 64-битном режиме параметры передаются по-разному. Первые параметры указаны в регистрах rdi, rsi, rdx, rcx, r8 и r9. Итак, что дает нам:

movq %rax, %rsi 
movq $output, %rdi 
movq $0, %rax ; number of vector registers used for var-arg-function printf() 
call printf 

Здесь:

inc %edi 

Вы только что уничтожили значение rdi вызовом и с помощью этого регистра для передачи параметров. Вам нужно вручную нажать rdi перед вызовом, а затем потушить его. Или вы можете сохранить его в глобальной переменной. Если вы решите нажать и поп, убедитесь, что указатель стека rsp всегда выровнен на 16 байт перед любой командой call.

Здесь:

movl $0, %ebx 
movl $1, %eax 
int $0x80 

вы используете 32-битный интерфейс системного вызова. В 64-разрядных программ, которые вы должны использовать 64-битный интерфейс системного вызова:

movq $60, %rax ; sys_exit 
movq $0, rdi ; return 0 (success) 
syscall 

Теперь, я думаю, что это одна может иметь проблемы тоже:

movl $0, %edi 
loop : 
movl values(, %edi, 4), %eax 

В общем, вы не должны быть используя 32-разрядные регистры и 32-разрядные команды в вычислениях адресов в 64-битном коде. Я бы изменить его на:

movl $0, %rdi 
loop : 
movl values(, %rdi, 4), %eax 

Если ни один из этих двух работ, так как адрес values более 2 Гб от rip (факт: перемещения ограничены 32-разрядных целых чисел в памяти операндов в большинстве инструкций в 64-битном режиме, и большинство из них не имеют кодировки операнда памяти только для перемещения в 64-битном режиме, они используют rip - относительную адресацию там), вам нужно будет вручную добавить 64-разрядный адрес values, а индекс в массив, умноженный на 4. Убедитесь, что вы делаете 64-битное дополнение без каких-либо усечений на этом пути.

Must-гласит:

  • System V Application Binary Interface AMD64 Архитектура процессора Дополнение Проект Версия 0.99.6

  • Вызов соглашения для различных компиляторов C++ и операционные системы По Agner Туман

+0

Ты такой добрый. Большое спасибо. Я читаю книгу PROFESSIONAL ASSEMBLY LANGUAGE, чьи образцы кода были написаны на 32-битной ОС, поэтому я столкнулся с множеством проблем, когда тестировал их на своей 64-битной ОС. Еще раз спасибо! – Nmzzz

Смежные вопросы