Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
x64b.pdf
Скачиваний:
75
Добавлен:
10.02.2015
Размер:
4.62 Mб
Скачать

Страничная модель защищенных режимов i386...x64

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Примечания:

 

 

 

 

 

 

Логический адрес

 

 

 

 

 

 

 

 

 

63

 

 

48 47

 

39 38

30 29

 

21 20

12 11

0

 

 

 

- Размер линейного адреса L бит.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- Линейный адрес разбивается на:

 

 

 

 

 

 

15

0

31

 

0

 

 

 

 

 

 

 

 

<signs>

 

#PML4E#PDPTE

 

 

 

смещение

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- младшие P бит — смещение на странице.

 

 

 

 

 

SSSS :

OOOO OOOO

 

 

 

 

 

 

 

 

<signs>

 

#PML4E#PDPTE #PDE

 

 

смещение

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- несколько (k) частей, длиной не более N бит каждая,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<signs>

 

#PML4E#PDPTE #PDE

 

#PTE

смещение

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

задающие индексы в иерархических таблицах страниц.

 

 

(селектор)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#PDE

 

#PTE

смещение

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

- Размер страницы 2P байт.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Сегментное

 

 

 

 

Таблица

 

 

 

 

 

 

 

 

 

 

31

 

22 21

12 11

0

 

 

 

- Размер физического адреса M бит.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#PDE

 

 

смещение

 

 

 

 

 

 

 

 

 

преобразование

 

 

 

4го уровня

 

Таблица

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Большая

 

- На одной странице размещается 2 *8/M записей PTE; т.е.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#PDE

 

#PTE

смещение

 

страница

1G

N=log2(2

P

*8/M).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

указателей

 

 

 

 

 

 

 

данных

 

 

 

 

 

 

 

Линейный адрес

 

 

 

 

 

PML4E

 

 

на каталоги

 

 

 

 

 

10

 

 

10

12

 

 

 

 

- все страницы начинаются на границе, кратной размеру

 

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

данные

 

страницы (т.е. младшие P битов PTE,PDE и т.п. записей не

 

 

 

63

47 32

23

 

 

 

 

 

 

 

 

PDPTE

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

используются для задания адреса кадра).

 

 

 

 

 

SSSS FFFF FFFF FFFF

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Каталог

 

 

 

 

 

 

 

 

 

 

Для i80386 (Pentium без PAE и без PSE-36)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Большая

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страниц

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница

 

L=32, M=32, k=2, N=10, P=12

 

 

 

 

 

 

Страничное

 

63

52 51

32 31

 

12 11

0

 

 

 

 

 

PDE

 

 

 

 

 

 

 

 

данных 4/2M

 

 

 

 

 

 

 

0

 

CR3 каталог страниц

?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница 4K, формат линейного адреса 10-10-12

 

 

 

 

 

преобразование

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

данные

 

большая страница 4M; формат 10-22

 

 

 

 

 

 

 

 

 

PAE

каталог страниц xx000

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Для Pentium с включенным PAE

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Таблица

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

каталог страниц

?

 

PCDPWT

 

 

 

 

 

 

 

 

 

 

Большая

 

 

 

 

 

Физический адрес

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страниц

 

 

 

L=32, M=64 (используется 36), k=3, N=9, P=12

 

 

0

 

 

0

 

CR0

 

MSW

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница

4K

 

 

 

 

 

63

51

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

данных

 

страница 4K, формат 2-9-9-12

 

 

 

 

 

 

 

000F FFFF FFFF FFFF

31

30

29 28

... 19

18 17

16

15

...

 

6

5

4

3

2

1

0

 

 

 

 

 

PTE

 

 

 

 

 

большая страница 2M, формат 2-9-21

 

 

 

 

 

 

4 PB

 

 

 

 

 

 

 

 

 

 

 

данные

 

 

Для x64

 

 

 

 

 

 

 

 

 

 

 

 

 

PG

CD

NW ...

AM -

WP - -

-

- -

-

NE

ET

TS

EM MP PE

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PG=1 страничный режим

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

L=64 (исп. 48), M=64 (исп. 52), k=4, N=9, P=12

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница 4K,формат 9-9-9-9-12

 

 

 

 

 

 

 

 

 

 

 

 

 

CR2 адрес страничного отказа

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница 2M, формат 9-9-9-21

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

страница 1G, формат 9-9-30

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

 

