mov
для EDX бессмысленно, регистр возвращаемого значения - AL / AX / EAX / RAX / RDX: RAX для ширины от 1 до 16 байтов на x86-64. EDX или RDX задействованы только для широких возвращаемых значений, слишком широких, чтобы поместиться в RAX. (Или в 32-битном режиме 64-битные значения возвращаются в паре регистров EDX: EAX, потому что RAX отсутствует.)
Это верно для всех стандартных 32-битных и x86-64 соглашений о вызовах. , включая i386 и x86-64 System V ABI, используемые в GNU / Linux.
Если вы пишете main
или любую функцию, которую хотите вызвать из другого файла, это должен быть символ .globl
. (Если только вы не .include "foo.s"
вместо построения отдельно + связывание.) Это то, что делает его видимым в таблице символов, чтобы компоновщик разрешал ссылки на него. например, из a call main
в уже скомпилированном коде для _start
, в crt0.o
или что-то в этом роде, что вы можете увидеть ссылку g cc, если вы запустите gcc -v foo.S
. (Это было чрезмерное упрощение; glib c s _start
на самом деле передает основной адрес как аргумент в __libc_start_main
, который находится в libc.so.6
, поэтому есть код из библиотеки c, который запускается раньше main
. См. Linux Запуск программы x86 или - Какого черта нам добраться до main ()? )
Если вы создаете stati c исполняемый файл без CRT (определение _start
вместо main
и создание собственного exit_group
системного вызова), вы можете просто добавить инструкции в файл и позволить компоновщику (ld
) выберите верхнюю часть раздела .text
как точку входа ELF, если он не находит символ _start
. (Используйте readelf -a a.out
, чтобы увидеть подобную информацию.)
Если вы планируете запускать программу под GDB только для пошагового выполнения пары инструкций, которые вам интересны, вы можете даже опустить exit-clean часть. (Для этого используйте команду GDB starti
для запуска с временной точкой останова перед первой инструкцией в пространстве пользователя, поэтому вам не нужно устанавливать точку останова вручную по абсолютному адресу (потому что нет символа).)
$ cat > foo.S
mov $1 + 2, %edi # do the math at assemble time
mov $231, %eax # _NR_exit_group
syscall
$ gcc -static -no-pie -nostdlib foo.S # like as + ld manually
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
$ ./a.out ; echo $?
3
$ strace ./a.out
execve("./a.out", ["./a.out"], 0x7ffe0706a3c0 /* 54 vars */) = 0
exit_group(3) = ?
+++ exited with 3 +++
Если ваша система 32-битная, поэтому as
по умолчанию работает в 32-битном режиме, используйте 32-битный int $0x80
с другими регистрами.
Наконец, какой ресурс лучше для поиска кодов операций?
Я обычно оставляю вкладку браузера открытой для https://www.felixcloutier.com/x86/, что является HTML парочкой из руководства Intel тома 2. В исходном PDF-файле есть несколько вводных глав о том, как читать записи, так что проверьте его, если вы найдете какие-либо обозначения сбивающими с толку. Существуют более старые отрывки руководств Intel, в которых нет инструкций по SIMD, так что это бесполезно для меня, но, возможно, то, что вы хотите как новичок.
Другие ресурсы связаны с x86 tag wiki , включая http://ref.x86asm.net/coder64.html, который организован по коду операции, а не по мнемоникам c, и имеет столбцы с краткой справкой, чтобы напомнить вам, читает ли инструкция или модифицирует ФЛАГИ, и если да, то какие и тому подобное.