Я пытаюсь написать простую тестовую программу на ассемблере, которая просто вызывает getchar и передает возвращаемое значение putchar. Мой текущий код выглядит так:
.global main
.text
main:
mov $12,%rbx
.head:
call getchar
mov %rax,%rcx
call putchar
dec %rbx
test %rbx,%rbx
jne .head
call exit
Программа скомпилирована с использованием gcc -o prog prog.s в Windows 10 с Cygwin (с сохранением приведенного выше кода на prog.s).
Я ожидаю, что это будет прочитано из стандартного ввода 12 раз (произвольно) и сразу же отправит 12 прочитанных символов в стандартный вывод. Другими словами, при запуске программы с консоли я ожидаю, что она будет ждать, пока что-то не будет введено в консоль и не будет нажата клавиша Enter. Вместо этого на самом деле происходит следующее: когда я запускаю его, он немедленно выводит 12, казалось бы, бессмысленных символов и завершает работу:
������������
В предыдущих программах, которые вызывали функцию C, которая использовала в себе getchar, затем выводила на печать символ чтения, а также результат для ferror(stdin). getchar, по-видимому, вернул -1, и флаг ошибки stdin был установлен, как только был вызван getchar. Почему это могло происходить? Тем более, что программа, написанная исключительно на C, может без проблем вызывать getchar.
Я использовал -o prog при компиляции, но он все еще сохранен на prog.exe, и file prog показывает, что это исполняемый файл PE32 +, x86-64, для MS-Windows.
На всякий случай добавьте -mconsole в командную строку gcc.
Добавление -mconsole не повлияло на поведение или результат file prog.
Обратите внимание, что вы неправильно выравниваете стек и не настраиваете теневое пространство, как того требует соглашение о вызовах. Вставка subq $40, %rsp после main: заставляет его работать, используя wine, по крайней мере, на Linux.
Почему 40-5 слов - это значение, которое нужно добавить в стек? Есть ли какое-то гарантированное выравнивание или несовпадение стека при запуске программы?
Вам нужно добавить 8 для выравнивания (поскольку CALL выталкивает еще 8 байтов). 32 предназначены для теневого пространства. См. Документацию по соглашению о вызовах. Это сработало?
@Jester: Я заметил отсутствие выделения нового теневого пространства, но этот main не возвращается: он вызывает exit. Помимо выравнивания, можно позволить getchar наступать на основной адрес возврата и выше, если мы не собираемся возвращаться. Несоосность стека обычно вызывает сбой или отсутствие эффекта, но вполне вероятно, что getchar делает предположение о том, что будет указывать где где после AND. Хотя маловероятно.
Выравнивание стека и настройка теневого пространства заставили его работать.





Возможно ли, что вы действительно использовали подсистему Windows для Linux или что-то в этом роде, где соглашение о вызовах передает первый аргумент в RDI, а не в RCX? Может быть, попробовать еще и
mov %eax, %edi? Однако это не объясняет немедленное возвращениеgetchar. Я удивлен, чтоcall putcharсвязан в Windows, где имена символов C обычно получают подчеркивание в начале, напримерcall _putchar. Используйтеfile prog, чтобы узнать, является ли это исполняемым файлом ELF64 (Linux) или Windows PE / COFF. Тем более, что вы называете егоprog, а неprog.exe.