x86_64 Сборка Linux Системный вызов Путаница - PullRequest
14 голосов
/ 14 декабря 2011

Я сейчас изучаю ассемблер на Linux.Я использую книгу «Программирование с нуля», и все примеры 32-битные.Моя ОС 64-битная, и я пытаюсь сделать все примеры в 64-битной.Однако у меня возникли проблемы:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rbx
int $0x80

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

.section .data

.section .text
.global _start
_start:
movq $1, %rax
movq $2, %rbx
int $0x80

, это работает.Очевидно, проблема заключается в значении, которое я перемещаю в% rax.Значение $ 1, которое я использую во втором примере, - это то, что «Программирование с нуля» сказал использовать, однако несколько источников в Интернете сказали, что номер 64-битного системного вызова составляет $ 60.Я делаю не так?Кроме того, какие другие вопросы я должен остерегаться и что я должен использовать для справки?На всякий случай, если вам нужно знать, я в главе 5 «Программирование с нуля».

Ответы [ 5 ]

17 голосов
/ 14 декабря 2011

Вы столкнулись с одним удивительным отличием между i386 и x86_64: они не используют один и тот же механизм системных вызовов.Правильный код:

movq $60, %rax
movq $2,  %rdi   ; not %rbx!
syscall

Прерывание 0x80 всегда вызывает 32-битные системные вызовы.Он используется для того, чтобы 32-битные приложения могли работать в 64-битных системах.

В целях обучения вам, вероятно, следует стараться точно следовать учебному руководству, а не переводить на лету 64-битные -Есть несколько других существенных поведенческих различий, с которыми вы можете столкнуться.Как только вы ознакомитесь с i386, , затем , вы можете получить x86_64 отдельно.

12 голосов
/ 14 декабря 2011

пожалуйста, прочитайте это Каковы соглашения о вызовах для системных вызовов UNIX и Linux на x86-64

и обратите внимание, что использование int 0x80 для системного вызова в системах x64 - это старый уровень совместимости. Вы должны использовать инструкцию syscall в системах x64.

вы все еще можете использовать этот старый метод, но вам нужно скомпилировать ваши двоичные файлы в режиме x86, подробности см. В руководстве по сборке / сборке.

7 голосов
/ 20 июля 2015

duskwuff * answer правильно указывает, что механизм для системных вызовов отличается для 64-битной x86 Linux и 32-битной Linux.

Однако этот ответ является неполным и вводящим в заблуждение по нескольким причинам:

Как указано в комментариях , SYSENTER на самом деле не работает во многих 64-битных системах Linux - а именно, 64-битных AMD системы.

Это заведомо запутанная ситуация. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1049].

Для 32-битного ядра SYSENTER / SYSEXIT - единственная совместимая пара [между процессорами AMD и Intel]

Только для 64-битного ядра в длинном режиме… SYSCALL / SYSRET - единственная совместимая пара [между процессорами AMD и Intel]

Похоже, что на Intel CPU в 64-битном режиме вы можете избежать использования SYSENTER, потому что он делает то же самое, что и SYSCALL, однако это не относится к AMD системы.

Итог: всегда используйте SYSCALL в Linux на 64-битных системах x86 . Это то, что на самом деле указывает ABI x86-64. (См. Этот замечательный вики-ответ для более подробной информации.)

4 голосов
/ 14 декабря 2011

Многое изменилось между i386 и x86_64, включая как инструкцию, используемую для входа в ядро, так и регистры, используемые для передачи аргументов системного вызова. Вот код, эквивалентный вашему:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall

Цитата из этого ответа на связанный вопрос:

Номера системных вызовов находятся в исходном коде Linux в arch / x86 / include / asm / unistd_64.h. Номер системного вызова передается в регистр rax. Параметры указаны в rdi, rsi, rdx, r10, r8, r9. Вызов вызывается с помощью инструкции "syscall". Системный вызов перезаписывает регистр rcx. Возврат в rax.

2 голосов
/ 29 сентября 2012

Если вы отметите /usr/include/asm/unistd_32.h, выход соответствует 1, но в /usr/include/asm/unistd_64.h выход соответствует 60.

...