
- •Подпрограммы
- •Передача и возврат управления
- •Вызов функции ЯВУ
- •Соглашения о вызовах (32 бита)
- •Соглашения о вызовах (64 бита)
- •Локальные переменные
- •Сохранение/восстановление регистров
- •Классический (16/32/64) пролог/эпилог
- •Оптимизированный пролог/эпилог (32/64)
- •Локальные переменные над стеком (32/64)
- •Совмещение C++ и ассемблера
- •Сборка
- •Описание C-функций на ассемблере
- •Вызов C-функций из ассемблера
- •Искажение имён
- •Искажение имён в MS Windows 32 и Mac OS X
- •Компенсация искажения имён вручную
- •Про платформы
- •ОС и программа
- •C-функция foo() на различных платформах

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
1 / 29 |
Подпрограммы
Александра Игоревна Кононова
МИЭТ
26 октября 2021 г. актуальную версию можно найти на https://gitlab.com/illinc/arch-cs
Подпрограммы |
} GNU/Linux, BSD (кроме Mac OS X), 32 |
Локальные переменные |
} Mac OS X и MS Windows, 32 |
Совмещение C++ и ассемблера |
} GNU/Linux, BSD (кроме Mac OS X), 64 |
Искажение имён |
} Mac OS X, 64 |
Про платформы |
} MS Windows, 64 |

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
2 / 29 |
Вывод чисел (C++)
#include <stdio.h>
const char* fmt = "x = %d, y = %d\n"; int x = +122;
int main()
{
printf(fmt, x, -13); return 0;
}
$ g++ main.cpp $ ./a.out
x = 122, y = -13
Подпрограммы |
} GNU/Linux, BSD (кроме Mac OS X), 32 |
Локальные переменные |
} Mac OS X и MS Windows, 32 |
Совмещение C++ и ассемблера |
} GNU/Linux, BSD (кроме Mac OS X), 64 |
Искажение имён |
} Mac OS X, 64 |
Про платформы |
} MS Windows, 64 |

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
|
3 / 29 |
|||||||||||
} GNU/Linux, BSD (кроме |
Mac OS X), 32 |
|
|
|
|
|||||||||
cdecl, нет искажения имён |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fmt: .string "x = %d, y = %d\n" |
|
|
|
|
|
|
|
|
|
|
|
|||
x: .int +122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.globl main |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pushl $-13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pushl x |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pushl $fmt |
printf(fmt, x, -13) |
|
|
|
|
|||||||||
call printf |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
add $3*4, %esp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
xor %eax, %eax |
return 0 из main() |
|
|
|
|
|||||||||
ret |
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*вариант: lea fmt, %eax + push %eax |
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
||||||||||||
|
Подпрограммы |
|
} GNU/Linux, BSD (кроме Mac OS X), 32 |
|||||||||||
Локальные переменные |
|
} Mac OS X и MS Windows, 32 |
|
|
|
|
||||||||
Совмещение C++ и ассемблера |
|
} GNU/Linux, BSD (кроме Mac OS X), 64 |
||||||||||||
|
Искажение имён |
|
} Mac OS X, 64 |
|
|
|
|
|||||||
|
Про платформы |
|
} MS Windows, 64 |
|
|
|
|

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
4 / 29 |
|
} Mac OS X и MS Windows, 32 |
|
||
cdecl, префикс-подчёркивание |
|
||
.data |
|
|
|
fmt: .string "x = %d, y = %d\n" |
|
||
x: .int +122 |
|
|
|
.text |
|
|
|
.globl _main |
|
|
|
_main: |
|
|
|
pushl $-13 |
|
|
|
pushl x |
printf(fmt, x, -13) |
|
|
pushl $fmt |
|
||
call _printf |
|
|
|
add $3*4, %esp xor %eax, %eax ret
Подпрограммы |
} GNU/Linux, BSD (кроме Mac OS X), 32 |
Локальные переменные |
} Mac OS X и MS Windows, 32 |
Совмещение C++ и ассемблера |
} GNU/Linux, BSD (кроме Mac OS X), 64 |
Искажение имён |
} Mac OS X, 64 |
Про платформы |
} MS Windows, 64 |

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
|
5 / 29 |
|||||||||||
} GNU/Linux, BSD (кроме |
Mac OS X), 64 |
|
|
|
|
|||||||||
System V amd64 psABI, нет искажения имён |
|
|
|
|
||||||||||
.data |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fmt: .string "x = %d, y = %d\n" |
|
|
|
|
|
|
|
|
|
|
|
|||
x: .int +122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.text |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.globl main |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
main: |
выравнивание sp на 16 после call main |
|
|
|
|
|||||||||
sub $8, %rsp |
|
|
|
|
||||||||||
lea fmt(%rip), %rdi |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
movslq x(%rip), %rsi |
printf(fmt, x, -13) |
|
|
|
|
|||||||||
mov $-13, %rdx |
|
|
|
|
|
|||||||||
mov $0, %al |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
call printf |
восстановление sp перед ret из main |
|
|
|
|
|||||||||
add $8, %rsp |
|
|
|
|
||||||||||
xor %eax, %eax |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вариант выравнивания/восстановления sp: push %rbp + pop %rbp |
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
|
Подпрограммы |
|
} GNU/Linux, BSD (кроме Mac OS X), 32 |
|||||||||||
Локальные переменные |
|
} Mac OS X и MS Windows, 32 |
|
|
|
|
||||||||
Совмещение C++ и ассемблера |
|
} GNU/Linux, BSD (кроме Mac OS X), 64 |
||||||||||||
|
Искажение имён |
|
} Mac OS X, 64 |
|
|
|
|
|||||||
|
Про платформы |
|
} MS Windows, 64 |
|
|
|
|

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
6 / 29 |
} Mac OS X, 64
System V amd64 psABI, префикс-подчёркивание
.data
fmt: .string "x = %d, y = %d\n" x: .int +122
.text
.globl _main _main:
sub $8, %rsp выравнивание sp на 16 после call main lea fmt(%rip), %rdi
movslq x(%rip), %rsi mov $-13, %rdx
mov $0, %al call _printf add $8, %rsp xor %eax, %eax ret
Подпрограммы |
} GNU/Linux, BSD (кроме Mac OS X), 32 |
Локальные переменные |
} Mac OS X и MS Windows, 32 |
Совмещение C++ и ассемблера |
} GNU/Linux, BSD (кроме Mac OS X), 64 |
Искажение имён |
} Mac OS X, 64 |
Про платформы |
} MS Windows, 64 |

