Пирогов Владислав Юрьевич

О программировании, ИТ и обо всем по немногу

64-битовое программирование в Linux на ассемблере
[info]pirogov_vju


Для вызова системных функций в Unix-системах на ассемблере можно использовать системный вызов (шлюз) 0x80. Однако, во-первых, нотация вызова может меняться от версии к версии, во-вторых, от одной Unix-системы, к другой. Изначально, в качестве прослойки, наподобие  функций API в Unix-системах использовались функции из стандартных библиотек языка C.

В 64-битных Unix-системах также произошел переход к соглашению о передаче параметров по средством регистров. Для передачи параметров, представляющих целые числа (в том числе и ссылки)  используются последовательно шесть регистров: rdi, rsi, rdx, rcx, r8, r9. Если количество параметров превышает шесть, то оставшиеся параметры передаются через стек. При этом, как и раньше следует помнить о выравнивании стека по границе кратной 16 байтов. 
В качестве примера того, как параметры передаются системным функциям, приведем пример, в котором используются две системные функции gets, exit,  printf. Для того, чтобы рассмотреть возможность использования стека, нами был взят случай с большим количеством параметров (см. вызов функции printf).

;вызов системных функций на ассемблере Unix64
format ELF64 executable 3
entry start
include 'import64.inc'
interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libc.so.6'
import exit, gets, printf
segment readable executable
start:
;в начале организуем стек
push rbp
mov  rbp,rsp
;выделить стек, чтобы в дальнейшем передать через него параметры
sub  rsp,32
;получить строку
mov rdx,1
mov  rsi,100
mov  rdi, buf
call [gets]
;вывод данных с помощью функции printf
;в начале выделим стек для стековых параметров (их будет три)
;параметры
mov  rdi,frmt
mov  rsi,buf
mov  rdx,32
mov  rcx,64
mov  r8,128
mov  r9,256
mov rax,512
mov  [rsp],rax
mov rax,1024
mov [rsp+8],rax
mov rax,2048
mov [rsp+16],rax
call [printf]
;восстановить стек
mov rsp,rbp
pop rbp
;выход из программы
mov  rdi,0
call [exit]
segment readable writeable
buf   db 100 dup(0)
frmt  db "%s %d %d %d %d %d %d %d ",10,0

Остановимся на некоторых важных моментах программы.
1. Для доступа к стеку, мы используем не команды push, а прямой доступ к области стека.
2. Для трех параметров (этим параметрам не хватило регистров и они будут передаваться через стек) мы выделяем 32 байта (команда sub rsp,32), так чтобы стек был выровнен по адресу, кратному 16 (Команды push rbp/sub rsp,32 плюс вызов процедуры (еще 8 байтов) в результате дают смещение в стеке равное 48 байтов, что кратно 16).
Для передачи параметров имеющих вещественный тип (64-х битовый) также как и в случае операционной системы Windows используются регистры группы xmm. Для возвращения данных из функции используются  регистры rax и xmm0.
 


Как и раньше для трансляции достаточно написать fasm prog.asm и получаем исполняемый модуль.

Продолжение следует...

