процедуры сборки вызываются дважды, даже не вызываясь из основного - PullRequest
5 голосов
/ 11 декабря 2011

Я пытаюсь определить некоторые подпрограммы, в которых есть вызовы printf. Очень тривиальный пример:

extern printf
LINUX        equ     80H
EXIT         equ     60

section .data
    intfmt: db "%ld", 10, 0

segment .text
    global  main

main:
    call os_return      ; return to operating system

os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    int  LINUX      ; Interrupt Linux kernel

test:
    push rdi
    push rsi
    mov rsi, 10
    mov rdi, intfmt
    xor rax, rax
    call printf
    pop rdi
    pop rsi
    ret

Здесь у теста просто есть вызов printf, который выводит число 10 на экран. Я не ожидал бы, что это вызовут, поскольку у меня нет вызова к нему.

Однако при компиляции и запуске:

nasm -f elf64 test.asm
gcc -m64 -o test test.o

Я получаю вывод:

10
10

Я совершенно сбит с толку и спрашиваю себя, может ли кто-нибудь объяснить, почему это происходит?

Ответы [ 2 ]

3 голосов
/ 11 декабря 2011

int 80H вызывает 32-битный интерфейс системных вызовов, который a) использует 32-битные номера системных вызовов и b) предназначен для использования 32-битным кодом, а не 64-битным кодом. Ваш код фактически выполняет системный вызов umask со случайными параметрами.

Для 64-разрядного системного вызова используйте вместо него инструкцию syscall:

...
os_return:
    mov  rax, EXIT      ; Linux system call 60 i.e. exit ()
    mov  rdi, 0     ; Error code 0 i.e. no errors
    syscall         ; Interrupt Linux kernel
...
2 голосов
/ 11 декабря 2011

Я бы сказал, что ваш вызов exit не работает, поэтому, когда он возвращается, он переходит к функции test, которая печатает первые 10.

Затем, когда вы вернетесь с ret, вы вернетесь к инструкции сразу после call os_return, то есть, ну os_return. Вызов exit завершается неудачей снова и снова переходит к функции test. Но на этот раз ret возвращается из функции main, и программа завершается.

О причине сбоя вызова exit я не могу сказать, поскольку у меня нет 64-битной системы. Но вы можете разобрать функцию exit из libc и посмотреть, как это там делается. Я предполагаю, что интерфейс int LINUX является 32-битным только, поскольку он существует только для исторической совместимости, а 64-битный Linux не так уж и стар.

...