МИЭТ, СПИНТех, КАИ |
Подпрограммы |
7 / 29 |
||||||||||
} MS Windows, 64 |
|
|
|
|
|
|
|
|
|
|
|
|
Соглашение Microsoft 64, нет искажения имён |
|
|
|
|
||||||||
.data |
|
|
|
|
|
|
|
|
|
|
|
|
fmt: .string "x = %d, y = %d\n" |
|
|
|
|
|
|
|
|
|
|||
x: .int +122 |
|
|
|
|
|
|
|
|
|
|
|
|
.text |
|
|
|
|
|
|
|
|
|
|
|
|
.globl main |
|
|
|
|
|
|
|
|
|
|
|
|
main: |
выравнивание sp на 16 после call main |
|
|
|
|
|||||||
sub $8, %rsp |
|
|
|
|
||||||||
sub $32, %rsp |
|
|
|
|
|
|
|
|
|
|
|
|
lea fmt(%rip), %rcx |
|
|
|
|
|
|
|
|
|
|
|
|
movslq x(%rip), %rdx |
printf(fmt, x, -13) |
|
|
|
|
|||||||
mov $-13, %r8 |
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
call printf |
|
|
|
|
|
|
|
|
|
|
|
|
add $32, %rsp |
восстановление sp перед ret из main |
|
|
|
|
|||||||
add $8, %rsp |
|
|
|
|
||||||||
xor %eax, %eax |
|
|
|
|
|
|
|
|
|
|
|
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
вариант выравнивания/восстановления sp: push %rbp + pop %rbp |
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
|
Подпрограммы |
|
} GNU/Linux, BSD (кроме Mac OS X), 32 |
|||||||||
Локальные переменные |
|
} Mac OS X и MS Windows, 32 |
|
|
|
|
||||||
Совмещение C++ и ассемблера |
|
} GNU/Linux, BSD (кроме Mac OS X), 64 |
||||||||||
|
Искажение имён |
|
} Mac OS X, 64 |
|
|
|
|
|||||
|
Про платформы |
|
} MS Windows, 64 |
|
|
|
|

