Здесь будут приведены примеры импорта и экспорта функций, применительно к Borland C/C++.
Пусть наш проект состоит из файла на C++ (CPPFILE.CPP) и файла на ассемблере (ASMFILE.ASM), а результирующий EXE-шник называется EXEFILE.EXE.
И пусть мы хотим вызывать функции, написанные в си-шном исходнике из ассемблерного кода, и наоборот; а также экспортировать и си-шные и ассемблерные функции из полученного PE EXE файла.
Пусть также есть некоторая внешняя библиотека ANYDLL.DLL, функции из которой мы хотим использовать в обоих частях проекта, т.е. и на ассемблере и на си.
Вот как тогда будет выглядеть файл СPPFILE.CPP:
#include <stdio.h> extern "C" { int __cdecl CodeInASM_UseInCPP_CName (int x); int _import __cdecl CodeInEXTPE_UseInCPP_Cname (int x); int _import __cdecl CodeInEXTPE_UseInCPP_Ordinal (int x); int __cdecl CodeInCPP_UseInASM_CName (int x) { return x; } int _export __cdecl CodeInCPP_UseInEXTPE_CName (int x) { return x; } } extern "C++" { int __cdecl CodeInASM_UseInCPP_CPPName (int x); int _import __cdecl CodeInEXTPE_UseInCPP_CPPname (int x); int __cdecl CodeInCPP_UseInASM_CPPName (int x) { return x; } int _export __cdecl CodeInCPP_UseInEXTPE_CPPName (int x) { return x; } } int RegisterUsage() { return (int)&CodeInASM_UseInCPP_CName + (int)&CodeInASM_UseInCPP_CPPName + (int)&CodeInEXTPE_UseInCPP_Cname + (int)&CodeInEXTPE_UseInCPP_CPPname + (int)&CodeInEXTPE_UseInCPP_Ordinal + (int)&CodeInCPP_UseInASM_CName + (int)&CodeInCPP_UseInASM_CPPName + (int)&CodeInCPP_UseInEXTPE_CName + (int)&CodeInCPP_UseInEXTPE_CPPName; } int main() { RegisterUsage(); } |
В свою очередь, ASMFILE.ASM будет выглядеть так:
public _CodeInASM_UseInCPP_CName _CodeInASM_UseInCPP_CName: mov eax, [esp+4] retn public @CodeInASM_UseInCPP_CPPName$qi @CodeInASM_UseInCPP_CPPName$qi: mov eax, [esp+4] retn publicdll CodeInASM_UseInEXTPE CodeInASM_UseInEXTPE: mov eax, [esp+4] retn public CodeInASM_UseInEXTPE_RenameInDef CodeInASM_UseInEXTPE_RenameInDef: mov eax, [esp+4] retn extern CodeInEXTPE_UseInASM_Name:PROC call CodeInEXTPE_UseInASM_Name extern CodeInEXTPE_UseInASM_Ordinal:PROC call CodeInEXTPE_UseInASM_Ordinal |
Для успешной компиляции всего этого потребуется EXEFILE.DEF файл, в котором будут описаны соответствия внутренних и внешних имен функций проекта:
EXPORTS AsmFunc = CodeInASM_UseInEXTPE_RenameInDef IMPORTS _CodeInEXTPE_UseInCPP_Cname = ANYDLL._CodeInEXTPE_UseInCPP_Cname @CodeInEXTPE_UseInCPP_CPPname$qi = ANYDLL.@CodeInEXTPE_UseInCPP_CPPname$qi _CodeInEXTPE_UseInCPP_Ordinal = ANYDLL.666 CodeInEXTPE_UseInASM_Name = ANYDLL.CodeInEXTPE_UseInASM_Name CodeInEXTPE_UseInASM_Ordinal = ANYDLL.777 |
Теперь, чтобы все это скомпилировать, понадобится файл MAKE.BAT:
@echo off set X=d:\whatever\borland\bcc55 %X%\bin\bcc32.exe -eEXEFILE -I%X%\include -L%X%\lib cppfile.cpp asmfile.asm |
С другой стороны, можно было бы сделать ANYDLL.LIB, посредством
IMPLIB.EXE -f anydll.lib anydll.dllпосле чего вместо IMPORTS-части EXEFILE.DEF файла, использовать ANYDLL.LIB; при этом надо не забыть подать ANYDLL.LIB в командную строку bcc32.exe.
Вот часть TDUMP'а от полученного EXEFILE.EXE:
Exports from EXEFILE.exe RVA Ord. Hint Name -------- ---- ---- ---- 00001168 3 0000 CodeInCPP_UseInEXTPE_CPPName(int) 000011C7 6 0001 AsmFunc 000011C2 4 0002 CodeInASM_UseInEXTPE 00001160 2 0003 _CodeInCPP_UseInEXTPE_CName Imports from ANYDLL.DLL _CodeInEXTPE_UseInCPP_Cname CodeInEXTPE_UseInCPP_CPPname(int) CodeInEXTPE_UseInASM_Name (ord. = 777) (ord. = 666) |