45
О некоторых вопросах бинарной совместимости в C++ Гомон Сергей, Regula [email protected]

о некоторых вопросах бинарной совместимости в C++

Embed Size (px)

Citation preview

Page 1: о некоторых вопросах бинарной совместимости в C++

О некоторых вопросах бинарной совместимости в C++Гомон Сергей, [email protected]

Page 2: о некоторых вопросах бинарной совместимости в C++

Обо мне

Более 5 лет опыта разработки

на C++.

Основные сферы интересов:

● Защита информации

● Сетевая разработка

● Обработка изображений2

Page 3: о некоторых вопросах бинарной совместимости в C++

Способы распространения библиотек

• Исходный код

• Статическая библиотека

• Динамическая библиотека

• RPC, COM, протоколы и т. п.

3

Page 4: о некоторых вопросах бинарной совместимости в C++

Идеальный мир

Один бинарник - все аппаратные и программные платформы

Реальный мир

Одна аппаратная и программная платформа - несколько бинарников

Платформа - совокупность аппаратного и программного обеспечения (Например Intel x86+Windows, Intel x64+Linux)

4

Page 5: о некоторых вопросах бинарной совместимости в C++

Исходный код

Плюсы

• Простота и удобство

• Возможность модификации кода

библиотеки

• Возможность поддержать все

платформы

Минусы

• Разные диалекты C++

• Реализация алгоритмов открыта

• Нельзя использовать из других

языков программирования

5

Page 6: о некоторых вопросах бинарной совместимости в C++

Статическая библиотека

Плюсы

• Реализация алгоритмов скрыта

• Границы модуля четко

определены

Минусы

• Нельзя использовать из других

языков программирования

• Обновление библиотеки требует

перекомпиляции основной

программы

• Большой размер основной

программы 6

Page 7: о некоторых вопросах бинарной совместимости в C++

Динамическая библиотека

Плюсы

• Малый размер основной

программы

• Эффективное использование

ресурсов системы

• Можно использовать из

других языков

программирования

Минусы

• Требует глубоких знаний

механизмов работы ОС и

компилятора

7

Page 8: о некоторых вопросах бинарной совместимости в C++

RPC, COM, протоколы и т. п.

Плюсы

• Можно использовать из

других языков

программирования

• Можно использовать через

сеть

Минусы

• Сложно

• Дорого

• Медленно работает

8

Page 9: о некоторых вопросах бинарной совместимости в C++

Staticlib (C++ ABI)

Staticlib (C++ ABI)

Header-only lib

Dynlib (C ABI)

