Передача аргументов в edi / esi в SysV ABI - PullRequest
1 голос
/ 07 августа 2020

Я хочу писать программы на сборке SysV ABI x86_64, и до сих пор я передавал аргументы в регистры совершенно случайным образом.

Но я только что увидел на этом форуме, что для этого есть стандарт. Мы должны передать RDI, RSI, RDX и RCX (в том же порядке).

Теперь я задаю себе два вопроса.

Во-первых, ESI и EDI не должны использоваться только во время операции со строками? Что произойдет, если я захочу передать в качестве аргумента целое число, а не строку?

Во-вторых, что, если мне нужно передать 32-битный аргумент, а не 64-битный аргумент? Например, если я хочу создать идентификатор для системного вызова write, я бы написал это:

;; void write(int fd, const void *buf, size_t count);
;; Inputs   :  ESI = offset string, EDX = number of characters to write, EBX = file descriptor
;; Outputs  :  <none>
;; Clobbers :  <none>
write:
    mov ecx, esi

    mov eax, 4
    int 0x80

    ret

Но со стандартом, как я могу переместить значения из 64-битных регистров в 32 -битовые регистры? Потому что я не могу этого сделать:

mov ecx, rdi ; impossible

1 Ответ

3 голосов
/ 07 августа 2020

В общем, rdi и rsi можно рассматривать как регистры общего назначения , т.е. вы можете использовать их для произвольных арифметических c и операций с памятью. У них есть особое значение, так как они также используются в качестве индексных регистров для строковых операций. Однако архитектуре безразлично, храните ли вы там строковый указатель или другое произвольное 64-битное число.

Что касается передачи 32-битных значений, вы можете просто получить доступ к младшей 32-битной части вашего исходного регистра:

mov ecx, edi

Это перемещает только младшие 32 бита в ecx. Обратите внимание, что на самом деле это не имеет значения, если вы передадите вместо этого все 64 бита - если вызываемый получает доступ только к 32-битному подрегистру ecx, результат будет таким же:

mov rcx, rdi
; ...
; use ecx

Небольшое примечание относительно примера кода в вопросе: похоже, вы используете 32-битный системный вызов в 64-битной среде. Это может сломаться, если указатель на buf не умещается в 32 бита. 64-битная версия системного вызова write будет выглядеть так:

write:
    ; syscall number
    mov rax, 1

    ; all other arguments are already in the right registers
    syscall

    ret

Дополнительная информация:

...