用cl.exe编译asm文件到dll

时间:2016-12-06 23:52:00

标签: visual-c++ assembly masm

给定:带有入口点>>> meanI = np.sum(I) / float(I.size) # Exactly the same as np.mean(I) or I.mean() >>> meanInew = np.sum(out) / float(out.size) >>> np.isclose(meanI, meanInew) # True

的prog.c

我通常做

prog

cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib

在这两种情况下,生成的prog.dll都能正常工作。

现在我执行了以下操作来获取asm文件而不是obj文件:

cl.exe /MD /Fo"prog.obj"
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib

这"工作"到目前为止。但我无法弄清楚如何制作这个文件的dll。

尝试:

cl.exe /c /MD /Fa"prog"

结果:prog.dll没有入口点ml.exe /c /Cx /coff prog.asm cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib

再次尝试:

prog

结果:编译器警告错误的入口点_prog不是stdcall,带有12个字节的参数,编译器错误有关未解析的符号_memcpy。

问题:有没有办法将/ dev生成的/ as文件生成的asm文件编译成dll(最好是通过cl.exe,如果ml.exe不可能的话)?

2 个答案:

答案 0 :(得分:4)

  

有没有办法将EXTERN生成的cl.exe生成的asm文件编译成dll(最好是通过cl.exe,如果ml.exe不可能的话)?

没有

  1. C / C ++编译器(cl.exe)无法汇编汇编代码输入。它只需要C或C ++源代码作为输入。汇编程序是MASM(ml.exe)。
  2. 通常,cl.exe的汇编代码输出不能直接送入MASM。在某些情况下,它甚至不是有效的汇编代码。在其他情况下,MASM不直接支持的代码中有指令,关键字和其他内容。如果C / C ++源代码使用异常,事情会变得特别多毛。列表文件仅用于信息目的。
  3. 我很不清楚为什么你甚至想要首先这样做。如果您的源代码是C或C ++,并且可以由MSVC编译和链接,那么引入将其转换为汇编语言和从汇编语言转换的附加中间步骤的重点是什么?只需直接使用cl.exe制作DLL。

    如果你绝对必须这样做,你必须获取MSVC生成的ASM列表文件,并在通过MASM运行之前手动清理它。您可以通过关闭整个程序优化,关闭异常处理,关闭安全检查/ cookie以及向链接器指示图像包含安全的SEH处理程序来简化此清理任务。请注意,其中一些可能会破坏或更改代码的行为!您还需要为从运行时库调用的函数添加mkdir -p /etc/marathon/ssl cd /etc/marathon/ssl export MARATHON_SSL_KEYSTORE_PASSWORD=jks_pass keytool -keystore marathon.jks -deststorepass $MARATHON_SSL_KEYSTORE_PASSWORD -alias marathon -genkey -keyalg RSA cat << EOF > /etc/default/marathon MARATHON_SSL_KEYSTORE_PATH=/etc/marathon/ssl/marathon.jks MARATHON_SSL_KEYSTORE_PASSWORD=$MARATHON_SSL_KEYSTORE_PASSWORD EOF 定义。

答案 1 :(得分:1)

虽然Microsoft C编译器生成的ASM源可能不是MASM的最佳输入,但这并不意味着它不起作用,至少在某些情况下(可能不是复杂的)。如果你看一下C编译器生成的ASM文件,你会发现微软的人很难插入各种“hacky”包含,指令,手册段定义和其他MASM细节来至少给出源文件很少有机会被反馈到MASM并获得组装结果。只要你把你的期望设置得很低,我猜一个简单的C源文件,转换为ASM,然后反馈到MASM应该可以工作,如果你按顺序获得命令行选项。

您需要记住的一个警告是,如果您像使用CRT一样使用CRT(即使用memcmp),您将需要允许从相应的CRT中选择默认入口点___ DllMainCRTStartup @ 12。 LIB文件而不是指定您自己的文件。这允许在调用DllMain之前初始化CRT,以防止在调用依赖于此初始化的某些CRT函数时发生崩溃。有了这个说,Visual Studio的旧版本,比如7.1(2003),你可以不用初始化CRT,这取决于你使用的功能而不会有崩溃的风险。如果进程之前没有调用mainCRTStarttup或DllMainCRTStartup,则无论调用哪个CRT函数,C Runtime的较新版本都将抛出异常。

