Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Assembler / P20

.pdf
Скачиваний:
60
Добавлен:
02.06.2015
Размер:
508 Кб
Скачать
☆

11

 

?debug

C E9

 

?debug

C FA00000000

_BSS

ends

 

 

_DATA

segment word public 'DATA'

s@

label byte

 

 

db

'%d '

 

 

db

0

 

 

db

10

 

 

db

10

 

 

db

0

 

 

db

'%d '

 

 

db

0

 

 

db

10

 

 

db

0

 

 

db

'%p '

 

 

db

0

 

_DATA ends

_TEXT segment byte public 'CODE' _TEXT ends

extrn _printf:near

public

_A

public

_B

public

_main

end

 

Внимательно изучите этот файл. Нужно пояснить, что в сегменте данных DATA собраны инициализированные данные, а в BSS — неинициализированные.

Теперь оттранслируем программу с помощью 32-разрядного компилятора. bcc32 –S c31v0.c

Будет получен файл c31v0.asm. Переименуем его в c31v0_32.asm.

.386p

 

model flat

 

ifndef

??version

?debug

macro

endm

 

endif

 

?debug

S "c3v0.c"

?debug

T "c3v0.c"

_TEXT

segment dword public use32 'CODE'

_TEXT

ends

 

_DATA

segment dword public use32 'DATA'

_DATA

ends

 

_BSS

segment dword public use32 'BSS'

_BSS

ends

 

DGROUP

group _BSS,_DATA

_DATA segment dword public use32 'DATA'

 

align

4

_A

label

dword

 

dd

1

 

dd

5

 

dd

2

 

dd

7

 

dd

5

 

dd

6

 

dd

3

_DATA ends

_TEXT segment dword public use32 'CODE' _main proc near

?live1@0:

;

; int main() {

;

push ebp

12

mov

ebp,esp

push

ebx

push

esi

push

edi

mov

esi,offset _A

;

;int i, j, k;

;for (i = 0; i < dimA; i++)

?live1@16: ; ESI = &_A @1:

xor ebx,ebx

;

; printf("%d ", A[i]);

;

?live1@32: ; EBX = i, ESI = &_A @2:

 

push

dword ptr [esi+4*ebx]

 

push

offset s@

 

call

_printf

 

add

esp,8

 

inc

ebx

 

cmp

ebx,7

 

jl

short @2

;

 

 

;

 

 

;

i = j = dimA - 1; k = 0;

;

 

 

?live1@48: ; ESI = &_A

 

mov

eax,6

 

mov

ebx,eax

 

xor

edi,edi

;

 

 

;

while (j > 0) {

;

?live1@64: ; EBX = i, EAX = j, ESI = &_A, EDI = k

test

eax,eax

jle

short

@6

;

 

 

;

if (A[j] ==

5) {

;

 

 

@5:

 

 

cmp

dword

ptr [esi+4*eax],5

jne

short

@7

;

 

 

;

B[k++] = &A[j];

;

 

 

mov

edx,eax

shl

edx,2

 

add

edx,esi

mov

dword

ptr [_B+4*edi],edx

inc

edi

 

jmp

short

@9

;

 

 

;while (j > 0 && A[--j] != 5) {

;A[i--] = A[j];

;

 

@8:

 

mov

ecx,dword ptr [esi+4*eax]

mov

dword ptr [esi+4*ebx],ecx

dec

ebx

@9:

 

test

eax,eax

 

13

jle

short @10

dec

eax

cmp

dword ptr [esi+4*eax],5

jne

short @8

;

 

;

}

;

if (j == 0 && A[0] == 5)

;

 

@10:

 

test

eax,eax

jne

short @12

cmp

dword ptr [esi],5

jne

short @12

;

 

;

B[k++] = &A[j];

;

 

mov

edx,eax

shl

edx,2

add

edx,esi

mov

dword ptr [_B+4*edi],edx

inc

edi

;

 

;

}

;

 

jmp

short @12

;

 

;else {

;i--;

@7:

 

dec

ebx

;

 

;

j--;

;

 

dec

eax

@12:

 

test

eax,eax

jg

short @5

;

 

;}

;}

;for (j = 0; j <= i; j++)

?live1@240: ; EBX = i, ESI = &_A, EDI = k @6:

xor

eax,eax

cmp

ebx,eax

jl

short @14

;

; A[j] = -1;

;

?live1@256: ; EBX = i, EAX = j, ESI = &_A, EDI = k @13:

mov

dword ptr [esi+4*eax],-1

inc

eax

cmp

ebx,eax

jge

short @13

;

; printf("\n\n");

;

?live1@272: ; ESI = &_A, EDI = k @14:

push

offset s@+4

call

_printf

14

pop ecx

;

; for (i = 0; i < dimA; i++)

;

xor ebx,ebx

;

; printf("%d ", A[i]);

;

?live1@304: ; EBX = i, ESI = &_A, EDI = k @16:

 

push

dword

ptr [esi+4*ebx]

 

push

offset s@+7

 

call

_printf

 

add

esp,8

 

 

inc

ebx

 

 

cmp

ebx,7

 

 

jl

short

@16

;

 

 

 

;

printf("\n");

 

;

 

 

 

?live1@320: ; EDI = k

 

 

push

offset s@+11

 

call

_printf

 

pop

ecx

 

;

 

 

 

;

for (i = 0; i

< k; i++)

;

 

 

 

 

xor

ebx,ebx

 

cmp

edi,ebx

 

jle

short

@20

;

; printf("%p ", B[i]);

;

?live1@352: ; EBX = i, EDI = k @19:

push

dword ptr [_B+4*ebx]

push

offset s@+13

call

_printf

add

esp,8

inc

ebx

cmp

edi,ebx

jg

short @19

;

; return 0;

;

?live1@368: ; @20:

 

xor

 

eax,eax

;

 

 

 

;

}

 

 

