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

гос / sp-lect (1)

.pdf
Скачиваний:
18
Добавлен:
16.02.2016
Размер:
2.59 Mб
Скачать

invoke GetProcAddress,hDll,$CTA0("@fcstrcpy@8") or eax,eax

jz exit

mov fcstrcpy,eax lea edi,amemcpy mov ebx,101

@@: invoke GetProcAddress,hDll,ebx or eax,eax

jz exit

mov dword ptr [edi],eax lea edi,[edi+4]

inc ebx

cmp ebx,105 jbe @B

lea edi,buffer lea esi,str1 push esi push edi

call astrcpy add esp,8

invoke StdOut,$CTA0("\nstrcpy:\t\t") invoke StdOut,edi

push offset str3 push offset str2 push edi

push 2 call astrcat add esp,16

invoke StdOut,$CTA0("\nstrcat:\t\t") invoke StdOut,edi

push 15 push 'x' push edi

call amemset add esp,12

invoke StdOut,$CTA0("\nmemset:\t\t") invoke StdOut,edi

mov ecx,edi mov dl,'y' push 10

call fcmemset

invoke StdOut,$CTA0("\nfcmemset:\t") invoke StdOut,edi

add esp,4 push esi call astrlen inc eax push eax push esi push edi

call amemcpy add esp,12

invoke StdOut,$CTA0("\nmemcpy:\t\t") invoke StdOut,edi

push esi call astrlen mov ebx,eax

push $CTA0("\nstrlen:\t\tLength of string '") push edi

call astrcpy add esp,12

push $CTA0("' equal ") push esi

push edi push 2 call astrcat

push edi call astrlen

lea esi,[edi+eax] invoke dwtoa,ebx,esi invoke StdOut,edi mov ecx,edi

lea edx,str1 call fcstrcpy

invoke StdOut,$CTA0("\nfcstrcpy:\t") invoke StdOut,edi

invoke StdIn,edi,lengthof buffer invoke FreeLibrary,hDll

exit: invoke ExitProcess,0 end start

7.6.5 Звязування Microsoft Visual C++ із динамічними бібліотеками

7.6.5.1 Раннє звязування

Зовнішньо раннє звязування проекту Microsoft Visual C++ із динамічною бібліотекою майже не відрізняється від звязування із статичною бібліотекою (див. розділ 7.5.3). Єдина відмінність полягає у використанні кваліфікатора

__declspec(dllexport) в описі прототипу функції.

Для раннього звязування програмний файл DLL (з розширенням dll) не потрібен і використовується тільки файл бібліотеки імпорту з розширенням lib, який автоматично створюється в результаті компонування DLL.

Приклад 7.7 Додаток на C (Microsoft Visual C++ 2008) dllstaticlinkcpp.exe,

що демонструє використання динамічної бібліотеки dlldemo.dll (див. Приклад 7.4) шляхом раннього звязування.

; Файл dllstaticlinkcpp.cpp

#include <iostream>

#include <cstdio>

#pragma comment(linker, "/DEFAULTLIB:dlldemo.lib")

extern "C"

{

__declspec(dllexport) unsigned int __stdcall astrlen(char* lpstr); __declspec(dllexport) void __cdecl amemcpy(char*, char*,unsigned int); __declspec(dllexport) void __cdecl astrcpy(char* lpdst, char* lpsrc); __declspec(dllexport) void __fastcall fcstrcpy(char* lpdst, char* lpsrc); __declspec(dllexport) void __cdecl amemset(char*, char,unsigned int); __declspec(dllexport) void __fastcall fcmemset(char*, char, unsigned int); __declspec(dllexport) void __cdecl astrcat(unsigned int strcount,...);

}

using namespace std; int main()

{

char str1[]="First string"; char str2[]="+second string"; char str3[]="+third string"; char buffer[80]; astrcpy(buffer,str1);

cout<<"astrcpy:\t"<<buffer<<endl;

astrcat(2,buffer,str2,str3);

cout<<"astrcat:\t"<<buffer<<endl;

amemset(buffer,'x',15);

cout<<"amemset:\t"<<buffer<<endl;

fcmemset(buffer,'y',10);

cout<<"fcmemset:\t"<<buffer<<endl;

amemcpy(buffer,str1,astrlen(str1)+1);

cout<<"amemcpy:\t"<<buffer<<endl; cout<<"strlen:\t\tLength of string '"<<str1\ <<"' equal "<<astrlen(str1)<<endl; fcstrcpy(buffer,str1); cout<<"fcstrcpy:\t"<<buffer<<endl;

return 0;

}

7.6.5.2 Пізнє звязування

Пізнє звязування з DLL на С вимагає попереднього визначення типів FARPROC для кожної функції з подальшим приведенням результату, що повертає GetProcAddress на цей тип.

