Почему эта ассемблерная программа ничего не выводит?

Будучи новичком в сборке x86_64, я пытаюсь написать базовую программу «hello» на своем ноутбуке с 64-битной OpenBSD. Программа завершается с кодом выхода 0, но, похоже, игнорирует системный вызов для записи текста в стандартный вывод. Почему?

Я использую ассемблер GNU и создаю исполняемый файл с помощью:

as -o hello.o hello.s; ld -Bstatic hello.o

# OpenBSD ELF identification
.section ".note.opensd.ident", "a"
.p2align 2
.long 0x8
.long 0x4
.long 0x1
.ascii "OpenBSD\0"
.long 0x0
.p2align 2

.section .data
msg: .ascii "hello"

.section .text
.globl _start
_start:
    push $5 # number of bytes to write
    push $msg # message address
    push $1 # file descriptor 1 for stdout
    mov $4, %eax # write is system call 4
    syscall

    push $0 # exit code 0
    mov $1, %eax # exit is system call 1
    syscall

person user1613254    schedule 10.01.2015    source источник
comment
Я не знаю насчет OpenBSD, но в Linux вы должны передавать аргументы в rdi/rsi/rdx/r10/r8/r9, если хотите использовать syscall, а не стек. Кажется, быть таким же во FreeBSD. Может быть, вы путаете системный вызов и int 0x80?   -  person tux3    schedule 10.01.2015
comment
Передача параметров в регистры работала. Судя по всему, 32-битные BSD используют стек, а 64-битные версии используют регистры. Если вы не возражаете, в чем разница между системным вызовом и int 0x80? Насколько я читал, int 0x80 просто означает прерывание 80, которое используется для системных вызовов.   -  person user1613254    schedule 13.01.2015


Ответы (1)


Поскольку вы пометили x86_64 и, вероятно, находитесь в системе x86_64. Поэтому вам необходимо:

  • as --64
  • используйте pushq вместо pushl, чтобы поместить 64-битные значения в стек
  • передать эти значения в соответствующие регистры перед системным вызовом

    .section ".note.opensd.ident", "a"
    .p2align 2
    .long 0x8
    .long 0x4
    .long 0x1
    .ascii "OpenBSD\0"
    .long 0x0
    .p2align 2
    
    .section .data
     msg: .ascii "hello"
    
    .section .text
    .globl _start
    _start:
            pushq $0x4
            popq %rax               # 4 (write syscall) into rax
            pushq $0x1
            popq %rdi               # 1 (STDOUT) into rdi
            pushq $msg
            popq %rsi               # address of hello msg into rsi
            pushq $0x5
            popq %rdx               # length of hello msg into rdx
            syscall
            pushq $1
            popq %rax
            pushq $0
            popq %rdi
            syscall
    

следующие статьи предлагают некоторую полезную информацию:

ассемблер x64 на FreeBSD

различия между x86 и x64 asm

person ramrunner    schedule 11.01.2015
comment
Принято за рабочий код, и спасибо за статьи. - person user1613254; 13.01.2015
comment
push $4 / pop %rax — странный и неэффективный способ записи mov $4, %eax. Обычно вы делаете такие вещи только в том случае, если вы оптимизируете размер кода по скорости или пишете шелл-код, который должен избегать 00 байтов в машинном коде. И когда у вас есть одна константа, вы можете lea других относительно нее с помощью 3-байтовой инструкции, такой как lea -3(%rax), %edi, если вы действительно хотите оптимизировать размер кода, а не производительность и читабельность. - person Peter Cordes; 22.05.2021