;

 

 

 

@23:

 

 

 

@22:

 

 

 

 

pop

 

edi

 

pop

 

esi

 

pop

 

ebx

 

pop

 

ebp

 

ret

 

 

_main endp

 

 

_TEXT ends

 

 

_BSS

segment dword public use32 'BSS'

 

align 4

 

_B

label dword

 

db

28

dup(?)

 

 

15

_BSS

ends

 

_DATA

segment dword public use32 'DATA'

s@

label byte

 

;

s@+0:

 

db

"%d ",0,10,10,0

 

;

s@+7:

 

db

"%d ",0,10,0

 

;

s@+13:

 

db

"%p ",0

 

align

4

_DATA ends

_TEXT segment dword public use32 'CODE' _TEXT ends

public

_A

public

_B

public

_main

extrn _printf:near

?debug

D "C:\BC5\INCLUDE\_null.h" 8825 10304

?debug

D "C:\BC5\INCLUDE\_nfile.h" 8825 10304

?debug

D "C:\BC5\INCLUDE\_defs.h" 8825 10304

?debug

D "C:\BC5\INCLUDE\stdio.h" 8825 10304

?debug

D "c31v0.c" 12910 21959

end

 

Отладку файла c31v0.exe нужно проводить с помощью 32-разрядного отладчика: td32.exe c31v0.exe

20.7. Программы на языке Си, размещенные в нескольких файлах.

Большие программы на языке Си создает бригада программистов. Они распределяют между собой работу по написанию подпрограмм. Каждый программист создает свой файл с подпрограммами. Далее их нужно собрать вместе. Порядок работы здесь следующий.

Если в файлах нет ссылки на общие глобальные данные (Глобальных данных следует избегать), то нужно только обеспечить правильный вызов функций.

20.8. Исполняемые файлы формата com

Мы уже создавали com-файлы с помощью отладчиков. Посредством tasm и tlink мы создавали только exe-файлы. Теперь с их помощью научимся получать и .com-файлы. Расширение файла com расшифровывается так: COre iMage. Вольный перевод: образ в оперативной памяти. Мы видели, что exe-файлы содержат блок управляющей и настроечной информации, в листинге отмечалось специальными флажками, где коды объектного и загрузочного файлов будут различными. Содержимое com-файла — в точности те же коды, которые будут расположены после загрузки в оперативной памяти. Эти файлы занимают меньше дисковой памяти, быстрее загружаются в ОЗУ, но при их создании надо придерживаться некоторых ограничений.

