Visual c++ 使用cl.exe将asm文件编译为dll
给定:带有入口点的程序cVisual c++ 使用cl.exe将asm文件编译为dll,visual-c++,assembly,masm,Visual C++,Assembly,Masm,给定:带有入口点的程序cprog 我通常这样做 cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib 或 在这两种情况下,生成的prog.dll都可以正常工作 现在,我执行以下操作以获取asm文件而不是obj文件: cl.exe /c /MD /Fa"prog" 到目前为止,这也“有效”。但是我不知道如何制作这个文件的dll 尝试: ml.exe /c /Cx /coff prog.asm cl.exe /MD /LD /
prog
我通常这样做
cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib
或
在这两种情况下,生成的prog.dll都可以正常工作
现在,我执行以下操作以获取asm文件而不是obj文件:
cl.exe /c /MD /Fa"prog"
到目前为止,这也“有效”。但是我不知道如何制作这个文件的dll
尝试:
ml.exe /c /Cx /coff prog.asm
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib
结果:prog.dll没有入口点prog
再次尝试:
ml.exe /c /Cx /coff prog.asm
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link /entry:prog ext.lib
结果:编译器警告错误的入口点_prog不是具有12字节参数的stdcall,以及编译器关于未解析符号_memcpy的错误
问题:有没有办法将cl.exe通过/Fa生成的asm文件编译成dll(如果不可能使用ml.exe,最好通过cl.exe)
有没有办法将cl.exe通过/Fa
生成的asm文件编译成dll(如果不可能使用ml.exe,最好通过cl.exe)
否:
如果您绝对必须这样做,那么您必须在通过MASM运行它之前获取MSVC生成的ASM列表文件并手动清理它。您可以通过关闭整个程序优化、关闭异常处理、关闭安全检查/cookie以及向链接器指示映像不包含安全的SEH处理程序来简化此清理任务。请注意,其中一些可能会破坏或更改代码的行为!您还需要为从运行库调用的函数添加
EXTERN
定义。虽然Microsoft C编译器生成的ASM源代码可能不是返回MASM的最佳输入,但这并不意味着它不起作用,至少在某些情况下是如此(只是可能不太复杂)。如果你看一看C编译器生成的ASM文件,你会发现微软的某个人费了很大的劲插入了各种“hacky”包括、指令、手动段定义和其他MASM细节,使源文件至少有很小的机会被反馈到MASM中并获得汇编结果。只要您将期望值设置得较低,我想,如果您的命令行选项正确,那么一个简单的C源文件,转换为ASM,然后反馈到MASM应该可以工作
您需要记住的一个警告是,如果您像现在这样使用CRT(即使用memcmp),您将希望允许默认入口点___DllMainCRTStartup@12从相应的CRT.LIB文件中选择,而不是指定自己的文件。这允许在调用DllMain之前初始化CRT,从而防止在调用依赖于此初始化的某些CRT函数时发生崩溃。话虽如此,VisualStudio的旧版本,如7.1(2003),您可以不初始化CRT,这取决于您使用的函数,而不会有崩溃的风险。如果进程以前没有调用maincrtstartup或DllMainCRTStartup,则无论调用哪个CRT函数,较新版本的C运行时都会引发异常
出于教育目的,让我们使用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)
您可以实现entrypoint函数,如本版本的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);
}
您已经知道可以使用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());
}
编译器生成的MSVC 7.1 ASM文件如下所示,以供参考。请注意该文件如何将自身称为“列表”:
通常情况下,您无法汇编Microsoft编译器的输出并获得有效的结果。MASM不支持编译器使用的所有功能,因此程序集输出仅代表编译器创建的目标文件。@RossRidge“程序集输出仅代表编译器创建的目标文件”-这应该没有问题,因为我可以直接编译编译器创建的对象文件-我只是不知道如何编译/链接它以使其从asm文件工作。不,事实上,您能够将编译器创建的程序集文件组装到对象文件中并不一定意味着您得到了可以工作的东西。Microsoft编译器不支持您尝试执行的操作。您应该只使用编译器直接创建的对象文件。LLVM工具链支持首先创建.asm,然后组装它。甚至有一个工具和测试集现在确保这相当于直接产生输出(检查CFC),见英伟达NVCC CUDA编译器也可以编译为他们的汇编语言PTX作为中间步骤,然后继续编译,而不是给出一个
ml.exe /c /coff /Cx prog.asm
link.exe /nologo /dll /subsystem:console /entry:prog prog.obj kernel32.lib
#include <Windows.h>
int __cdecl main(void)
{
HMODULE hLib = LoadLibrary("prog.dll");
printf("LoadLibrary result: 0x%X / code=0x%X\n",hLib,GetLastError());
}
Result of memcmp: 1
LoadLibrary result: 0x10000000 / code=0x0
Result of memcmp: 1
; 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