CR4

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Адрес кадра страницы

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

+

Атрибуты PTE, PDE, PDPTE, PML4E

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

31

30

 

 

...

 

 

 

 

6

5

4

3

2

1

0

 

 

Смещение на странице

P

1: признак присутствия в ОЗУ

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

 

 

PAE PSE

 

 

 

R/W 1: страница доступна для изменения

 

 

 

 

 

 

 

 

 

 

 

 

режим PAE разрешен

флаг PDE.PS разрешен

 

 

 

 

Физический адрес

 

U/S 1: страница доступна только из нулевого кольца

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PWT 1: кэш должен использовать сквозную запись

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PTE, 4K

 

 

 

 

63

62

 

52 51

40 39

36 35

32 31

 

 

 

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

 

 

PCD

1: запрещено кэширование этой страницы

 

 

 

 

 

 

 

 

 

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IA-32

 

 

PAT

1: использовать PCD-PWT как индекс атрибутов

 

 

 

 

0 . . . 0

 

 

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

Avl

 

G

PAT

D

A

 

PCD PWT U/S R/W

P

IA-32 + PAE

 

 

A

1: было обращение

 

 

 

 

 

EXB

 

Avl

< . . . >

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

x64

 

 

D

1: страница была изменена

 

 

 

 

63

62

 

52 51

40 39

36 35

32 31

 

 

 

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

PDE

 

 

PS

1: признак большой страницы (2M, 4M, 1G)

 

 

 

 

 

 

 

 

 

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IA-32

 

 

G

1: глобальная таблица (запись сохраняется в TLB)

 

 

 

 

0 . . . 0

 

 

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

Avl

 

G

PS

D

A

 

PCD PWT U/S R/W

P

IA-32 + PAE

 

 

EXB

1: запрет исполнения

 

 

 

 

 

EXB

 

Avl

< . . . >

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

 

 

 

 

=0

 

 

 

 

 

 

x64

 

 

AVL 1: доступны для разработчиков

 

 

 

63

62

 

52 51

40 39

36 35

32 31

 

 

 

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

PDE, страница 4/2M

<...> биты адреса используются конкретными процессорами

Длина

 

 

 

 

 

 

 

Адрес кадра

 

 

0 . . . 0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

IA-32

 

 

CR0

CR4

CR4

MSR

PDE

PDPTE

Платформа

Размер

 

 

 

 

 

 

 

Адрес кадра 31..22

0 . . . 0

Адрес 35...32

PAT

 

Avl

 

G

PS

D

A

 

PCD PWT U/S R/W

P

IA-32 + PSE36

 

 

PG

PSE

PAE

LME

PS

PS

и режим

страницы

адреса

 

 

 

0 . . . 0

 

 

 

Адрес кадра

 

 

 

0 . . . 0

 

 

 

 

 

 

 

 

=1

 

 

 

 

 

 

IA-32 + PAE

 

 

0

x

 

x

x

x

x

i8086

откл.

EXB

 

Avl

< . . . >

 

 

Адрес кадра

 

 

 

 

0 . . . 0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

x64

 

 

1

0

 

0

x

0

x

386

4K

32

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

63

62

 

52 51

40 39

36 35

32 31

 

 

 

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

PDPTE

 

 

1

1

 

0

x

0

x

586

4K

32

 

 

 

0 . . . 0

 

 

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

Avl

 

G

PAT

D

A

 

PCD PWT U/S R/W

P

IA-32 + PAE

 

 

1

1

 

0

x

1

x

586 PS

4M

32

EXB

 

Avl

< . . . >

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

 

 

 

 

1

1

 

0

x

1

x

586 PSE36

4M

36

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

x64

 

 

 

63

62

 

52 51

40 39

36 35

32 31

30 29

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

PDPTE, страница 1G

1

1

 

1

x

0

0

586 PAE

4K

36

EXB

 

Avl

< . . . >

 

Адрес кадра

 

 

 

 

0 . . . 0

 

 

 

 

 

Avl

 

G

PS

D

A

 

PCD PWT U/S R/W

P

x64

 

 

1

1

 

1

x

1

0

586 PAE PS

2M

36

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

=1

 

 

 

 

 

 

PML4E

 

 

1

1

 

1

1

0

0

x64

4K

52

63

62

 

52 51

40 39

36 35

32 31

30 29

22 21

20

 

17 16

15

14

13

12

11

10

9

8

7

6

 

5

4

3