|
МИЭТ, СПИНТех, КАИ |
Подпрограммы |
|
8 / 29 |
|||
Передача и возврат управления |
|
|
|
|
|||
|
|
|
|
||||
|
jmp smem |
передача управления (goto smem) smem ! ip |
|||||
|
jCC smem |
передача управления smem ! ip, если верно CC 2 flags |
|
||||
|
call smem |
вызов подпрограммы |
push ip; |
smem ! ip |
|
||
|
ret |
возврат |
pop ip |
|
|
|
|
|
ret imm16 |
возврат с чисткой стека |
pop ip; |
sp += imm16 |
|
Флаги: не изменяются
|
|
: : : |
|
|
sp |
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
sp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Стек |
|
|
|
|
|
|
ci+1 |
|
|
sp |
|
ci+1 |
|
|
sp |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret |
|
|
|
|
ret |
|
|
|
|
ret |
|
|
ip |
|
ret |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
: : : |
|
|
f() |
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
Код |
f : |
|
|
|
|
f : |
|
|
|
ip |
f : |
|
|
|
|
f : |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
: : : |
|
|
|
|
ci+1 : |
|
|
|
|
ci+1 : |
|
|
|
|
ci+1 : |
|
|
|
|
ci+1 : |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ip |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
ci : |
call f |
|
|
ip |
ci : |
call f |
|
|
|
ci : |
call f |
|
|
|
ci : |
call f |
|
|
|
|
|
|
|
|
|
|
|
|
адреса растут снизу вверх
а) б) в) г)
Подпрограммы |
Передача и возврат управления |
|
Локальные переменные |
||
Вызов функции ЯВУ |
||
Совмещение C++ и ассемблера |
||
Соглашения о вызовах (32 бита) |
||
Искажение имён |
||
Соглашения о вызовах (64 бита) |
||
Про платформы |
||
|

|
МИЭТ, СПИНТех, КАИ |
|
Подпрограммы |
9 / 29 |
Вызов функции ЯВУ |
|
|
|
|
|
Требования к вызовам подпрограммы (в т. ч. функции ЯВУ) |
|
||
1 |
передача управления на произвольный адрес; |
|
||
2 |
возврат управления назад после завершения подпрограммы; |
|
||
3 |
вложенные вызовы подпрограмм; |
|
||
4 |
сохранение и восстановление регистров вызывающей программы; |
|
||
5 |
передача заданного количества аргументов; |
|
||
6 |
передача и возврат структур; |
|
|
7выделение и освобождение памяти под локальные переменные подпрограмм.
1-3 call/ret, 4-6 соглашения, 7 традиции (пролог/эпилог).
|
Соглашение о вызовах |
|
1 |
способ передачи аргументов (через регистры, через стек, смешанный); |
|
2 |
порядок в стеке (Pascal первый помещается первым, C последним); |
|
3 |
кто очищает стек и сохраняет/восстанавливает регистры (и какие). |
|
|
Возвращаемое значение: |
1 целое или указатель A (D : A); |
2 |
вещественное st(0) (32-битный режим), xmm0=ymm0=zmm0 (64). |
Подпрограммы |
Передача и возврат управления |
|
Локальные переменные |
||
Вызов функции ЯВУ |
||
Совмещение C++ и ассемблера |
||
Соглашения о вызовах (32 бита) |
||
Искажение имён |
||
Соглашения о вызовах (64 бита) |
||
Про платформы |
||
|