Пирогов В.Ю. (http://asm.shadrinsk.net
  • 2
  • Leave a comment
  • Add to Memories

64-битовое программирование в Windows на ассемблере
[info]pirogov_vju
Первой вопрос, который, я хочу рассмотреть и  который, мне кажется, сейчас очень важным, это 64-битовое программирование.  Естественно речь пойдет об ассемблере. В качестве такового возьмем  fasm. Во-первых, поддерживает 64-битовое программирование, во-вторых, этот ассемблер является кроссплатформенным. Для того, чтобы начать писать 64-битовые программы достаточно 1. Узнать структуру программы; 2. Использовать правильное соглашение вызова системных и вообще функций.
Программирование в Windows.
В 64-битовых Windows принята следующая конвенция вызова функций (в том числе вызов функций API).
1. Первые четыре параметра передаются в функцию через регистры: rcx, rdx, r8, r9. Остальные параметры (если они есть) передаются через стек.
2. Перед вызовом функции резервируется область в стеке, на случай, если вызываемая функция "захочет" временно сохранить параметры в стеке. Таким образом, параметры, которые передаются через стек, помещаются туда после резервируемой области.
3. При передаче параметров, размер которых меньше 64 бит, передаются как 64-битовые параметры. При этом следует обнулить старшие биты. Параметры, большие 64-бит передаются по ссылке.
4. Данные возвращаются через регистр rax. Если возвращаемое значение имеет размер больший 64 бит, то данное передается через область памяти, адрес которой передается в первом параметре. Для возвращения может также использоваться регистр xmm0.
5. Все регистры при вызове функций сохраняются за исключением rax, rcx, rdx, r8, r9, r10, r11, сохранность которых не гарантируется.
6. Граница стека должна быть выровнена по адресу кратному 16.
Рассмотрим в общих чертах схему вызова функции API с пятью параметрами.

...
sub rsp,40 ; резервируем стек
mov qword ptr [rsp+32],par5
mov r9,par4
mov r8,par3,
mov rdx,par2
mov cdx,par1
call f_api64
...
add rsp,40 ;восстанавливаем стек
...

Обратите внимание, что в нашем случае стек с учетом адреса возврата при вызове функции оказывается выровненным на величину кратную 16 (48 байт). С учетом такого выравнивания вызов функции, содержащей только 4 параметра будет выглядеть так

sub rsp,40 ; резервируем стек
mov r9,par4
mov r8,par3,
mov rdx,par2
mov cdx,par1
call f_api64
...
add rsp,40 ;восстанавливаем стек


Рассмотрим следующую программу

format PE64 GUI
entry start
section '.text' code readable executable
start:
sub rsp,8*5
mov r9,0
lea r8,[_caption]
lea rdx,[_message]
mov rcx,0
call [MessageBoxA]
add rsp,40
sub rsp,16
mov ecx,eax
call [ExitProcess]
section '.data' data readable writeable
_caption db 'Win64 assembly program',0
_message db 'Hello World!',0
section '.idata' import data readable writeable
dd 0,0,0,RVA kernel_name,RVA kernel_table
dd 0,0,0,RVA user_name,RVA user_table
dd 0,0,0,0,0
kernel_table:
ExitProcess dq RVA _ExitProcess
dq 0
user_table:
MessageBoxA dq RVA _MessageBoxA
dq 0
kernel_name db 'KERNEL32.DLL',0
user_name db 'USER32.DLL',0
_ExitProcess dw 0
db 'ExitProcess',0
_MessageBoxA dw 0
db 'MessageBoxA',0

Если имя программы prog.asm, то компилируется она просто командой
fasm prog.asm

Как видите, в Windows все просто.

Пирогов В.Ю, (
http://asm.shadrinsk.net)


Linux 64, продолжение следует...

  • Leave a comment
  • Add to Memories

Объяснение
[info]pirogov_vju
Вот уже двадцать пять с лишним лет я программирую, преподаю, пишу книги. В 2003-м году появился в сети мой сайт Ассемблер и не только (http://asm.shadrinsk.net). Сайт был посвящен в основном программированию на языке ассемблера.
В прошлом году я полностью переделал сайт, однако чувство неудовлетворенности не оставляет меня. Дело в том, что на сайте отсутствует форум и блог. Времени у меня слишком мало, чтобы разрабатывать самому, а чужими продуктами пользоваться не хочется. С другой стороны есть настоятельная необходимость некоторого общения с читателями. На сайт присылаются вопросы, ответы на которые могли бы быть интересны и другим любителям программирования. Я подумал, что ЖЖ это идеальная площадка для подобного общения. Ну, по крайнй мере, пока у меня на сайте не заработает свой блог.
Мой блог посвящен только темам, так или иначе связанным с программированием и информационными технологиями. В нем не будут обсуждаться другие вопросы нашей жизни, которые меня, естественно интересуют (философия, искусство и т.д.).

Конструктор
[info]pirogov_vju

Никакой информации, просто конструктор.


You are viewing [info]pirogov_vju's journal