2013-04-22 2 views
6

Я работаю над проектом cpp. Проект должен быть перенесен на 64 бит. Он содержит некоторый код сборки Inline, который не может компилироваться на x64. Это функция, которая содержит код сборки:Преобразовать встроенный код сборки в C++

void ExternalFunctionCall::callFunction(ArgType resultType, void* resultBuffer) 
{ 
#if defined(_NT_) || defined(__OS2__) 

    // I386 

    // just copy the args buffer to the stack (it's already layed out correctly) 
    int* begin = m_argsBegin; 
    int* ptr = m_argsEnd; 
    int arr[1000], i=0; 
    while (ptr > begin) { 
     int val = *(--ptr); 

     __asm push val 
    } 

    void* functionAddress = m_functionAddress; 

    // call the function & handle the return value. use __stdcall calling convention 
    switch (resultType) { 
    case voidType: 
     __asm { 
      call functionAddress 
     } 
     break; 
    case pointerType: 
    case int32Type: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      mov dword ptr [ebx],eax 
     } 
     break; 
    case floatType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp dword ptr [ebx] 
     } 
     break; 
    case doubleType: 
     __asm { 
      call functionAddress 
      mov ebx, resultBuffer 
      fstp qword ptr [ebx] 
     } 
     break; 
    } 

Я использовал стек, массив перенести это «ассемблерный толчок VAL», но не работает. Хотя, он не бросает ошибки компиляции, но логика не сработала.

Итак, я хочу спросить: что я могу использовать на C++ вместо «__asm ​​push val». Любая помощь будет оценена.

+1

Несомненно, это не единственная инструкция по сборке в программе? Как вы используете толкаемое значение? На данный момент информации недостаточно, чтобы помочь вам. –

+1

Вам нужно будет показать больше кода, чтобы мы могли знать, что делается со значением, наложенным на стек. –

+2

Стандарт C++ не включает встроенный язык ассемблера или любые операции для непосредственного изменения стека процессора .... У вас больше шансов получить полезный совет, если вы объясните, что делает ваша функция с стеком впоследствии? Если он готовит значения для вызова функции или чего-то еще, может быть другой способ предоставить аргументы. Вероятно, это очень специфично для вашей ОС и/или компилятора, о чем вы не указали. –

ответ

0

Есть несколько вещей, которые вам нужно решить. (Я искал ваш код по другому вопросу). Как я понял, этот код является оболочкой для вызова довольно абстрактной функции, расположенной по указанному адресу, которая ожидает определенный объем данных в стеке и может возвращать разные вещи, основанные на ArgType.

Если вы хотите обернуть его с помощью простого C, вы должны определить несколько прототипов функций (на основе возвращаемого значения), чтобы использовать их на вашем коммутаторе, но тогда вам нужно решить еще одну проблему, которая более сложна.

Проблема с переносом таких вещей в C заключается в том, что вы не знаете заранее аргументов (размер данных), которые вы должны вставить в стек, так что у вас возникнут проблемы с прототипом.

Предположим, что func (char c) определенно будет вставлять в стек 1 байт (но также не всегда правильно из-за выравнивания данных) .. в вашем случае вам нужно подумать о решении, которое будет иметь набор параметров с равным размером к размеру данных, которые должны быть в стеке. Что на первый взгляд не то, что вы можете сделать сразу.

UPD. вы можете сделать это с помощью func (char [] param); но он также имеет проблемы, которые были объяснены в ответе выше.

+0

Вы знаете, это не так уж плохо, но последний абзац, особенно «вы должны думать о решении», это разваливает его для меня. ОП не просили бы о помощи, если бы они могли что-то придумать. Очевидно, они очень старались решить эту проблему самостоятельно. – StoryTeller

+0

Извините, что разочаровал вас .. Может быть, «вам нужно думать» действительно было немного сложно, но я извиняюсь, что я не носитель английского языка. Я имею в виду, что я действительно не знаю точного решения для последнего шага, и то, что я написал, было более изящным, а не готовым ответом. Другое дело, что из того, что я прочитал в вопросе ОП (фактически оба из них), я считаю, что «очевидно, очень трудно решить» применимо. – evilruff

13

Проблема не разрешима вообще; это потому, что комментарий,

// call the function & handle the return value. use __stdcall calling convention 

указывает на зависимость от 32bit вызова конвенций.

В 32-битной x86, stdcall означает, что все аргументы передаются через стек в обратном порядке (т.е. последний аргумент выталкивается первым. То есть, если arg[0] находится в addr тогда arg[1], независимо от того, это тип, является на addr + sizeof(arg[0])). Вот причина, почему следующий код в вашем примере:

