Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Assembler > компиляция одного исходника под 32 и 64


Автор: kin01 17.09.18, 15:57
Портировал на ассемблер один проект из Delphi (1500 строк), компилирую его из Visual Studio с помощью masm. В среде выбрал соотв. опции (Build Dependencies -> masm) и в опциях проекта Microsoft Macro Assembler. Под 32 работает. Теперь хочу портировать код под 64, да так чтобы не писать новый код со всеми особенностями 64 разработки, а прям в этом же файле с условными компиляциями и макроопределениями, к примеру

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    IFDEF RAX
      _WIN64 equ TRUE
    ELSE
      _WIN32 equ TRUE
    ENDIF
     
    IFDEF _WIN32
        .386
        .model flat, stdcall
        option casemap :none   ; case sensitive
     
    include c:\masm32\include\windows.inc
    include c:\masm32\include\kernel32.inc
     
    my_eax equ eax
     
    ELSE
     
    include c:\masm64\include64\win64.inc
    include c:\masm64\include64\kernel32.inc
     
    my_eax equ rax
     
    ENDIF


1. Если переопределить все регистры.
2. В участках кода где вызываются функции с помощью условных компиляций выделить место в стеке
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    sub rsp, 32
и соотв. по завершению обратно вернуть.
3. Заменить структуры и типы на 64 вариант, где это требуется.
4. Выровнять границу в нужных местах.
и т.д.
Насколько адекватна затея всё это городить в одном файле исходного текста? Дело в том что по определённым причинам нужно именно в одном файле.
Какие могут быть ещё нюансы, чтобы грамотно всё сделать? Ещё такой вопрос, взял отсюда комплект под 64 и сгенерил либы инклуды Library update May 2018 может это всё не нужно раз из студии компилирую, как через неё можно сгенерировать инклуды и т.д.

Спасибо!

Автор: Jin X 17.09.18, 16:24
kin01, тут зависит от того, что в исходнике и как он написан.
Теоретически, это возможно (правда, некоторые возможности будут утеряны, например, можно было бы оптимизировать код с учётом наличия r8-r15 и SSE2), а практически все может оказаться сложнее, чем кажется (тем более, если прога длинная).
Нюансы:
• Могут поехать размеры данных из-за изменения размеров операндов. К примеру, есть dd и dword ptr. Нужно ли их приводить к dq и qword ptr? Далеко не всегда, зависит от конкретном ситуации. К примеру, в виндовых структурах есть dw-поле, а есть lpsz. Поле dw Всегда будет 32-битным, а lpsz – зависит от разрядности. При этом, если мы записываем что-то с помощью mov dwSomeData,eax, то mov dwSomeData,rax вызовет ошибку. Но тут можно играться с названиями универсальных регистров. Там, где нужно всегда использовать eax, указывать явно: eax. А где операнд зависит от разрядности – my_eax. Аналогично с dd, dword ptr.
• То же самое, но с непосредственными значениями. Что значит 0FFFF0000h? Что у нас только 16 младших разрядов должны быть обнулены или что старшие 32 (в 64 битах) тоже?
• Как сделаны вызовы и объявления функций? Если это просто метки и push+call, то будет геморно (потому как фреймы устроены по-разному, да и параметры передаются по-разному). Тут sub rsp,32 может оказаться недостаточно, т.к. нужно выравнивать стек до 8 байт. Но если через invoke/proc, тогда всё должно работать само собой. Но! Вызов invoke SomeFunc, eax, ecx сработает в Win32, а вот в Win64 (invoke SomeFunc, rax, rcx) – не факт, т.к. invoke скорее всего заносит в регистры-параметры данные тупо последовательно (у меня именно такой вариант, по приведённой вами ссылке – не знаю, может, там исправлено), т.е. это развернётся в:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    mov rcx,rax
    mov rdx,rcx  ; опа... а rcx у нас уже перезаписан!
    call [Function]
• Если есть push/pop, которые окружают вызов функции, они могут нарушить выравнивание стека перед вызовом (т.к. это не учитывается при создании фрейма).
• Если вдруг в коде используются инструкции, которые в 64-х битах недоступны (скажем, das, например, для перевода в 16-ричное число), то этот кусок кода придётся переписывать.
• Ну и пр., о чём я ещё не вспомнил.
Пробуйте. Всё реально :)

Добавлено
Цитата kin01 @
Ещё такой вопрос, взял отсюда комплект под 64 и сгенерил либы инклуды Library update May 2018 может это всё не нужно раз из студии компилирую, как через неё можно сгенерировать инклуды и т.д.
Думаю, что нужно, т.к. когда я делал подобное, я не нашёл у себя файла, к примеру, kernel32.inc и пр., и брал из masm32 и стороннего комплекта под ml64.

Добавлено
По трудоёмкости сложно сказать, всё сильно зависит от кода. Может, он там так написан, что проще сделать
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    if _WIN32
      ; весь код под 32
    elseif _WIN64
      ; весь код под 64
    endif
:)

Добавлено
Посмотрел вашу ссылку. А что там, собственно, ценного? Это чисто библиотека m64lib, там нет inc'ов вообще. Вам надо вот это: http://xk8.ru/ml64

Автор: kin01 17.09.18, 18:18
не то скопировал. ниже по ссылке есть makeall.bat который всё делает.
Current build of the 64 bit MASM SDK

Добавлено
но по сути нужны только *.inc т.к. в студии всё есть.

Автор: kin01 07.02.19, 19:11
Оказалось достаточно легко написать исходный код для двух платформ. Помимо переопределения регистров:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        rax equ eax
        rcx equ ecx
        rdx equ edx
        rbx equ ebx
        rbp equ ebp
        rsp equ esp
        rsi equ esi
        rdi equ edi
        r9  equ ebx
        r8d equ ebx
        r8b equ bl
        r8  equ ebx


переопределил типы, структуры
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    Pointer         typedef PVOID;
    NativeInt       typedef SIZE_T;
    UIntPtr         typedef SIZE_T
    HINST           typedef SIZE_T;
    Integer         typedef DWORD;
    TMemoryModule   typedef Pointer;
    Cardinal        typedef Integer;
    PUINT16         typedef PTR UINT16;
    PUINT_PTR       typedef PTR UINT_PTR
    PPointer        typedef PTR Pointer
    PWord           typedef PTR Word
    PAnsiChar       typedef Pointer
    PByte           typedef Pointer


и использовал несколько макросов
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    ;--------------------------------------------
    ;               CROSS
    ;--------------------------------------------
     
      pmx macro arg1, arg2
        ifdef win32
            push arg2
        else
            mov arg1, arg2
        endif
      endm
      
      plx macro arg1, arg2
        ifdef win32
            lea arg1, arg2
            push arg1
        else
            lea arg1, arg2
        endif
      endm
     
      CROSS_MOVSXD macro arg1, arg2
        IFDEF win64
            movsxd arg1, arg2
        ELSE
            mov arg1, arg2
        ENDIF
      ENDM


получилось нечто такого
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
        pmx rdx, rdx
        mov rax, codebase
        mov rcx, section
        mov ecx, (IMAGE_SECTION_HEADER ptr [rcx]).VirtualAddress
        add rcx, rax
        pmx rcx, rcx
        call VirtualAlloc


почти нет условных компиляций в коде. только в препроцессоре.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)