Сборочный исполняемый файл на Bash в Ubuntu в Windows не выводит
Я искал учебник по сборке, и я пытаюсь заставить программу hello world работать. Я использую Bash на Ubuntu в Windows.
Вот сборка:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
Я использую эти команды для создания исполняемого файла:
nasm -f elf64 hello.asm -o hello.o
ld -o hello hello.o -m elf_x86_64
И я запускаю его, используя:
./hello
Кажется, что программа работает без ошибки или ошибки сегментации, но не выдает никаких результатов.
Я не могу понять, почему код не будет выдавать результат, но мне интересно, имеет ли какое-либо отношение к этому использование Bash в Ubuntu в Windows? Почему он не производит вывод и как я могу это исправить?
2 ответа
Проблема связана с Ubuntu для Windows (подсистема Windows для Linux). Поддерживает только 64-бит syscall
интерфейс, а не 32-разрядный x86 int 0x80
механизм системного вызова.
Кроме того, не в состоянии использовать int 0x80
(32-разрядная совместимость) в 64-разрядных двоичных файлах Ubuntu в Windows (WSL) также не поддерживает запуск 32-разрядных исполняемых файлов.
Вам необходимо конвертировать из использования int 0x80
в syscall
, Это не сложно. Другой набор регистров используется для syscall
и номера системных вызовов отличаются от своих 32-битных аналогов. Блог Райана Чепмена содержит информацию о syscall
интерфейс, системные вызовы и их параметры. Sys_write
а также Sys_exit
определяются следующим образом:
%rax System call %rdi %rsi %rdx %r10 %r8 %r9 ---------------------------------------------------------------------------------- 0 sys_read unsigned int fd char *buf size_t count 1 sys_write unsigned int fd const char *buf size_t count 60 sys_exit int error_code
С помощью syscall
также заглушки RCX и регистры R11. Они считаются летучими. Не полагайтесь на то, что они имеют одинаковое значение после syscall
,
Ваш код может быть изменен, чтобы быть:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov rsi,msg ;message to write
mov edi,1 ;file descriptor (stdout)
mov eax,edi ;system call number (sys_write)
syscall ;call kernel
xor edi, edi ;Return value = 0
mov eax,60 ;system call number (sys_exit)
syscall ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string
Примечание: в 64-битном коде, если регистр назначения команды является 32-битным (например, EAX, EBX, EDI, ESI и т. Д.) , Нулевой процессор расширяет результат в верхние 32 -битные 64-битного регистра. mov edi,1
имеет тот же эффект, что и mov rdi,1
,
Этот ответ не учебник по написанию 64-битного кода, а только об использовании syscall
интерфейс. Если вас интересуют нюансы написания кода, который вызывает библиотеку C и соответствует 64-битному ABI System V, есть разумные учебники для начала, например , учебник Рэй Тоа по NASM. Он обсуждает выравнивание стека, красную зону, использование регистров и общий обзор соглашения о вызовах 64-битной системы V.
Как уже указывалось в комментариях Росса Риджа, не используйте 32-битные вызовы функций ядра при компиляции 64-битных.
Либо скомпилируйте для 32-битного, либо "переведите" код в 64-битные системные вызовы. Вот как это может выглядеть:
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov rdx,len ;message length
mov rsi,msg ;message to write
mov rdi,1 ;file descriptor (stdout)
mov rax,1 ;system call number (sys_write)
syscall ;call kernel
mov rax,60 ;system call number (sys_exit)
mov rdi,0 ;add this to output error code 0(to indicate program terminated without errors)
syscall ;call kernel
section .data
msg db 'Hello, world!', 0xa ;string to be printed
len equ $ - msg ;length of the string