2 1

0

 

 

1

1

 

1

1

1

0

x64 PS

2M

52

EXB

 

Avl

< . . . >

 

 

 

 

Адрес кадра

 

 

 

 

 

 

 

Avl

 

G

PS

D

A

 

PCD PWT U/S R/W

P

x64

 

 

1

1

 

1

1

x

1

x64 PS

1G

52

Соглашения о вызовах C/C++ (платформы IA-32, x64)

 

 

 

 

 

 

#ifdef __cplusplus

Различия C и C++:

 

 

 

 

 

 

 

 

В традиционном соглашении о вызовах языка C принято:

 

 

 

 

 

extern «C» {

а) передача аргументов через стек, справа-налево (первый аргумент размещается в стеке последним)

 

 

#endif

 

б) освобождение фрейма от аргументов выполняет вызывающий код

 

 

 

 

 

int __cdecl test(int x)

в) декорирование имен сводится к добавлению прочерка перед именем функции (т.е. _main и т.п.)

 

 

{

 

 

В случае C++ необходима поддержка перегрузки функций, поэтому используются сложные схемы декорирования имен, сохраняющие

/* ... */

информацию о пространстве имен, классе, типе возвращаемого результата и списке аргументов функции. Для экземплярных методов

}

 

 

классов используется неявный аргумент (обычно первый) — указатель this.

 

 

 

 

#ifdef __cplusplus

Ключевое слово extern задает умолчания, применяемые в программе («C» или «CPP»); а также влияет на декорирование имен.

}

 

 

Явное задание соглашения при описании функции влияет на способ передачи аргументов, но зачастую не влияет на декорирование.

 

 

#endif

 

Точное задание соглашение и декорирования — использование extern и модификаторов соглашения (cdecl, stdcall, fastcall).

 

 

 

 

Различия между разными платформами и компиляторами:

 

 

 

 

 

 

 

 

Компиляторы строго придерживаются принятых соглашений о вызовах только для функций, доступных из внешних модулей. Оптимизатор часто изменяет соглашение,

принятое для локальных функций в части упрощения фрейма процедуры, передачи аргументов через регистры и использования регистров.

 

 

 

Microsoft-совместимые

 

 

 

 

GCC

 

 

 

 

 

IA-32

 

x64

 

IA-32 /__attribute__((соглашение))/

x64

 

(default)

__cdecl

__stdcall

__fastcall

 

(default)

cdecl

stdcall

 

fastcall

 

сохраняемые

 

EBX, EBP, ESI, EDI

 

RBX, RBP,

 

 

EBX, EBP, ESI, EDI

 

 

RBX, RBP,

регистры

 

 

 

 

RSI, RDI,

 

 

 

 

 

 

R12-R15

 

 

 

 

 

R12-R15,

 

 

 

 

 

 

 

 

 

 

 

 

XMM6-XMM15

 

 

 

 

 

 

 

передача

[this в ECX]

стек

стек

ECX

RCX / XMM0

[this в стек]

стек

стек

 

ECX

RDI, RSI,

аргументов

стек

 

 

EDX

RDX / XMM1

стек

 

 

 

EDX

RCX, RDX,

(в стек:

 

 

 

стек

R8 / XMM2

 

 

 

 

 

стек

R8, R9,

справа-налево)

 

 

 

 

R9 / XMM3

 

 

 

 

 

 

XMM0-XMM7

 

 

 

 

 

стек

 

 

 

 

 

 

стек

освобождение

вызывающий вызывающий

функция

функция

вызывающий

вызывающий

вызывающий

функция

 

функция

вызывающий

стека от

 

 

 

 

 

 

 

 

 

 

 

 

аргументов

 

EAX, EDX

 

RAX

 

 

EAX, EDX

 

 

RAX, RDX

возврат

 

 

 

 

 

 

значений

 

ST(0)

 

XMM0

 

 

ST(0)

 

 

 

ST(0), ST(1)

возврат

 

 

стек по указателю, переданном вызывающим кодом в неявном аргументе

 

 

XMM0, XMM1

 

 

 

 

 

структур

 

 

(в C++ сопровождается неявным вызовом конструкторов копирования/деструкторов)

 

 

 

Формирование фрейма функции:

сохранение регистров

 

 

Способы передачи аргументов в стеке:

 

push

%ebp

 

...

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

mov

%esp,

 

резервирование

 

sub

$XX, %esp

sub

 