// just copy the args buffer to the stack (it's already layed out correctly) 
int* begin = m_argsBegin; 
int* ptr = m_argsEnd; 
int arr[1000], i=0; 
while (ptr > begin) { 
    int val = *(--ptr); 

    __asm push val 
} 

на самом деле может работать - потому что это просто не имеет значения, что именно там, какой тип аргументы; все, что имеет значение, состоит в том, что каждый из них находится в известном месте памяти и известен как последовательный в памяти. Если вы знаете, что аргумент N находится на addr, то вы можете узнать аргумент N+1 на addr + sizeof(arg[N]).

Вот что говорится в комментариях, «это уже заложен правильно» - к сожалению, это не верно в 64-разрядном режиме. Поэтому код не может быть «портирован»; для порта нет эквивалента.

Вызывающие соглашения, которые хотя бы частично регистрируются на основе - как Win64 на x64 (64 бит x86), ведут себя по-разному.Для них это зависит от того, какие типы аргументов принимают вызываемые функции (вы можете в Windows передать четыре аргумента целочисленного типа в регистры общего назначения плюс некоторые аргументы типа float в регистрах XMM). Таким образом, вам нужно знать о сигнатуре (прототипе) функции, которую вы вызываете, а не просто «она принимает N аргументов», чтобы иметь возможность правильно маршевать args из обертки типа «anycall», как указано выше. В 64-битном режиме для каждой функции, которую вы хотите вызвать через свою обертку, вам нужно знать не только количество аргументов в целом, но также и то, сколько из них находится в реестре общего назначения, сколько в XMM рег, и как многие в стеке.

Функция «вызов функции func через указатель и копирование возвращаемого значения в известное место» переносима и может быть выражена в виде простого C/C++. Но та часть, которая получает аргументов для этого, как указаны выше, не не порт в любом прямом пути между 32-битной stdcall и любым 64-битной x86 соглашением о вызовах, я знаю (ни Win64/x64, ни ООН * X x86_64 конвенция позволяет для прогнозирования как местоположений, так и общего использования памяти стека для всех аргументов для функции, заданной только количеством и типами аргументов, но не их порядком).

Что именно вам нужно сделать, зависит гораздо больше на позвонивших/пользователях выше class ExternalFunctionCall чем на маленьком образце встроенного ассемблера вы показали. Особенно необходимо знать, как инициализируются члены m_argsBegin и m_argsEnd и где. Можете ли вы предоставить несколько подробностей о том, как выглядит класс (все переменные/функции-члены), а также примеры его фактического использования?

+0

Спасибо, Фрэнк, я хотел бы попросить еще одну вещь. Разве мы не можем отделить этот код asm в asm/s файле? Отдельный файл asm может компилироваться на x64 через MASM64.exe. Если возможно, скажите, пожалуйста, как мы можем это сделать? Мы перенесли весь код asm в cpp, остался только «__asm ​​push val».Вы можете увидеть код полной функции выше. – vsoni

+0

@ user2118116: как уже было сказано, есть _more_, чем просто «заменить« __asm ​​push val »на 64-биты». Это «больше» находится вне функции_ - это _both_ во всем классе, а также, и именно здесь самая большая часть работы - это те места, где создаются/используются экземпляры этого класса. Извините, здесь нет простого выхода. Ваш вопрос о портировании этого на 64-битный бит напоминает «мой x86-код использует' lcall' в встроенной сборке, и мне нужно поместить его в ARM, поэтому я хочу знать инструкцию ARM, которая делает «lcall». –

+0

@FrankH. Полный ACK. Я предложил ОП в дубликате этого: 「Лучшее, что вы можете сделать, это переписать всю функцию с помощью [libffi] (http://sourceware.org/libffi/) или [dyncall] (http: // dyncall. org /). 」 – mirabilos

0

Я понимаю, что это несколько старый вопрос, но я просто наткнулся на: xbyak.

Возможно, вы что-то ищете?

+0

Hi Nix, Я хочу заменить код asm из этого контекста: int * begin = m_argsBegin; int * ptr = m_argsEnd; int arr [1000], i = 0; while (ptr> begin) { int val = * (- ptr); __asm ​​push val } В принципе, я хочу заменить утверждение «__asm ​​push val» кодом Cpp. Спасибо – vsoni

+0

Что такое m_argsBegin и m_argsEnd? –

+0

@ Nix- Оба они являются int * Спасибо – vsoni

Смежные вопросы