|
|
МИЭТ, СПИНТех, КАИ |
|
Подпрограммы |
|
|
|
|
|
|
10 / 29 |
|
||||||||
Соглашения о вызовах (32 бита) |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
Соглашение |
Параметры |
Порядок |
|
Выр.sp |
|
Очистка стека |
Изменяемые |
Неизменяемые регистры |
Результат |
|
|||||||||
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
в регистрах |
в стеке |
|
|
|
регистры |
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cdecl |
|
C |
|
на 16) |
|
вызывающая |
|
|
|
|
|
|
|
|
|
st(0) |
|
||
|
|
|
|
|
|
программа |
eax; |
|
|
|
|
|
||||||||
|
pascal |
|
Pascal |
|
|
функция |
ecx; edx; |
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
st(0) st(7); |
|
= |
|
||||||||
|
winapi |
|
C |
|
|
функция |
ebx; ebp; |
|
||||||||||||
|
(stdcall) |
|
|
|
MacOS X |
|
|
|
|
xmm; |
esi; edi |
=edx:eax |
|
|||||||
|
gnu |
|
C |
|
|
this функция, |
ymm; |
|
|
|
|
|
||||||||
|
|
|
|
|
|
вызывающая |
zmm; |
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
остальные |
|
|
|
|
|
|
|||||||
|
|
|
|
|
байта(в |
|
программа |
|
|
|
|
|
|
|
|
|
eax |
|
||
|
gnu fastcall |
ecx; edx |
C |
|
|
функция |
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
gnu |
eax; edx; ecx |
C |
|
|
|
функция |
|
|
|
|
|
|
|
|
|
|
|
||
|
regparm(3) |
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Borland |
ecx; edx |
Pascal |
|
на |
|
функция |
|
|
|
|
|
|
|
|
|
|
|
||
|
fastcall |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Microsoft |
ecx; edx |
C |
|
|
|
функция |
|
|
|
|
|
|
|
|
|
|
|
||
|
fastcall |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
Подпрограммы |
|
Передача и возврат управления |
|
|
|
|
|
|
|||||||||
|
|
Локальные переменные |
|
|
|
|
|
|
|
|||||||||||
|
|
|
Вызов функции ЯВУ |
|
|
|
|
|
|
|||||||||||
|
|
Совмещение C++ и ассемблера |
|
|
|
|
|
|
|
|||||||||||
|
|
|
Соглашения о вызовах (32 бита) |
|
|
|
|
|
|
|||||||||||
|
|
|
Искажение имён |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
Соглашения о вызовах (64 бита) |
|
|
|
|
|
|
||||||||||
|
|
|
Про платформы |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
МИЭТ, СПИНТех, КАИ |
|
|
Подпрограммы |
|
|
|
11 / 29 |
|
|||
|
Соглашения о вызовах (64 бита) |
|
|
|
|
|
||||||||
|
ОС |
Соглашение |
Параметры в регистрах |
Порядок в стеке |
Выр. sp |
перед call |
Очистка стека |
Особенности работы со стеком |
Изменяемые регистры |
Неизменяемые регистры |
Результат |
|
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
X) |
64MicrosoftSystem V amd64 psABI |
rdi; rsi; |
|
байт16наили32(на64, если через стек |
или32передаётся64-байтовое целое) |
вызывающаяпрограмма |
красная зона 128 |
rax; rcx; rdx; |
rbx; rbp; |
rax; |
|
||
|
WindowsMS |
|
|
программа |
частей 6 15 |
|
|
|
|
|||||
|
BSD GNU/Linux, OS Mac (включая |
|
rdx; rcx; r8; r9; |
|
|
|
|
|
байт над стеком |
rsi; rdi; |
r12 r15 |
rdx:rax, |
|
|
|
|
xmm0 xmm7 |
C |
|
|
|
|
прерываниями |
r8 r11; |
|
|
xmm0, |
|
|
|
|
при переменном |
|
|
|
|
|
и системными |
st(0) st(7); |
|
|
st(0) |
|
|
|
|
кол-ве парам-в |
|
|
|
|
|
вызовами) |
|
|
|
|||
|
|
|
(как в printf/scanf) |
|
|
|
|
|
обеспечивает ОС |
x=y=zmm |
|
|
|
|
|
|
|
кол-во xmm |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в al |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rcx=xmm0; |
|
|
|
|
|
теневые 32 байта |
rax; rcx; rdx; |
rbx; rbp; |
rax; |
|
|
|
|
|
rdx=xmm1; |
|
|
|
|
|
под адресом |
r8 r11; |
rsi; rdi; |
xmm0 |
|
|
|
|
|
|
|
|
|
|
возврата (но над |
|
|||||
|
|
|
r8=xmm2; |
|
|
|
|
|
стековыми |
st(0) st(7); |
r12 r15; |
|
|
|
|
|
|
r9=xmm3 |
|
|
|
|
|
обеспечивает |
x=y=zmm; |
xmm6 |
|
|
|
|
|
|
|
|
|
|
|
|
параметрами) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вызывающая |
кроме младших |
xmm15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Перед call sp = 16x ! после входа в функцию sp = 16x 8 (64-битный адрес возврата)
Подпрограммы |
Передача и возврат управления |
|
Локальные переменные |
||
Вызов функции ЯВУ |
||
Совмещение C++ и ассемблера |
||
Соглашения о вызовах (32 бита) |
||
Искажение имён |
||
Соглашения о вызовах (64 бита) |
||
Про платформы |
||
|