Web-service (C# pinvoke, Java jni, ...)

Internet

Client

Unit-tested

External API tested

App (C# pinvoke, Java

jni,...)

9

Page 10: о некоторых вопросах бинарной совместимости в C++

C# assembly COM object

CLI assembly wrapper (C++

ABI)

C++ App/Lib

Pascal dll (C ABI)

Client 10

Page 11: о некоторых вопросах бинарной совместимости в C++

API и ABI

API - application programming interface, интерфейс прикладного программирования (набор заголовочных файлов, предоставляемых библиотекой)

11

ABI - application binary interface, бинарный интерфейс приложения (скомпилированный API, ABI=API+compiler ABI)

Page 12: о некоторых вопросах бинарной совместимости в C++

Что описывает C++ ABI• Objects layout• Calling convention• Name mangling• Virtual function mechanism• Static object instantiation• C++ support function: set_uexpected(), operator new[]...• Exception handling• RTTI• Template instantiation• Memory debug facilities

12

Page 13: о некоторых вопросах бинарной совместимости в C++

ABI языка Си

• Objects alignment

• Name mangling

• Calling convention

• C support functions: atexit()

13

Page 14: о некоторых вопросах бинарной совместимости в C++

Стандарты Си и C++ не содержит описание ABI

14

Page 15: о некоторых вопросах бинарной совместимости в C++

Стандарты C++ ABI существуют

• Itanium C++ ABI

• Visual Studio C++ ABI

• Vendor specific C++ ABI (Intel, Embarcadero ...)

15

Page 16: о некоторых вопросах бинарной совместимости в C++

Пример: один компилятор C++

Продукт: Сложная система с большим количеством модулей

Условия: Для каждой платформы вся система компилируется одним компилятором C++ с одинаковыми параметрами компиляции

Хотим получить: Возможность обновлять отдельные модули независимо от других без необходимости перекомпиляции всей системы

16

Page 17: о некоторых вопросах бинарной совместимости в C++

Бинарная совместимость

Новую версию библиотеки можно использовать в системе без ее перекомпиляции

Совместимость по исходному коду

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

17

Page 18: о некоторых вопросах бинарной совместимости в C++

Мы можем...• Добавить новый класс• Добавить новый невиртуальный метод или новый конструктор• Добавить новый enum• Добавить новый элемент в существующий enum• Добавить новый статический член• Удалить приватный невиртуальный метод• Удалить приватный статический член класа• ...

18

Page 19: о некоторых вопросах бинарной совместимости в C++

Мы не можем...• Добавить новые данные в класс• Удалить ранее экспортированные функции, методы, классы и т. п.• Удалить виртуальный метод из класса• Изменить иерархию классов: добавлять, удалять или менять местами

базовые классы• Изменить шаблонные параметры: добавлять, удалять, менять местами• Изменять сигнатуру экспортируемой функции: тип возвращаемого

аргументы, входные аргументы, константность, volatile и т. п.• ...

19

Page 20: о некоторых вопросах бинарной совместимости в C++

Нарушение бинарной совместимости (1)

enum Enum { one, two, max = 0xFFFFFFFF};

sizeof(Enum) is 4

enum Enum { one, two, three, max = 0xFFFFFFFF};

sizeof(Enum) is 4

enum Enum { one, two, max = 0xFFFFFFFF, three};

sizeof(Enum) is 8

20

Page 21: о некоторых вопросах бинарной совместимости в C++

Нарушение бинарной совместимости (2)

class A {public: A() {} ~A() {}};

sizeof(A) is 1

class A {public: A() {} ~A() {} void f() {}};

sizeof(A) is 1

class A {public: A() {} ~A() {} virtual void f() {}};

sizeof(A) is 4

21

Page 22: о некоторых вопросах бинарной совместимости в C++

Нарушение бинарной совместимости (3)

class A {public: A() {} ~A() {}};

sizeof(A) is 1

class A {public: A() {} ~A() {}private: static int _a;};

sizeof(A) is 1

class A {public: A() {} ~A() {}private: int _a;};

sizeof(A) is 4

22

Page 23: о некоторых вопросах бинарной совместимости в C++

Что может помочьЗарезервированные поля:

struct S { int a; int b; int c; int reserverd_1; int reserverd_2;};

D-pointer (pimpl)

class A { // Exportedpublic: A() { d = new APrivate; } ~A() { delete d; }private: class APrivate; APrivate *d;};

class APrivate { // Not exported int a, b, c;};

23

Page 24: о некоторых вопросах бинарной совместимости в C++

Пример: несколько компиляторов C++

Продукт: сложная система с большим количеством модулей

Условия: Разные модули могут компилироваться разными компиляторами

Хотим получить: Возможность обновлять отдельные модули независимо от других без необходимости перекомпиляции всей системы

24

Page 25: о некоторых вопросах бинарной совместимости в C++

Декорирование имен

QString::replace(int, int, const QChar *, int);

GCC_ZN7QString7replaceEiiPK5

QChari

Visual Studio?

replace@QString@@QAEAAV0@HHPBVQChar@@H@Z

Q126845: "Microsoft does not publish the algorithm its compilers use for name decoration because it may change in the future."

25

Page 26: о некоторых вопросах бинарной совместимости в C++

Представление данных (Windows x64)

Microsoft Intel GNU

wchar_t 2 2 4

long int 4 4 8

long double 8 16 16

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

x = 21 = 0001 0101-21 = 1110 1011 - two's complement (дополнительный код): 2^N - x-21 = 1110 1010 - one's complement (обратный код): all bits of x is flipped

26

Page 27: о некоторых вопросах бинарной совместимости в C++

Выравнивание членов структур по умолчанию (Windows x86)

Microsoft Intel Borland

2 byte int 2 2 1

4 byte int 4 4 1

8 byte int 8 8 1

float 4 4 1

double 8 8 1

27

Page 28: о некоторых вопросах бинарной совместимости в C++

Соглашение о вызове

• __cdecl

• __stdcall

• __pascal

• __fastcall

Одинаковые соглашения могут реализовываться

компилятора по-разному!28

Page 29: о некоторых вопросах бинарной совместимости в C++

Модель памяти, исключения

• Каждый модуль должен управлять своей памятью

• Исключения не должны выбираться за пределы модуля

29

Page 30: о некоторых вопросах бинарной совместимости в C++

Макросы определения компилятораBorland __BORLANDC__

Codeplay VectorC __VECTORC__

Digital Mars __DMC__

Gnu __GNUC__

Intel __INTEL_COMPILER

Microsoft _MSC_VER

Pathscale __PATHSCALE__

Symantec __SYMANTECC__

30

Page 31: о некоторых вопросах бинарной совместимости в C++

Макросы определения аппаратной платформыx86 _M_IX86, __INTEL__, __i386__

x86-64 _M_X64, __x86_64__, __amd64

IA64 __IA64__

DEC Alpha __ALPHA__

Motorola Power PC __POWERPC__

Any little endian __LITTLE_ENDIAN__

Any big endian __BIG_ENDIAN__

31

Page 32: о некоторых вопросах бинарной совместимости в C++

Макросы определения программной платформы

DOS 16 bit __MSDOS__, _MSDOS

Windows 16 bit _WIN16

Windows 32 bit _WIN32, __WINDOWS__

Windows 64 bit _WIN64, _WIN32

Linux 32 bit __unix__, __linux__

Linux 64 bit __unix__, __linux__, __LP64__, __amd64

BSD __unix__, __BSD__, __FREEBSD__

Mac OS __APPLE__, (__DARWIN__, __MACH__)

OS/2 __OS2__

32

Page 33: о некоторых вопросах бинарной совместимости в C++

COM, XPCOM

COM - component object model, спецификация бинарного

интерфейса от Microsoft.

XPCOM - cross-platform COM, спецификация бинарного

интерфейса от Mozilla для реализации браузера Firefox.

33

Page 34: о некоторых вопросах бинарной совместимости в C++

Как работает COM

class IUnknown { virtual HRESULT QueryInterface (REFIID riid, void **ppvObject) = 0; virtual ULONG AddRef () = 0; virtual ULONG Release () = 0;};

34

Page 35: о некоторых вопросах бинарной совместимости в C++

Экспортирование классов

class Interface {public: virtual void destroy() = 0; virtual void hello() = 0; virtual void world() = 0;protected: virtual ~Interface() {}};

class Class : public Interface {public: static Interface* create() { return new Class; } void destroy() override { delete this; } void hello() override { std::cout << "Hello" << std::endl; } virtual void world() override { std::cout << "World" << std::endl; }private: Class() {} ~Class() {}};

35

CH_DLL_FUNC(Interface*) create() { return Class::create(); }

Page 36: о некоторых вопросах бинарной совместимости в C++

Использование импортированного класса из C++

36

auto hDynLib = LoadLibraryW(L"DynLib.dll");

auto createFunc =

reinterpret_cast<CreateFunc>(GetProcAddress(hDynLib, "create"));

Interface *obj = createFunc();

obj->hello();

obj->world();

obj->destroy();

obj = nullptr;

Page 37: о некоторых вопросах бинарной совместимости в C++

Использование импортированного класса из C

37

struct VPtr;struct CInterface { VPtr *vptr;};

typedef void DestroyFunc(CInterface*);typedef void HelloFunc(CInterface*);typedef void WorldFunc(CInterface*);

struct VPtr { DestroyFunc *destroy; HelloFunc *hello; WorldFunc *world;};

HMODULE hDynLib = LoadLibraryW(L"DynLib.dll");CreateFunc createFunc =(CreateFunc)( GetProcAddress(hDynLib, "create"));CInterface *obj = (CInterface*)(createFunc());obj->vptr->hello(obj);obj->vptr->world(obj);obj->vptr->destroy(obj);obj = nullptr;

Page 38: о некоторых вопросах бинарной совместимости в C++

Пример: несколько языков программирования

Продукт: Сложная система с большим количеством модулей

Условия: Для реализации модулей используются разные языки программирования

Хотим получить: Возможность обновлять отдельные модули независимо от других без необходимости перекомпиляции всей системы. Возможность использовать модули на C++ из других языков программирования.

38

Page 39: о некоторых вопросах бинарной совместимости в C++

Только Си ABI

• Никакого декорирования имен

• Только POD типы

• Явное указание выравнивания структур

• Явное указание соглашения о вызове

39

Page 40: о некоторых вопросах бинарной совместимости в C++

Проблемы с Си ABIСколько занимает памяти?

struct S { long l; int i; short s; char ch;};

15, 16, 24, 32?

Какой символ экспортируется?

int func(int a, int b, int c);

func, _func, _func@12 ?

40

Page 41: о некоторых вопросах бинарной совместимости в C++

Макросы иногда помогают

41

#ifdef __cplusplus# define CH_EXTERNC extern "C"#else // __cplusplus# define CH_EXTERNC#endif // __cplusplus

#ifdef _WIN32# define CH_CDECL __cdecl# define CH_DLLEXPORT __declspec(dllexport)# define CH_DLLIMPORT __declspec(dllimport)# ifdef CH_BUILD_DLL# define CH_EXPORT CH_EXTERNC CH_DLLEXPORT# else // CH_BUILD_DLL# define CH_EXPORT CH_EXTERNC CH_DLLIMPORT# endif#else // _WIN32// ...#endif // _WIN32#define CH_DLL_FUNC(type) CH_EXPORT type CH_CDECL

Page 42: о некоторых вопросах бинарной совместимости в C++

Упаковка стурктур// DynLibPackPush.h

#ifdef _MSC_VER

#pragma pack(push, 1)

#else // _WIN32

// ...

#endif

// DynLibPackPop.h

#ifdef _MSC_VER

#pragma pack(pop)

#else // _WIN32

// ...

#endif

42

Page 43: о некоторых вопросах бинарной совместимости в C++

Экспорт функции

43

// DynLib.h

#pragma once

#include <cstdint>#include "DynLibMacro.h"#include "DynLibPackPush.h"

typedef uint32_t (*CreateFunc)(uint32_t,uint32_t);CH_DLL_FUNC(uint32_t) create(uint32_t,uint32_t);

#include "DynLibPackPop.h"

Page 44: о некоторых вопросах бинарной совместимости в C++

Спасибо за внимание!

44

Page 45: о некоторых вопросах бинарной совместимости в C++

Источники

1. COM in plain C - http://www.codeproject.com/Articles/13601/COM-in-plain-C

2. Export C++ classes from a DLL -

http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

3. Policies/Binary Compatibility Issues With C++ -

https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B

4. Matthew Wilson - Imperfect C++

5. Agner Fog - Calling conventions for different C++ compilers and operating systems

45