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

Загрузка библиотек на этапе исполнения.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

PIC-код

 

 

 

 

 

Для архитектуры x86 характерно

Определение

 

Модификация кода и данных

 

 

 

 

 

 

 

 

использование абсолютных адресов

действительных адресов

 

вследствие изменения адресов

 

Описание перемещаемых

 

Предзадание адресов

при обращении к данным, в случае

только после определения

 

статических переменных и процедур

 

записей в исполняемом

 

в момент сборки или при

косвенной адресации, а также при

адреса загрузки библиотеки

 

 

 

 

файле

 

создании кэша библиотек

 

 

 

 

 

 

 

 

 

 

 

 

 

межсегментной передаче управления.

 

 

Определение адресов импортируемых

 

Прямое обращение к импортируемым символам

 

В IA-32 относительный адрес используют только инструкции

 

символов только после загрузки

 

 

 

 

 

 

 

 

 

 

внутрисегментной передачи управления (ближние и короткие

 

нужной разделяемой библиотеки

 

 

 

 

 

 

 

 

 

Косвенное обращение через секции импорта

 

 

переходы, ближние вызовы) и только при прямой адресации

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(косвенные формы переходов и вызовов используют абсолютные адреса). В 64х разрядном режиме в частных случаях (ModR/M: 00...101) может использоваться адресация константным 32х разрядным смещением к RIP.

Код с перемещаемыми записями

#include <stdio.h> static int s_x;

void show_x( void )

{

printf("%d",add_x(0));

}

int add_x( int v )

{

return s_x += v;

}

В случае Visual Studio для указания экспортируемых символов использовался .def файл:

LIBRARY test EXPORTS

add_x show_x

Вместо использования .def файла можно было описать функции show_x и add_x с атрибутом

dllexport, например: void

__declspec(dllexport) show_x( void )