$XX+max(N)*4, %esp

push

%esi

 

 

пространства

 

...

 

 

...

 

 

 

sub

$XX, %esp

 

 

под локальные

 

push

argN

 

mov

 

argN, 4*(N-1)(%esp)

...

-4(%ebp), %esp

 

переменные

 

...

arg1

 

...

 

arg1, (%esp)

leal

 

 

 

push

 

mov

 

pop

%esi

освобождение

 

 

call

_function

call

 

_function

 

pop

%ebp

 

фрейма

 

 

add

$4*N, %esp

...

 

 

 

ret

[NN]

от переменных

 

 

...

 

 

leal

 

-4(%ebp), %esp

Пример программы, демонстрирующей различные соглашения о вызовах.

1. Определяемые типы данных и конструкторы

Структура 'xy', содержащая два поля целого типа; в памяти будет занимать 8 байт (2*4).

Класс 'xx', содержащий одно поле (m_v), три экземплярных метода (конструктор, getxy и getsum), неэкземплярный метод (sumxy) и виртуальный деструктор; в

памяти будет занимать 8 байт (4 байта — поле + 4 байта — неявное поле-указатель на т.н. «таблицу виртуальных методов»).

 

 

 

 

#ifdef __GNUC__

 

 

 

 

 

 

CONST

SEGMENT

 

 

адрес RTTI данных

.weak

_ZTV2xx

 

 

# define __cdecl

__attribute__((cdecl))

 

??_7xx@@6B@

DD ??_R4xx@@6B@

.section

.rodata

 

 

 

 

 

 

 

# define __stdcall __attribute__((stdcall))

 

 

 

DD ??_Exx@@UAEPAXI@Z

 

 

 

ZTV2xx:

адрес RTTI данных

 

# define __fastcall __attribute__((fastcall))

 

CONST

ENDS

 

 

 

 

 

 

 

 

 

 

адрес первого

.long

0

 

 

#endif

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

SEGMENT

 

 

 

.long

_ZTI2xx

 

 

 

 

 

 

традиционное соглашение

 

 

 

 

 

виртуального

 

 

struct xy {

 

 

 

 

 

??0xx@@QAE@XZ

 

 

.long

_ZN2xxD1Ev

 

 

 

 

о вызовах C++ (т.н. thiscall)

 

 

 

 

метода

 

 

 

int

x, y;

 

??0xx@@QAE@XZ PROC

; xx::xx()

 

 

 

.long

_ZN2xxD0Ev

 

в ECX передается this

 

(здесь: деструктора)

 

};

 

 

 

 

 

= ecx

 

 

.text

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mov

eax, ecx

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.globl _ZN2xxC1Ev

 

 

 

this

 

 

 

 

 

 

 

 

mov

DWORD PTR [eax], OFFSET ??_7xx@@6B@

 

 

 

class xx {

 

 

 

 

 

 

 

 

 

_ZN2xxC1Ev:

 

 

 

void **vtable;

 

 

 

 

 

 

 

 

 

protected:

 

 

 

void *RTTI;

 

 

 

mov

DWORD PTR [eax+4], -

 

 

 

 

movl

4(%esp), %eax

 

 

 

int m_v;

 

 

 

 

ret

0

 

 

 

 

 

 

int m_v;

 

 

 

void (*)(...)

 

 

 

 

инициализация указателя

movl

$_ZTV2xx+8, (%eax)

 

 

 

...

 

 

 

 

??0xx@@QAE@XZ ENDP

 

 

public:

 

 

 

 

...

 

 

 

на таблицу виртуальных

movl

$-1, 4(%eax)

 

xx( void ) { m_v = -1; }

 

 

 

 

PUBLIC

??1xx@@UAE@XZ

 

 

методов

 

 

ret

 

 

 

 

 

 

 

 

 

 

 

 

 

 

virtual ~xx( void ) {}

 

 

 

 

??1xx@@UAE@XZ PROC

; xx::~xx

 

 

 

.globl _ZN2xxD1Ev

 

 

static long long __cdecl sumxy

 

 

mov

DWORD PTR [ecx], OFFSET ??_7xx@@6B@

 

 

 

 

 

 

_ZN2xxD1Ev:

 

 

 

( struct xy );

 

 

 

 

 

 

ret

0

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

movl

4(%esp), %eax

 

struct xy __stdcall getxy

 

 

 

 

??1xx@@UAE@XZ ENDP

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

movl

$_ZTV2xx+8, (%eax)

 

( int );

 

 

 

 

 

 

 

 

 

 

В GCC this передается

 

 

 

 

 

 

 

 

 

 

 

ret

 

 

 

double __fastcall getsum

 

 

 

 

 

 

 

 

как обычный аргумент

 

 

 

 

( int, double, int, double );

 

 

 

 

 

 

в стеке

 

 

 

 

 

 

};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2. Неэкземплярный метод, передача структуры в качестве аргумента, соглашение о вызовах cdecl

 

 

 

 

 

 

 

 