出于教育目的,让我们使用MSVC 7.1(2003)解决您在上面描述的入口点问题,我们不会担心初始化CRT,因此您可以明确指定自己的入口点。我认为您正在点击以下链接器警告:

warning LNK4086: entrypoint '_prog@XX' is not __stdcall with 12 bytes of arguments; image may not run

当指定自己的DLL入口点时,链接器需要一个DllMain签名(12个参数字节和stdcall,因此该函数会自行清除参数);官方是:

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

您可以实现此版本的prog.c中显示的入口点函数:

#include <Windows.h>
#include <stdio.h>

#pragma warning (disable:4100) //Warning Level 4: unreferenced formal parameter

int __stdcall prog(DWORD hInst, DWORD dwReason, DWORD dwReserved)
{
    printf("Result of memcmp: %d\n",memcmp("foo","bar",3));
    return(1);
}

假设您的LIB和INCLUDE环境变量已正确设置,您可以使用以下命令构建上面的源:

cl.exe /nologo /c /MD /Fa./prog.asm prog.c
link.exe /nologo /dll /subsystem:console /entry:prog prog.obj kernel32.lib

您已经知道可以使用C编译器构建原始C源代码。 关注从/ Fa选项生成的prog.asm输出文件,您可以从生成的ASM源构建DLL,如下所示:

ml.exe /c /coff /Cx prog.asm
link.exe /nologo /dll /subsystem:console /entry:prog prog.obj kernel32.lib

使用简单的控制台加载程序测试您的DLL,例如:

#include <Windows.h>
int __cdecl main(void)
{
    HMODULE hLib = LoadLibrary("prog.dll");
    printf("LoadLibrary result: 0x%X / code=0x%X\n",hLib,GetLastError());
}

在我的机器上,C和MASM生成的DLL都产生了以下输出:

Result of memcmp: 1
LoadLibrary result: 0x10000000 / code=0x0
Result of memcmp: 1

下面列出了编译器生成的生成的MSVC 7.1 ASM文件以供参考。注意文件如何将自己称为“列表”:)

; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.6030 

    TITLE   prog.c
    .386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT   SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT   ENDS
_DATA   SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA   ENDS
CONST   SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST   ENDS
_BSS    SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS    ENDS
$$SYMBOLS   SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS   ENDS
_TLS    SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS    ENDS
FLAT    GROUP _DATA, CONST, _BSS
    ASSUME  CS: FLAT, DS: FLAT, SS: FLAT
endif

INCLUDELIB MSVCRT
INCLUDELIB OLDNAMES

_DATA   SEGMENT
$SG74617 DB 'bar', 00H
$SG74618 DB 'foo', 00H
$SG74619 DB 'Result of memcmp: %d', 0aH, 00H
_DATA   ENDS
PUBLIC  _prog@12
EXTRN   __imp__printf:NEAR
EXTRN   _memcmp:NEAR
; Function compile flags: /Odt
_TEXT   SEGMENT
_hInst$ = 8                     ; size = 4
_dwReason$ = 12                     ; size = 4
_dwReserved$ = 16                   ; size = 4
_prog@12 PROC NEAR
; File prog.c
; Line 10
    push    ebp
    mov ebp, esp
; Line 11
    push    3
    push    OFFSET FLAT:$SG74617
    push    OFFSET FLAT:$SG74618
    call    _memcmp
    add esp, 12                 ; 0000000cH
    push    eax
    push    OFFSET FLAT:$SG74619
    call    DWORD PTR __imp__printf
    add esp, 8
; Line 12
    mov eax, 1
; Line 13
    pop ebp
    ret 12                  ; 0000000cH
_prog@12 ENDP
_TEXT   ENDS
END