Приклад 7.8 Додаток dlldynamiclinkcpp.exe, що демонструє використання динамічної бібліотеки dlldemo.dll (див. Приклад 7.4) шляхом пізнього звязування.

; Файл dlldynamiclinkcpp.cpp

#include <windows.h>; LPSTR, HINSTANCE, NULL, MAKEINTRESOURCE

#include <iostream> #include <cstdio> using namespace std;

typedef DWORD (__stdcall *dllstrlen)(LPSTR);

typedef void (__cdecl *dllmemcpy)(LPSTR lpdst, LPSTR lpsrc,DWORD n); typedef void (__cdecl *dllstrcpy)(char*, char*);

typedef void (__fastcall *dllfcstrcpy)(char* lpdst, char* lpsrc);

typedef void (__cdecl *dllmemset)(char* lpdest, char chr,unsigned int count); typedef void (__fastcall *dllfcmemset)(char*, char,unsigned int);

typedef void (__cdecl *dllstrcat)(unsigned int strcount,...); int main()

{

char str1[]="First string"; char str2[]="+second string"; char str3[]="+third string"; char buffer[80];

HINSTANCE hDll; dllmemcpy pmemcpy; dllstrcpy pstrcpy; dllfcstrcpy pfcstrcpy; dllmemset pmemset; dllfcmemset pfcmemset; dllstrcat pstrcat;

dllstrlen pstrlen; if((hDll=LoadLibrary("dlldemo.dll"))!=NULL)

{

pstrcpy=(dllstrcpy)GetProcAddress(hDll,"astrcpy");

pstrcpy(buffer,str1);

cout<<"astrcpy:\t"<<buffer<<endl;

pstrcat=(dllstrcat)GetProcAddress(hDll,"astrcat");

pstrcat(2,buffer,str2,str3);

cout<<"astrcat:\t"<<buffer<<endl;

pmemset=(dllmemset)GetProcAddress(hDll,"amemset");

pmemset(buffer,'x',15);

cout<<"amemset:\t"<<buffer<<endl;

pfcmemset=(dllfcmemset)GetProcAddress(hDll,

MAKEINTRESOURCE(104));

pfcmemset(buffer,'y',10);

cout<<"fcmemset:\t"<<buffer<<endl;

pmemcpy=(dllmemcpy)GetProcAddress(hDll,"amemcpy"); pstrlen=(dllstrlen)GetProcAddress(hDll,"_astrlen@4"); pmemcpy(buffer,str1,pstrlen(str1)+1); cout<<"amemcpy:\t"<<buffer<<endl; cout<<"strlen:\t\tLength of string '"<<str1

<<"' equal "<<pstrlen(str1)<<endl; pfcstrcpy=(dllfcstrcpy)GetProcAddress(hDll,"fcstrcpy"); pfcstrcpy(buffer,str1); cout<<"fcstrcpy:\t"<<buffer<<endl;

} else {

MessageBox(0,"Не можу завантажити бібліотеку", NULL,MB_OK | MB_ICONERROR);

return(-1);

}

return 0;

}

8 ПРОГРАМУВАННЯ МАТЕМАТИЧНОГО СПІВПРОЦЕСОРУ

Для виконання операції з плаваючою комою у процесорах Intel64 використовується спеціальний пристрій – Floating Point Unit (FPU). Це спеціалізований процесор з власними регістрами і власним набором команд, який спочатку постачався у вигляді окремої мікросхеми (і8087, і80287, і80387), що отримала назву математичного співпроцесора і уставлялася в спеціально передбачене для неї рознімання на системній платі, а починаючи з і80486DX4100 – вбудовується в мікросхему основного (CPU) процесора.

Не зважаючи на фізичне поєднання основного процесора і математичного співпроцесора в одному корпусі інтегральної мікросхеми, логічно це два різні обчислювальні пристрої. Процесор і математичний співпроцесор можуть працювати паралельно над виконанням різних команд, однак повної паралельності в їх роботі немає, бо процесор забезпечує математичному співпроцесору інтерфейс з памяттю. Синхронізація доступу до памяті з боку процесора і співпроцесора забезпечується в більшості випадків апаратними засобами і при програмуванні є абсолютно прозорою.

8.1 Програмна модель математичного співпроцесору

Під програмною моделлю математичного співпроцесору, так само як і під програмною моделлю основного процесору, розуміють його організацію з точки зору можливостей програмування. Рисунок 8.1 відображає складові програмної моделі математичного співпроцесору.

Рисунок 8.1 Зважаючи на те, математичний співпроцесор є складовою частиною

основного процесору, в контексті його програмної моделі не розглядаються