long long __cdecl xx::sumxy( struct xy S )

 

PUBLIC

?sumxy@xx@@SA_JUxy@@@Z

 

 

 

.globl _ZN2xx5sumxyE2xy

 

{

 

 

 

 

 

 

 

 

_S$ = 8

 

 

 

; size = 8

 

_ZN2xx5sumxyE2xy:

 

 

return (long long)S.x + S.y;

 

?sumxy@xx@@SA_JUxy@@@Z PROC

 

 

 

 

pushl

%ebx

 

 

}

 

 

 

 

 

 

 

 

 

mov

eax, DWORD PTR _S$[esp]

 

 

 

movl

12(%esp), %eax

 

При передаче структуры в качестве аргумента

 

 

cdq

 

 

 

 

 

 

movl

8(%esp), %ecx

 

вызывающий код создает в стеке на месте нужного

 

 

mov

ecx, eax

 

 

 

 

movl

 

 

 

аргумента временную копию структуры. В C++ это

 

 

mov

eax, DWORD PTR _S$[esp-

 

 

 

movl

 

 

 

может приводить к неявному вызову конструкторов

 

 

push

esi

 

esp

→ retaddr

sarl

 

 

 

копирования и деструкторов после выхода из

 

 

mov

esi, edx

sarl

 

 

 

 

 

+4

→ xy.x

 

 

 

 

 

вызванной функции (отдельный вопрос связан с тем —

 

 

cdq

 

 

 

 

addl

 

 

 

 

 

 

 

+8

→ xy.y

 

 

 

 

 

кто и когда должен вызывать деструкторы и какие

 

 

add

ecx, eax

 

 

adcl

 

 

 

 

 

 

...

 

 

 

 

 

именно).

 

 

 

 

 

 

 

 

 

adc

esi, edx

 

 

 

popl

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

mov

edx, esi

 

 

 

 

ret

esp

→ ebx

 

 

 

 

 

 

 

 

 

 

 

mov

eax, ecx

 

 

 

 

 

+4

→ retaddr

 

 

 

 

 

 

 

 

 

 

 

pop

esi

 

 

 

 

 

 

+8

→ xy.x

 

 

 

 

 

 

 

 

 

 

 

ret

0

 

 

 

 

 

 

+12

→ xy.y

 

 

 

 

 

 

 

 

 

 

?sumxy@xx@@SA_JUxy@@@Z ENDP

 

 

 

 

 

 

...

3. Экземплярный метод, возвращение структуры в виде результата, соглашение о вызовах stdcall

 

 

 

 

 

 

 

 

struct xy __stdcall xx::getxy( int v )

 

PUBLIC

?getxy@xx@@QAG?AUxy@@H@Z

 

 

 

.globl _ZN2xx5getxyEi

 

{

 

 

_this$ = 8

 

 

; size = 4

 

_ZN2xx5getxyEi:

 

struct xy

R;

 

___$ReturnUdt$ = 12

 

; size = 4

 

 

 

movl

8(%esp), %edx

 

 

 

 

_v$ = 16

 

 

; size = 4

 

 

 

movl

4(%esp), %eax

 

R.x = m_v;

 

 

?getxy@xx@@QAG?AUxy@@H@Z PROC

 

 

 

 

 

 

 

%edx

 

R.y = v;

 

 

 

mov

eax, DWORD PTR _this$[esp-4]

 

 

 

 

(%eax)

 

return R;

 

 

 

mov

ecx, DWORD PTR [eax+4]

 

 

 

 

 

%edx

 

}

 

 

 

mov

eax, DWORD PTR ___$ReturnUdt$[esp-

 

 

 

4(%eax)

 

Память для возвращаемой структуры выделяет

 

 

mov

edx, DWORD PTR

 

 

 

 

 

 

 

 

 

вызывающий код, предавая адрес выделенной

 

mov

DWORD PTR [eax],

 

 

esp

→ retaddr

 

области в виде неявного аргумента функции. Таким

 

mov

DWORD PTR [eax+4],

 

 

 

образом данная функция имеет три аргумента — один

 

ret

12

 

 

 

+4

→ xy *p

 

 

явный (int v) и два неявных: this и указатель на

?getxy@xx@@QAG?AUxy@@H@Z ENDP

esp

→ retaddr

+8

→ xx *this

 

возвращаемую структуру.

 

 

 

 

 

+12

→ int v

 

 

 

 

 

 

 

+4

→ xx *this

 

 

 

...

 

 

Инструкция выхода из процедуры (ret 12)

 

 

 

 

 

 

 

 

 

 

 

+8

→ xy *p

 

 

 

 

 

 

освобождает стек от переданных аргументов (3*4).

 

 

 

 

 

 

 

 

 

 

 

 

+12

→ int v

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

4. Экземплярный метод, соглашение о вызовах fastcall

PUBLIC

?getsum@xx@@QAINHNHN@Z

 

...

 

.globl _ZN2xx6getsumEidid

 

double __fastcall xx::getsum

 

 

 

 

 

 

( int a, double b, int c, double d )

 

EXTRN

__fltused:DWORD

 

 

 

 

_ZN2xx6getsumEidid:

 

{

 

 

EXTRN

__ftol2_sse:PROC

 

 

 

 

 

 

subl

$4, %esp

 

double r = a+b+c+d;

 

_a$ = -4

 

 

; size = 4

 

 

 

pushl

%edx

 

m_v = (int)r;

 

 

_b$ = 8

 

 

 

; size = 8

 

 

 

fildl

(%esp)

 

return r;

 

 

_c$ = 16

 

 

; size

 

 

 

faddl

12(%esp)

 

}

 

 

_d$ = 20

 

 

;

 

 

 

 

fnstcw

6(%esp)

 

В архитектуре IA-32 соглашение fastcall предполагает

 

?getsum@xx@@QAINHNHN@Z PROC

 

 

esp

→ копия a

 

movzwl

6(%esp), %eax

 

использование двух регистров ECX и EDX для передачи

; _this$ = ecx

 

 

 

 

fildl

20(%esp)

 

 

 

 

+4

→ short cw1

 

первых двух аргументов целого (или приводимого к

; _a$ = edx

 

 

 

faddp

%st, %st(1)

 

целому) типа. Для экземплярного метода первый

 

push

ecx

 

 

+6

→ short cw0

movb

$12, %ah

 

аргумент — неявный this (будет

 

mov

DWORD PTR _a$[esp+4], edx

+8

→ retaddr

 

faddl

24(%esp)

 

второй — int a (будет размещен в

 

fild

DWORD PTR _a$[esp+4]

 

+12

→ double b

movw

%ax, 4(%esp)

 

 

push

esi

 

 

+20

→ int c

 

fldcw

4(%esp)

 

аргументы должны быть размещены

 

 

 

+24

→ double d

 

Интересный момент — инструкция

 

mov

esi, ecx

 

 

 

...

 

fistl

4(%ecx)

 

 

fadd

QWORD PTR _b$[esp+4]

 

 

 

fldcw

6(%esp)

 

в double требует задания операнда

 

 

edx

: int a

 

 

 

fiadd

DWORD PTR _c$[esp+4]

 

 

addl

$8, %esp

 

ссылки на память, а (согласно

 

fadd

QWORD PTR _d$[esp+4]

 

ecx

: xx *this

ret

$20

 

аргумент размещен в регистре EDX.

 

fld

ST(0)

 

 

 

 

 

 

 

 

 

по сути размещают этот аргумент в

 

 

 

 

 

 

 

 

 

 

 

call

__ftol2_sse

 

 

 

 

 

 

 

 

 

обращаются к его «локальной копии»

 

mov

DWORD PTR [esi+4], eax

Регистр

ECX не сохраняется при вызове вложенной

 

выделен жирным)

ECX не является

 

pop

esi

 

процедуры (_ftol2_sse), а указатель this ECX) нам

 

 

сохраняемым,

 

pop

ecx

 

 

будет нужен после её вызова для сохранения

 

 

это резервирование

 

ret

20

 

 

 

результата в this->m_v.

 

 

места для EDX

?getsum@xx@@QAINHNHN@Z ENDP

 

Поэтому this из ECX копируют в ESI (который является

сохраняемым) и, соответственно, сохраняют ESI в стеке

до его использования и восстанавливают после. (выделено курсивом)

5. Функция, не являющаяся методом, соглашение cdecl double cpptest( int y )10

{

xx t;

return (double)t.getsum( (int)t.sumxy( t.getxy(y) ), 0.0, -1,

(double)y

);

}

#ifdef __cplusplus extern "C" { #endif

double ctest( int y )

{

return cpptest( y );

}

#ifdef __cplusplus

}

#endif

По логике приведенной процедуры должны быть выполнены следующие действия:

-выделено пространство для xx t и выполнен конструктор xx::xx()

-выделено пространство для структуры xy, возвращаемой методом getxy; должен быть выполнен (неявный) конструктор xy::xy().

-выполнен экземплярный метод getxy (__stdcall).

-выполнен неэкземплярный метод sumxy (__cdecl).

-выполнен экземплярный метод getsum (__fastcall) с приведением результата (long) к типу double.

-выполнен (неявный) деструктор xy::~xy();

освобождено пространство, занимаемое временной структурой xy.

- выполнен деструктор xx::~xx(); освобождено пространство, занимаемое xx t.

В зависимости от режима оптимизации компиляторы могу пропускать некоторые шаги (например, вызов неявных конструкторов и деструкторов структуры), подставлять текст коротких функций, вместо их вызова (например, деструктор xx::~xx() может быть

подставлен и элиминирован) и т.п.

 

 

PUBLIC ?cpptest@@YANH@Z

 

_t$ = -16

 

; size = 8

$T2647 = -8

 

; size = 8

_y$ = 8

 

; size = 4

?cpptest@@YANH@Z PROC

 

sub

esp, 16

 

lea

ecx, DWORD PTR _t$[esp+16]

call

??0xx@@QAE@XZ

; xx::xx

mov

eax, DWORD PTR _y$[esp+12]

push

eax

 

lea

ecx, DWORD PTR $T2647[esp+20]

push

ecx

 

lea

edx, DWORD PTR _t$[esp+24]

push

edx

 

call

?getxy@xx@@QAG?AUxy@@H@Z ; xx::getxy

fild

DWORD PTR _y$[esp+12]

 

mov

ecx, DWORD PTR [eax+4]

mov

edx, DWORD PTR [eax]

 

sub

esp, 8

 

fstp

QWORD PTR [esp]

 

push

-1

 

fldz

 

 

sub

esp, 8

 

fstp

QWORD PTR [esp]

 

push

ecx

 

push

edx

 

call

?sumxy@xx@@SA_JUxy@@@Z ; xx::sumxy

add

esp, 8

 

mov

edx, eax

 

lea

ecx, DWORD PTR _t$[esp+36]

call

?getsum@xx@@QAINHNHN@Z ; xx::getsum

add

esp, 16

 

ret

0

 

?cpptest@@YANH@Z ENDP

 

PUBLIC _ctest

 

 

_y$ = 8

 

; size = 4

_ctest PROC

 

 

jmp

?cpptest@@YANH@Z

; cpptest

_ctest ENDP

 

 

.globl _Z7cpptesti _Z7cpptesti:

pushl %esi pushl %ebx subl $68, %esp

movl

80(%esp), %esi

leal

56(%esp), %ebx

movl

%ebx, (%esp)

call

_ZN2xxC1Ev

leal

40(%esp), %eax

movl

%ebx, 4(%esp)

movl

%esi, 8(%esp)

movl

%eax, (%esp)

call

_ZN2xx5getxyEi

subl

$12, %esp

movl

40(%esp), %eax

movl

44(%esp), %edx

movl

%eax, (%esp)

movl

%edx, 4(%esp)

call

_ZN2xx5sumxyE2xy

movl

%ebx, %ecx

pushl

%esi

fildl

(%esp)

addl

$4, %esp

movl

%eax, %edx

fstpl

12(%esp)

fldz

 

fstpl

(%esp)

movl

$-1, 8(%esp)

call

_ZN2xx6getsumEidid

subl

$20, %esp

fstpl

32(%esp)

movl

%ebx, (%esp)

call

_ZN2xxD1Ev

fldl

32(%esp)

addl

$68, %esp

popl

%ebx

popl

%esi

ret

 

.globl ctest

 

ctest:

 

jmp

_Z7cpptesti

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]