Сборка COM-объекта vtable в сборке x86 - PullRequest
4 голосов
/ 26 июля 2010

Я строю COM-объект в сборке x86, используя NASM. Я достаточно хорошо понимаю COM и понимаю, что такое сборка x86, но то, что я запутался, мешает мне ... (кстати, если вы хотите отговорить меня от использования сборки x86, пожалуйста, воздержитесь, У меня есть очень конкретные причины, почему я собираю это в сборке x86!)

Я пытаюсь создать vtable для использования в моем COM-объекте, но я продолжаю получать странные указатели, а не фактические указатели на мои функции. (Я думаю, что я получаю относительные смещения или что NASM встраивает туда временные значения, и они не заменяются реальными значениями во время связывания)

Текущий интерфейс, который я пытаюсь создать, - это интерфейс IClassFactory, с кодом следующим образом:

%define S_OK 0x00000000
%define E_NOINTERFACE 0x80004002

section .text

; All of these have very simple shells rather than implementations, but that is just until I can get the vtable worked out

ClassFactory_QueryInterface:
    mov eax, E_NOINTERFACE
    retn 12

ClassFactory_AddRef:
    mov eax, 1
    retn 4

ClassFactory_Release:
    mov eax, 1
    retn 4

ClassFactory_CreateInstance:
    mov eax, E_NOINTERFACE
    retn 16

ClassFactory_LockServer:
    mov eax, S_OK
    retn 8

global ClassFactory_vtable
ClassFactory_vtable dd ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, ClassFactory_CreateInstance, ClassFactory_LockServer

global ClassFactory_object
ClassFactory_object dd ClassFactory_vtable

Примечание: Это не весь код, у меня DllGetClassObject, DllMain и т. Д. В другом файле.

Но когда я собираю (используя NASM: nasm -f win32 comobject.asm) и ссылку (используя MS Link: link /dll /subsystem:windows /out:comobject.dll comobject.obj) и проверяю исполняемый файл, используя OllyDbg, vtable выходит со странными значениями. Например, в моей последней сборке фактические адреса для функций были следующими:

  • QueryInterface - 0x00381012
  • AddRef - 0x0038101A
  • Релиз - 0x00381020
  • CreateInstance - 0x00381026
  • LockServer - 0x0038102E

Но vtable вышел со следующими значениями:

  • QueryInterface - 0x00F51012
  • AddRef - 0x00F5101A
  • Релиз - 0x00F51020
  • CreateInstance - 0x00F51026
  • LockServer - 0x00F5102E

Эти значения выглядят ужасно подозрительно ... почти так же, как и перемещение. Кроме того, vtable выходит как 0x00F5104A, все из которых являются адресами недоступной памяти. ( в информационных целях, эти значения каждый раз различаются )

Я попытался сделать то же самое в C ++, используя Visual Studio 2010 Express, и все получилось хорошо. Поэтому я предполагаю, что это просто то, чего мне не хватает в моей сборке ...


Может кто-нибудь указать мне, почему эти значения не выходят должным образом?

Ответы [ 3 ]

2 голосов
/ 02 августа 2010

Я должен извиниться, проблема оказалась из-за моей собственной ошибки ... Во время всей этой потасовки я убрал /dll из вызова компоновщика, в результате чего он был собран как EXE, а не как DLL ...


Позвольте мне объяснить это немного лучше для следующего человека, который сталкивается с этим.

Все исполняемые файлы Windows имеют базовый адрес , который считается виртуальным адресом, в который будет загружен исполняемый файл. Исполняемые файлы, которые загружаются в работающий процесс, в большинстве случаев не будут загружаться по «предпочтительному» базовому адресу , поскольку другая DLL (или само приложение), вероятно, уже занимает адрес. По этой причине исполняемые файлы Windows PE используют так называемую таблицу перемещений . Таблица Перемещения сообщает Windows, какие места в исполняемом файле необходимо переписать в случае перемещения на новый базовый адрес .

Однако, с появлением Виртуальная память , большинство компоновщиков исключают таблицу перемещения из EXE-файлов в качестве оптимизации, поскольку исполняемый файл всегда будет загружаться по его базовому адресу (если он не конфликтует с зарезервированным ядром). адреса, в этом случае он не сможет загрузить все вместе). Так как я перестал компилировать как DLL, мой исполняемый файл не получил Таблицу перемещений и, как следствие, не загружался должным образом в адресное пространство запущенного процесса.


Обновление:

По умолчанию MSVC включает только таблицы перемещения в проектах DLL, как описано в MSDN :

By default, /FIXED:NO is the default when building a DLL, and /FIXED is the default for any other project type.

Это поведение можно изменить, подключив переключатель /FIXED:NO к компоновщику. По умолчанию для проектов, не относящихся к DLL, - /FIXED, что говорит компоновщику, что целевой объект имеет фиксированный базовый адрес и не требует таблицы перемещения.

1 голос
/ 27 июля 2010

Вы пытались также объявить свои глобальные списки как экспортные?Я давно не делал x86.Но чтение документации nasm, по-видимому, подразумевает, что вам нужно как глобально, так и экспортировать, чтобы исправление перемещения DLL работало.

1 голос
/ 26 июля 2010

Вы пытались построить заглушку COM-интерфейс в C и разобрать результат?Это должно дать вам представление о том, что не так в вашей реализации.

...