режими роботи, які від «успадковує» від основного процесору і тому вони не представлені на рисунку.

Зважаючи на те, що основний процесор забезпечує математичному співпроцесору інтерфейс з памяттю, способи організації і адресації памяті для них співпадають. Вони представлені на рисунку тому, що в системі команд співпроцесору є команди, які передбачають використання операндів в памяті. Для таких операндів будуть використовуватися відомі вже з попередніх розділів курсу способи адресації памяті.

8.1.1 Типи даних математичного співпроцесора

Математичний співпроцесор підтримує наступні типи даних:

1.Двійкові цілі (знаковий біт у старшому розряді) числа в трьох форматах: а) 16-бітне ціле число від -32 768 до 32 767; б) 32-бітне коротке ціле від -2 · 109 до +2 · 109; в) 64-бітне довге ціле від -9 · 1018 до +9 · 1018;

2.Числа з плаваючою комою в трьох форматах:

а) коротке 32-бітне дійсне число від 10-38 до 10+38; б) довге 64-бітне дійсне число від 10-308 до 10+308;

в) розширене 80-бітне дійсне число від 10-4932 до 10+4932;

3.Упаковані цілі BCD-числа в форматі 9+1 – в девяти молодших байтах розміщуються числові розряди, а в десятому байті використовується тільки старший біт для кодування знаку)

4.Спеціальні числові значення

а) позитивний і негативний нуль; б) позитивна і негативна нескінченність; в) денормалізовані дійсні числа;

г) сигнальні не числа SNAN і тихі не числа QNAN

Визначення в програмі 16/32/64-бітних двійкових цілих виконується звичним способом за допомогою директив, відповідно, WORD / DWORD / QWORD.

Визначення в програмі 32/64/80-бітних чисел з плаваючою комою може виконуватися за допомогою директив, відповідно, (DD | DWORD | REAL4) / (DQ | QWORD | REAL8) / (DT | REAL10) двома способами в природній або в експоненціальній формі. В будь якій формі в записі числа повинен бути присутнім символ «.» десяткової крапки, навіть якщо число не має дробової частини:

X1 DD 123.

Y1 QWORD 123456.0

Z1 DT 123.456

X2 REAL4 1.23e+2

Y2 REAL8 –0.123456+e6

Z2 REAL10 123456.0e-3

Визначення в програмі упакованих цілих BCD-чисел виконується звичним способом за допомогою директиви DT. Спеціальні числові значення зявляються у результаті обчислень і, як правило, попередньо не визначаються.

8.1.2Склад і призначення регістрів співпроцесора

Впрограмній моделі математичного співпроцесора (Рисунок 8.2) можна виділити три групи регістрів. Основу моделі складає група з восьми 80- розрядних регістрів даних R0–R7 в яких зберігаються числа з плаваючою комою в розширеному форматі: старший (79-й) біт визначає знак числа, в бітах 78–64 розташована так звана характеристика числа, а в бітах 63–0 розміщується його мантиса. Мантиса зберігається у нормалізованому вигляді, у якому вона завжди починається з одиниці. При нормалізації кома в запису числа переміщується вправо або вліво так, щоб в цілій частини числа була єдина одиниця. Кількість перенесень коми визначає порядок числа s який зберігається

уполі характеристики як значення q=s+16383.

Рисунок 8.2

При завантаженні з памяті в регістри R0-R7 даних будь-яких інших типів

(див. 8.1.1) вони автоматично перетворюються в розширений формат числа з

плаваючою комою і уся їх подальша обробка відбувається в цьому форматі. При вивантаженні результатів у память, якщо вони зберігаються там не

як числа з плаваючою комою в розширеному форматі, то автоматично відбувається потрібне перетворення. При перетворенні у більш короткі формати чисел с плаваючою комою «зайві» розряди після округлення

відкидаються.

З кожним фізичним регістром R0–R7 жорстко звязане (Рисунок 8.3) відповідне двох бітове поле в регістрі тегів співпроцесора (TR, Tag Register). Двох бітове число, що зберігається у відповідних бітах TR, у кожний момент

часу надає інформацію про вміст відповідного регістру:

00 –

в регістрі знаходиться припустиме не нульове значення;

01 –

в регістрі знаходиться нульове значення;

10 –

в регістрі знаходиться спеціальне числове значення;

11 –

регістр порожній.

 

Регістри даних

математичного співпроцесора організовано

у вигляді

стеку

і команди співпроцесора звертаються до регістрів даних

R0–R7 за

логічними номерами

ST(0)–ST(7). Логічний номер ST(0) позначає верхівку

стеку

математичного співпроцесору, а ST(1), ST(2), …, ST(7) –

елементи в

глибині стеку.

 

 

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