Различия между exe- и com-файлами сведем в таблицу (табл. *.1)

Таблица *.1

Свойство

exe-файл

com-файл

Размер

Любой

Не превышает 64 Кбайта

программы

 

 

Стек

Определяется сегмент стека.

Стек определяется при загрузке.

 

 

SP = FFFE.

Данные

Обычно определяется сегмент

Данные размещаются в кодовом

 

данных.

сегменте.

Содержимое

CS — указывает на сегмент кода,

CS, SS, DS, ES —

сегментных

SS — указывает на сегмент

указывают на PSP

16

регистров

стека,

DS, ES — указывают на PSP

Итак, из первой строки таблицы ясно, что размер com-файла не превышает 64K. Но в Windows 95 размер файла command.com составляет 92870 байтов! На самом деле это exeфайл (нетрудно убедиться, что его первые два байта образуют сигнатуру 'MZ') и расширение .com ему присваивают по традиции.

Прежде чем приводить пример .com-программы, познакомимся с новой для нас директивой Ассемблера.

ORG выражение — вычисляет выражение и присваивает полученное значение счетчику адреса. (Напомню, что счетчик адреса хранится во встроенной переменной $.)

Пример программы повторяет нашу первую программу, но в новом формате:

pc.asm

 

 

 

INCLUDE macro.inc

 

 

.MODEL tiny

 

 

.CODE

 

 

ORG 100h

; Выделить пространство для PSP

start:

jmp short begin

; "Обойти" данные

msg

DB "Hello!",0Dh,0Ah,'$'

 

begin: message msg exit

END start

Директива ORG 100h выделяет 256 байтов для префикса программного сегмента. (Можно было вместо этой директивы написать $ = $ + 100h или DB 100h DUP(?).) При написании программ в exe-формате заботиться об этом не было необходимости.

Данные рекомендуется помещать перед кодом, чтобы ассемблеру было легче сгенерировать нужные коды команд. Но по смещению 100h обязательно должна находиться команда, а не данные. Поэтому инструкция безусловного перехода передает управление на первую "настоящую" команду кода. Сегментный регистр DS теперь загружать не нужно. Программу можно было завершить не вызовом функции 4Ch, а прерыванием int 20h, специально предназначенным для завершения com-программ. (Для int 20h регистр CS должен указывать на PSP. Но для com-программ это и так выполнено.)

Последовательность действий для получения com-файла. Нужно выполнить команды:

tasm pc.asm tlink/t pc.obj

Ключ /t указывает tlink, что нужно создавать pc.com, а не pc.exe. (t — сокращение от tiny.) Упражнение. Какое сообщение об ошибке выдаст tlink, если вы опустите директиву

ORG 100h? если вы включите директиву .STACK 100h? Упражнение. Сравните размеры файлов p.exe (гл. ) и p.com. С помощью MASM файл pc.com можно получить так:

ml/AT pc.asm

В ранних версиях MASM сначала нужно было получить exe-файл, а затем преобразовать его в com-файл с помощью утилиты exe2bin.

Отладка com-файлов. Если, как раньше, добавить к tasm и tlink ключи /zi и /v, то, к нашему разочарованию, td сообщит нам: "Program has no symbol table". Действуем подругому: сначала получим pc.exe, а затем преобразуем его в pc.com, размещая отладочную информацию в отдельном файле.

tasm/zi pc.asm

17

tlink/v pc.obj (создает pc.exe, выдает предупреждение: No stack — игнорируем его) tdstrip –s –c pc.exe

td pc.com

Утилита tdstrip переносит отладочную информацию из pc.exe в файл pc.tds (ключ –s), и преобразует pc.exe в pc.com (ключ –c). Отладчик, не найдя в исполняемом файле отладочной информации, ищет ее в файле с расширением tds.

Соседние файлы в папке Assembler