Я конвертирую огромную DLL Windows для работы как в Windows, так и в Linux. У dll есть много сборок (и инструкции SS2) для обработки видео.
Теперь код компилируется как на Windows, так и на Linux с использованием компилятора Intel, входящего в состав Intel ComposerXE-2011, на Windows и Intel ComposerXE-2013 SP1 на Linux.
Выполнение, однако, приводит к сбоям в Linux при попытке вызвать указатель на функцию. Я проследил код в gdb, и действительно, указатель функции не указывает на требуемую функцию (тогда как в Windows в делает). Почти все остальное отлично работает.
Это последовательность кода:
...
mov rdi, this
lea rdx, [rdi].m_sSomeStruct
...
lea rax, FUNCTION_NAME # if replaced by 'mov', works in Linux but crashes in Windows
mov [rdx].m_pfnFunction, rax
...
call [rdx].m_pfnFunction # crash in Linux
где:
1) 'this' имеет член структуры m_sSomeStruct.
2) m_sSomeStruct имеет член m_pfnFunction, который является указателем на функцию.
3) FUNCTION_NAME - свободная функция в одном модуле компиляции.
4) Все эти чистые функции сборки объявлены голыми.
5) 64-разрядная среда.
Что меня больше сбивает с толку, так это то, что если я заменю инструкцию "lea", которая должна загрузить адрес функции в rax с инструкцией "mov", она отлично работает в Linux, но сбой в Windows. Я проследил код как в Visual Studio, так и в gdb и, по-видимому, в Windows "lea" дает правильный адрес функции, тогда как в Linux "mov" делает.
Я попытался найти ссылку на сборку Intel, но не нашел там ничего, что могло бы помочь мне (если я не искал нужное место).
Любая помощь приветствуется. Спасибо!
Изменить Подробнее:
1) Я попытался использовать квадратные скобки
lea rax, [FUNCTION_NAME]
но это не изменило поведение в Windows и Linux.
2) Я посмотрел на дизассемблер в gdb и Windows, похоже, оба дают те же инструкции, которые я на самом деле написал. Еще хуже то, что я попытался поместить оба lea
/mov
один за другим, и когда я смотрю на них при разборке в gdb, адрес, напечатанный после инструкции после знака # (который я предполагаю, является адрес, который будет сохранен в регистре) на самом деле тот же, и НЕ является правильным адресом функции.
В gdb disassembler это выглядело как
lea 0xOffset1(%rip), %rax # 0xSomeAddress
mov 0xOffset2(%rip), %rax # 0xSomeAddress
где оба (SomeAddress) были идентичны, и оба смещения были отключены с той же разницей между инструкциями lea и mov,
Но каким-то образом, когда я проверяю содержимое регистров после каждого выполнения, mov
кажется, помещается в правильное значение!!!!
3) Член-переменная m_pfnFunction имеет тип LOAD_FUNCTION, который определяется как
typedef void (*LOAD_FUNCTION)(const void*, void*);
4) Функция FUNCTION_NAME объявлена в .h(в пространстве имен) как
void FUNCTION_NAME(const void* , void*);
и реализован в .cpp как
__declspec(naked) void namespace_name::FUNCTION_NAME(const void* , void*)
{
...
}
5) Я попытался отключить оптимизацию, добавив
#pragma optimize("", off)
но я все еще имею ту же проблему