{

...

cl /O2 /Ox /LD /MD test.c /link /DEF:test.def

 

 

 

 

.686P

 

 

.model

flat

PUBLIC

_add_x

 

PUBLIC

??_C@_02EF@?$CFd?$AA@

PUBLIC

_show_x

 

EXTRN

_printf:PROC

_BSS

SEGMENT

 

_s_x

DD

01H DUP (?)

_BSS

ENDS

 

CONST

SEGMENT

 

??_C@_02AMEF@?$CFd?$AA@ DB '%d',0

CONST

ENDS

 

_TEXT

SEGMENT

 

_v$ = 8

 

; size = 4

_add_x PROC

 

 

mov

eax, DWORD PTR _s_x

 

add

eax, DWORD PTR _v$[esp-4]

 

mov

DWORD PTR _s_x, eax

 

ret

0

_add_x ENDP

 

_show_xPROC

 

 

mov

eax, DWORD PTR _s_x

 

push

eax

 

push

OFFSET ??_C@_02DEF@?$CFd?$AA@

 

call

_printf

 

add

esp, 8

 

ret

0

_show_xENDP

 

_TEXT

ENDS

 

END

 

 

gcc -O3 -fomit-frame-pointer -shared -o libtest.so test.c

 

 

.section

.rodata.str1.1,"aMS"

.LC0: .string"%d"

 

.text

 

 

.globl add_x

 

 

.type

add_x, @function

add_x:

 

 

movl

4(%esp), %eax

addl

s_x, %eax

movl

%eax, s_x

ret

 

 

.globl show_x

 

 

.type

show_x, @function

show_x:

 

 

subl

$12, %esp

movl

s_x, %eax

movl

$.LC0, (%esp)

movl

%eax, 4(%esp)

call

printf

 

addl

$12, %esp

ret

 

 

.local

s_x

 

.comm

s_x,4,4

 

для получения ассемблерного кода использовались команды: cl /Fafile.asm /O2 /Ox /LD /MD test.c /link /DEF:test.def

и

gcc -O3 -fomit-frame-pointer -shared -S -o libtest.s test.c

Экспорт, импорт, перемещаемые записи в Windows

Отдельные поля из заголовка библиотеки:

 

 

 

 

 

A00 size of code

 

 

 

 

C00 size of initialized data

 

 

 

13B5

entry point (100013B5)

 

 

 

1000

base

of code

 

 

 

 

2000

base

of data

 

 

 

 

10000000 image base (10000000 to 10004FFF)

 

 

 

24C0

[ 50] RVA [size] of Export Directory

Import

Address Table

217C

[ 3C] RVA [size] of Import Directory

4000

[ 130] RVA [size] of Base Relocation Directory

 

(IAT)

20B0

[ 40] RVA [size] of Load Configuration Directory

 

2000...2087

2000

[ 88] RVA [size] of Import Address Table Directory

 

Дизассемблериванный фрагмент секции .text:

 

 

 

10001000: mov

eax, [10003010h]

 

 

 

10001005: add

eax, [esp+4]

 

Import Directory

10001008: mov

[10003010h], eax

 

 

217C...21B7

1000100E: ret

 

 

 

 

10001010: mov

eax, [10003010h]

 

 

 

10001015: push eax

 

 

 

 

10001016: push 100020A0

 

 

 

 

1000101B: call 10001024h

 

Import Lookup Table

10001020: add esp, 8

 

10001023: ret

 

 

 

 

(ILT)

10001024: jmp [10002080]

 

 

 

21B8...223F

Отдельные сведения об экспорте и импорте:

 

 

 

exports for qq.dll:

 

 

 

 

 

00000000 characteristics

 

 

 

 

4B14F093 time date stamp Tue Dec 01 13:31:47 2009

 

Strings

 

0.00 version

 

 

 

 

 

1 ordinal base

 

 

 

2240...24BF

 

 

2 number of functions

 

 

 

 

 

2 number of names

 

 

 

 

ordinal hint RVA

name

 

 

 

10 00001000 add_x

2

1 00001010 show_x

Export Directory

imports:

 

 

 

 

24C0...24FF

MSVCR90.dll

 

 

 

 

1000203C Import Address Table

 

 

 

100021F4 Import Name Table

 

 

 

276

_lock

 

 

 

...

 

 

 

 

52E

printf

 

 

KERNEL32.dll

 

 

 

 

10002000 Import Address Table

 

 

 

100021B8 Import Name Table

10000000

 

 

415

SetUnhandledExceptionFilter

+00001000

 

 

…

 

+(0FFF & 300A)

(!) Import Name Table называют также Import

 

 

1000100A

Lookup Table. В исполняемом файле IAT[i] равно ILT[i], а

во время загрузки образа в адресное пространство процесса загрузчик записывает в IAT[i] актуальный адрес импортируемой функции или данных.

.text

 

 

 

 

 

 

 

 

 

 

 

 

ImageBaseAddress

Для символов, описанных с

 

 

A1

10

30

00

10

03

44

24

 

10001000:

 

 

 

 

10000000

атрибутом

 

10001008:

 

04

A3

10

30

00

10

C3

CC

 

 

10001010:

 

 

A1

10

30

00

10

50

68

A0

 

адреса

 

__declspec(dllimport)

10001018:

 

20

00

10

E8

04

00

00

00

 

 

транслятор сразу генерирует

 

 

вычислены в

 

10001020:

 

83

C4

08

C3

FF 25

80

20

 

предположении

 

инструкции с косвенной адресацией

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

10001028:

00

10

8B

FF

56

68

80

00

 

загрузки библиотеки

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

через IAT; т.е. если транслятор

 

 

 

 

 

 

 

 

 

 

 

 

 

по адресу

 

.rdata

 

 

 

 

 

 

 

 

 

 

 

 

 

ImageBaseAddress

 

располагает прототипом

10002000:

 

74

24

00

00

58

24

00

00

 

 

 

 

 

 

 

DLL

void

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

10000000

 

 

 

 

 

10002078:

 

56

22

00

00

2E

23

00

00

 

__declspec(dllimport)

 

 

 

10002080:

 

40

22

00

00

00

00

00

00

 

+000021F4

импортируемой

func(void);

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

100021F4

 

100020A0:

%

d

00

00

00

00

00

00

 

(подраздел ILT)

 

то будет сгенерована инструкция

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

косвенного вызова

 

10002170: FE

FF

FF FF

0B

16

00

10

 

10000000

 

 

 

call dword ptr [IAT_func]

10002178:

 

 

 

1F

16

00

10

 

 

 

 

 

 

 

 

 

F4

21

00

00

 

 

10002180:

 

 

 

 

00

00

00

00

00

00

00

00

 

+0000224A

 

В противном случае транслятор

10002188:

 

 

 

 

4A

22

00

00

3C

20

00

00

 

1000224A

 

использует прямую адресацию, т.е.

10002190:

 

 

 

B8

21

00

00

00

00

00

00

 

 

10002198:

 

 

 

00

00

00

00

A6

24

00

00

 

(имя библиотеки)

если транслятор располагает

100021C0:

 

 

44

24

00

00

30

24

00

00

 

 

каждой

func(void);

 

100021A0:

 

 

00

20

00

00

00

00

00

00

 

10000000

 

прототипом

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

100021B8:

 

74

24

00

00

58

24

00

00

 

+0000203C

 

void

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

1000203C

Для

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

то будет использована инструкция

100021F0:

 

00

00

00

00

26

23

00

00

 

(подраздел IAT)

100021F8:

 

18

23

00

00

38

23

00

00

 

 

 

call func

 

10002200:

 

52

23

00

00

0E

23

00

00

 

 

 

Если позже при сборке выяснится,

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

10002238:

 

 

 

40

22

00

00

00

00

00

00

 

+10000000

 

что символ импортирован из DLL, то

10002240:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2E

05

p

r

i

n

t

f

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

00002240

 

линкер сгенерирует промежуточные

10002248: 00

00

M

S

V

C

R

9

 

10002240

 

заглушки (stub), содержащие

10002250:

 

0

.

d

l

l

00

6A 01

 

...

 

 

 

 

 

 

 

 

 

 

K

E

 

 

инструкции косвенного перехода; т.е.

100024A0: 65

73

65

6E

74

00

 

 

100024A8:

 

 

 

R

N

E

L

3

2

.

d

 

 

call func

 

100024B0:

 

 

 

l

l

00

00

00

00

00

00

 

10000000

 

будет модифицирован как:

100024B8:

 

00

00

00

00

00

00

00

00

 

 

call __autostub_func

100024C0:

 

00

00

00

00

93

F0

14

4B

 

+000024FC

 

...

 

 

100024C8:

 

00

00

00

00

FC 24

00

00

 

100024FC

 

 

 

100024D0:

 

01

00

00

00

02

00

00

00

 

 

__autostub_func:

 

 

(имя библиотеки)

100024D8:

 

02

00

00

00

E8

24

00

00

 

jmp dword ptr [IAT_func]

 

 

 

 

100024E0:

 

 

F0

24

00

00

F8

24

00

00

 

список адресов

 

См. вызов printf по адресу 1000101B;

100024E8:

 

 

00

10

00

00

10

10

00

00

 

 

100024F0:

 

 

03

25

00

00

09

25

00

00

 

список имен

 

Обращение к экспортируемым

100024F8:

 

 

00

00

01

00

q

q

.

d

 

 

10002500:

 

 

 

 

l

l

00

a

d

d

_

x

 

 

 

данным возможно только если они

10002508:

 

 

00

s

h

o

w

_

x 00

 

 

 

описаны с «dllimport».

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.data

 

 

 

 

FF

FF FF

FF FF

FF

FF

 

 

Отдельные сведения о

10003000: FF

 

 

перемещаемых записях:

10003008: 4E

E6

40

BB

B1

19

BF

44

 

 

 

 

 

 

BASE RELOCATIONS #4

 

10003010:

 

 

00

00

00

00

00

00

00

00

 

 

 

 

 

 

 

 

 

1000 RVA,

110 SizeOfBlock

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.reloc

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1

HIGHLOW

10003010

10004000:

 

 

00

10

00

00

10

01

00

00

 

 

 

A

HIGHLOW

10003010

 

 

 

 

 

17

HIGHLOW

100020A0

10004008:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

01

30

0A

30

11

30

17

30

 

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

10004108: B7

38

BE 38

C6

38

00

00

 

 

 

0

ABS

 

10004110: 00

20

00

00

20

00

00

00

 

 

 

2000 RVA,

20 SizeOfBlock

10004118: 94

30

A8

30

AC 30

EC

30

 

 

 

94

HIGHLOW

1000102A

Экспорт, импорт, перемещаемые записи в Posix

каждая запись

.dynsym

 

 

 

 

 

 

 

+0000025c (.dynstr)

Вызов функции, импортируемой из

Дизассембер секции .plt

 

 

 

определения символа

01bc...

2b

00

00

00

00

00

00

00

«разделяемого объекта» (shared

__loader__@plt:

 

 

 

 

занимает 16 байт,

01c4

00

00

00

00

20

00

00

00

0000002b

object), осуществляется обращением

 

pushl

0x4(%ebx)

 

 

 

приведена запись с ...

 

 

 

 

 

 

 

 

00000287 + LoadAddr

к созданной сборщиком заглушке в

 

 

 

 

 

индексом 2

.dynstr

 

 

 

 

 

 

 

 

PLT (Procedure Linkage Table):

 

jmp

*0x8(%ebx)

 

# загрузчик LD.SO

_

_

g

m

o

n

_

 

 

 

Формат записей

025c

00

 

 

 

 

 

.long

0

 

 

 

 

 

 

call

add_x@plt

 

 

 

 

 

 

 

0264

s

t

a

r

t

_

_ 00

тип перемещаемой

 

 

 

 

 

 

 

 

.dynsym и .symtab; ...

 

 

 

 

 

 

 

 

где

 

 

__gmon_start__@plt:

 

 

 

 

 

(имя-значение-

0284

z

e 00

_

J

v

_

R

записи

 

 

 

jmp

*0xc(%ebx)

 

 

 

 

размер-флаги-

028c

e

g

i

s

t

e

r

C

02: R_386_PC32

add_x@plt:

Заменяется на

 

pushl

$0x0

 

 

 

 

 

секция)

0294

l

a

s

s

e

s 00

a

(отн. адрес символа #)

jmp

 

реальный адрес

 

 

 

 

 

 

 

...

 

 

 

 

 

 

 

 

06: R_386_GLOB_DAT

*GOT.PLT[add_x]

 

jmp

__loader__@plt

 

 

 

 

.rel.dyn

 

 

 

 

 

 

 

push

off_in_rel.plt

 

 

 

 

адрес

 

 

 

 

 

 

 

(адрес символа #)

__cxa_finalize@plt:

 

 

 

 

перемещаемой

...

 

 

 

 

 

 

 

 

07: R_386_JUMP_SLOT

jmp

__loader__@plt

 

 

 

 

0350

08

20

00

00

08

00

00

00

 

 

 

 

(адрес записи в .plt для #)

..

 

 

 

jmp

*0x10(%ebx)

 

 

 

 

записи

0358

d4

04

00

00

02

03

00

00

08: R_386_RELATIVE

 

 

 

pushl

$0x8

 

 

 

 

 

 

0360

e8

1f

00

00

06

01

00

00

(прибавить адрес загрузки) __loader__@plt:

 

 

 

 

 

 

 

 

0368

ec 1f 00

00

06

02

00

00

 

pushl GOT.PLT+4 (LoadAddr)

 

jmp

__loader__@plt

 

 

 

 

 

 

 

 

 

 

0370

f0

1f

00

00

06

04

00

00

индекс символа

 

 

 

 

 

jmp

*GOT.PLT+8

 

 

 

 

 

 

 

 

 

 

.rel.plt

 

 

 

 

 

 

 

 

Дизассемблер начала секции .init

 

 

 

 

 

 

 

 

 

 

 

в .dynsym

сборщик создает по одной записи в

 

 

 

 

0378

00

20

00

00

07

01

00

00

 

push

%ebp

 

 

 

 

 

 

0380

04

20

00

00

07

04

00

00

 

PLT на каждую импортируемую

 

mov

%esp,%ebp

 

 

 

 

 

.init

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

55

89

e5

53

83

ec 04 e8

 

функцию и инициализирует

 

push

%ebx

 

 

 

 

 

 

0388

 

указатель в GOT (Global Offset Table)

 

sub

$0x4,%esp

 

 

 

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.plt

 

 

 

 

 

 

 

 

 

адресом этой заглушки + 6 — с этого

 

call

1f

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

__gmon_start__@plt

03b8

ff b3 04

00

00

00

ff a3

Procedure Linkage Table

места размещен вызов загрузчика

1:

pop

%ebx

 

 

 

03c0

08

00

00

00

00

00

00

00

 

 

 

 

 

 

16 байт на каждую

данного символа.

 

 

add

$0x1c60,%ebx

# ebx = 1FF4

 

03c8

ff a3 0c

00

00

00

68

00

 

 

 

03d0

00

00

00

e9

e0

ff ff ff

импортируемую функцию

GOT.PLT[add_x]:

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

__gmon_start__@plt + 6

03d8

ff a3 10

00

00

00

68

08

 

Частичный дизассемблер секции .text

03e0

00

00

00

e9

d0

ff ff ff

 

.long

add_x@plt+6

 

 

 

 

.text

 

 

 

 

 

 

 

 

 

который заменяется загрузчиком на

add_x:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Величина -4 (0xFFFFFFFC)

mov

0x4(%esp),%eax

 

 

 

 

03f0

55

89

e5

56

53

e8

ad 00

.long

real_address

 

 

 

 

 

...

d2

83

c4

04

5b

5d

c3

8b

указывает смещение адреса

 

add

0x2014,%eax

 

 

 

 

 

04a0

перемещаемой записи

Во время загрузки исполняемого

 

 

 

 

 

 

04a8

1c

24

c3

90

90

90

90

90

относительно EIP,

# 4b6:

R_386_RELATIVE

 

*ABS*

 

 

 

04b0

8b

44

24

04

03

05

14

20

используемого инструкцией

файла загрузчик сразу

 

 

mov

%eax,0x2014

 

 

 

 

 

04b8

00

00

a3

14

20

00

00

c3

 

модифицирует первые записи в

 

 

 

 

 

 

04c0

83

ec 0c

a1

14

20

00

00

 

# 4bb:

R_386_RELATIVE

 

*ABS*

 

 

 

Адрес

.got.plt так, что бы стало

 

 

 

 

04c8

c7

04

24

34

05

00

00

89

 

ret

 

 

 

 

 

 

 

04d0

44

24

04

e8

fc ff ff ff

загрузки

возможно обращение к

 

show_x:

 

 

 

 

 

 

 

 

04d8

83

c4

0c

c3

90

90

90

90

этого .

__loader__@plt из загруженного

sub

$0xc,%esp

 

 

 

 

 

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

.fini

 

 

 

 

 

 

 

 

 

модуля.

 

 

 

mov

0x2014,%eax

 

 

 

 

 

0518

55

89

e5

53

83

ec 04 e8

Global Offset Table

Импорт данных специфичен: в

# 4c4:

R_386_RELATIVE

 

*ABS*

 

 

 

...

 

 

 

 

 

 

 

 

4 байта на каждый символ

разделяемом объекте обращения к

 

 

Смещение

.got

 

 

 

 

 

 

 

 

 

movl

$0x534,(%esp)

 

 

 

 

 

 

 

 

 

 

(типично, если .rel

экспортируемым данным

 

 

 

 

1fe8

00

00

00

00

00

00

00

00

 

# 4cb:

R_386_RELATIVE

 

*ABS*

 

секции .dynamic

1ff0

00

00

00

00

 

 

 

 

ссылается на записи в .got) описываются со специфичным типом

 

mov

%eax,0x4(%esp)

 

 

 

 

.got.plt

1f

00

00

00

00

00

00

LoadAddr

перемещаемой записи R_386_COPY,

 

call

.+1

 

 

 

 

 

EBX → 1ff4

10

+000003CE

а в приложении, ссылающемся на на

# 4d4:

printf

 

 

Адрес

1ffc

00

00

00

00

ce 03 00 00

R_386_PC32

 

 

2004

de 03 00

00

 

 

 

 

__gmon_start__@plt+6

эти данные, создается их копия;

 

add

$0xc,%esp

 

 

 

процедуры

.data

08

20

00

00

 

 

 

 

Адрес замещается загрузчиком

после чего корректируются все

 

ret

 

 

 

 

 

загрузки в

2008

 

 

 

 

 

перемещаемые записи библиотеки

 

 

 

 

 

 

.bss

 

 

 

 

 

 

 

 

__cxa_finalize@plt+6,

В приведенном примере обращение к функции

 

LD.SO

00

00

00

00

00

00

00

00

так, что бы

использовался

 

printf из стандартной libc выполнено прямым вызовом.

 

200c

замещаемый на реальный

экземпляр данных в приложении.

 

2014

00

00

00

00

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

адрес процедуры

 

 

 

POSIX. Позиционно-независимый код в архитектуре IA-32.

Использование перемещаемых записей несколько замедляет процесс загрузки разделяемых объектов и, кроме того, существенно осложняет использование общих проекций — в современных POSIX-системах часто варьируют адреса разделяемых объектов от процесса к процессу и от запуска к запуску; это существенно усложняет многие виды атак, особенно удаленных.

С этим связана рекомендация использовать позиционно-независимый код при компиляции разделяемых объектов, несмотря даже на то, что код получается большего размера и чуть медленнее выполняется (усложняется только обращение к статическим данным; работа с автоматическими переменными остается без изменений).

Пример реализации позиционно-независимого кода:

 

Исходный код test.c

 

 

gcc -S -o test-rel.s -O3 -fomit-frame-pointer -shared test.c

 

 

gcc -fPIC -S -o test-rel.s -O3 -fomit-frame-pointer -shared test.c

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <stdio.h>

.section

.rodata.str1.1,"aMS"

.section

.rodata.str1.1,"aMS"

 

 

static int s_x;

 

 

.LC0: .string"%d"

 

 

 

.LC0: .string"%d"

 

 

 

 

.text

 

 

 

 

.text

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void show_x( void )

 

 

.globl add_x

 

 

 

 

.globl add_x

 

 

 

 

 

 

.type

add_x, @function

 

 

.type

add_x, @function

 

 

{

 

 

 

 

 

 

 

 

 

 

add_x:

 

 

 

 

add_x:

 

 

 

 

printf("%d", add_x(0));

 

 

 

 

 

 

 

 

 

 

 

 

movl

4(%esp), %eax

 

 

call

__i686.get_pc_thunk.cx

 

 

}

 

 

 

 

 

 

 

 

 

 

addl

s_x, %eax

 

 

addl

$_GLOBAL_OFFSET_TABLE_, %ecx

 

 

 

 

 

 

 

 

 

 

int add_x( int v )

 

 

movl

%eax, s_x

 

 

movl

4(%esp), %eax

 

 

 

 

ret

 

 

 

 

addl

s_x@GOTOFF(%ecx), %eax

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

.globl show_x

 

 

 

 

movl

%eax, s_x@GOTOFF(%ecx)

 

 

return s_x += v;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ret

 

 

 

 

}

 

 

 

.type

show_x, @function

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

show_x:

 

 

 

 

.globl show_x

 

 

 

 

 

 

 

 

 

 

 

 

Получение адреса секции данных

 

 

 

 

 

 

 

 

 

 

 

 

subl

$12, %esp

 

 

.type

show_x, @function

 

 

осуществляется с помощью вызова

 

 

movl

s_x, %eax

 

 

show_x:

 

 

 

 

служебной процедуры, загружающей в

 

 

movl

$.LC0, (%esp)

 

 

subl

$8, %esp

 

 

какой-либо регистр значение адреса

 

 

movl

%eax, 4(%esp)

 

 

movl

$0, (%esp)

 

 

возврата.

 

 

 

call

printf

 

 

 

call

add_x@PLT

 

 

Вызов __i686.get_pc_thunk.cx

 

 

addl

$12, %esp

 

 

call

__i686.get_pc_thunk.cx

 

 

возвращает в ecx адрес возврата — т.е.

 

 

ret

 

 

 

 

addl

$_GLOBAL_OFFSET_TABLE_, %ecx

 

 

адрес следующей после вызова

 

 

.local s_x

 

 

 

movl

%eax, 4(%esp)

 

 

инструкции; далее сборщик может

 

 

 

 

 

leal

.LC0@GOTOFF(%ecx), %eax

 

 

 

 

.comm

s_x,4,4

 

 

 

 

 

вычислить расстояние между текущей

 

 

 

 

 

movl

%eax, (%esp)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

call

printf@PLT

 

 

точкой и началом секции данных (реально — начала секции .got.plt, после которой

 

 

 

 

 

 

addl

$8, %esp

 

 

размещаются секции .data и .bss). Т.е. примерно такие инструкции:

 

 

 

 

 

 

ret

 

 

 

 

call

__i686.get_pc_thunk.cx

 

 

 

 

 

 

 

 

 

 

 

 

.local

s_x

 

 

 

addl

$адрес_секции_got - ., %ecx

 

 

 

 

 

 

 

Компилятор gcc распознает обращение к специальной «переменной» _GLOBAL_OFFSET_TABLE_

 

 

.comm

s_x,4,4

 

 

 

 

 

 

 

 

 

как необходимость вычислить расстояние до секции .got.plt.

 

 

 

.section

.text.__i686.get_pc_thunk.cx,"axG"

 

 

Функции семейства ...get_pc_thunk... генерируются компилятором и размещаются в

 

 

.globl __i686.get_pc_thunk.cx

 

 

специфичных секциях по мере надобности. Так, например, функция __i686.get_pc_thunk.bx

 

 

.hidden__i686.get_pc_thunk.cx

 

 

вернет значение EIP в EBX, а не в ECX и будет размещена в отдельной секции — это позволит

 

 

.type

__i686.get_pc_thunk.cx, @function

 

 

сборщику наложить одноименные секции с соответствующими процедурами друг на друга.

 

 

__i686.get_pc_thunk.cx:

 

 

 

 

movl

(%esp), %ecx

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ret

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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