Сборочный исполняемый файл на 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
Другие вопросы по тегам