Связыватель не может найти символ сборки

Вопрос или проблема

Windows 10, Visual Studio 2022 Community. Модель x64. Вот файл сборки

.code
PUBLIC StubCode

StubCode PROC 
    mov rax, 4711
    ret
StubCode ENDP
end

Вот часть на C++:

extern __int64 __cdecl StubCode();

int main()
{
    __int64 n = StubCode();
    return 0;
}

Файл сборки компилируется без ошибок. Параметры сборки->Настройка сборки установлена на masm.

Файл C++ показывает следующее:

error LNK2019: неразрешенный внешний символ “__int64 __cdecl StubCode(void)”
Подсказка по символам, которые определены и могут соответствовать: StubCode

Я также пробовал __stdcall и __fastcall. Никакой разницы.
Что не хватает компоновщику?

Решение:
extern “C” extern __int64 StubCode(void);

Вызов происходит через __fastcall независимо от сигнатуры.
Это означает, что первые четыре аргумента находятся в регистрах, остальные на стеке. Если вы хотите вызвать с аргументами:

.code
PUBLIC StubCode
;///////////////////////////////////////////////////////////////
;// Fastcall, rcx первый, rdx второй, r8 третий, r9 четвертый
;//
StubCode PROC 
    mov rax, [rsp + 40] ; Пятый 
    mov rax, [rsp + 48] ; Шестой
    mov rax, [rsp + 56] ; Седьмой
    mov rax, [rsp + 64] ; ... и так далее ...
    ret
StubCode ENDP
end

Вызов с

__int64 n = StubCode(1, 2, 3, 4, 5, 6, 7, 8);

Ответ или решение

Ответ на вопрос: Ссылка на символ сборки не найдена

Описание проблемы:
Вы столкнулись с ошибкой компоновщика, которая сообщает о том, что не удается разрешить внешний символ __int64 __cdecl StubCode(void). Вы используете Windows 10 и Visual Studio 2022 Community для работы с проектом, который включает как ассемблерный, так и C++ код.

Код на ассемблере:

.code
PUBLIC StubCode

StubCode PROC 
    mov rax, 4711
    ret
StubCode ENDP
end

Код на C++:

extern __int64 __cdecl StubCode();

int main()
{
    __int64 n = StubCode();
    return 0;
}

Причина ошибки:
Ошибка компоновщика LNK2019 указывает на то, что компоновщик не может найти реализацию символа StubCode с той сигнатурой, которая указана в C++. Основная причина кроется в соглашении о вызовах и манере, как символы обрабатываются между C++ и ассемблером.

Когда вам нужно использовать ассемблерный код в C++, особенно если вы используете различные соглашения о вызовах (например, __cdecl, __stdcall, __fastcall), необходимо убедиться, что символы экспортируются и объявляются правильно.

Решение:

  1. Используйте extern "C":
    Чтобы предотвратить изменение имени символа при компиляции, оберните декларацию вашей функции в extern "C" в C++ коде. Это остановит подавление именования и гарантирует, что символ будет доступен компоновщику.

    Измените вашу декларацию следующим образом:

    extern "C" __int64 __cdecl StubCode();
  2. Проверьте соглашение о вызовах:
    Ваша функция может быть вызвана с использованием определенного соглашения. Убедитесь, что объявление функции в C++ соответствует ее реализации. Если вы хотите использовать __fastcall, вам нужно будет изменить как декларацию, так и определение:

    На стороне C++:

    extern "C" __int64 __fastcall StubCode();

    На стороне ассемблера:

    .code
    PUBLIC StubCode
    ;///////////////////////////////////////////////////////////////
    ; Fastcall, rcx first, rdx second, r8 third, r9 fourth
    ;
    StubCode PROC 
       mov rax, [rsp + 40] ; Пятый аргумент
       mov rax, [rsp + 48] ; Шестой аргумент
       mov rax, [rsp + 56] ; Седьмой аргумент
       mov rax, [rsp + 64] ; ... и так далее ...
       ret
    StubCode ENDP
    end
  3. Используйте правильный вызов функции:
    Если вы измените соглашение на __fastcall, вам нужно будет передать параметры, как показано ниже:

    __int64 n = StubCode(1, 2, 3, 4, 5, 6, 7, 8);

Заключение

Использование правильных соглашений о вызовах и грамотное формулирование деклараций функций между C++ и ассемблером решит вашу проблему с линковкой. Убедитесь, что оба компонента правильно синхронизированы, и ваша программа скомпилируется и свяжется без ошибок.

Оцените материал
Добавить комментарий

Капча загружается...