将 cl.exe 的 asm 文件编译为 dll
Compile asm file with cl.exe to dll
给定:prog.c 有一个入口点 prog
我通常
cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib
或
cl.exe /MD /Fo"prog.obj"
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib
在这两种情况下,结果 prog.dll 工作正常。
现在我执行了以下操作来获取 asm 文件而不是 obj 文件:
cl.exe /c /MD /Fa"prog"
这 "works" 也是如此。但是我不知道如何制作这个文件的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 字节参数的标准调用的编译器警告和关于未解析符号 _memcpy 的编译器错误。
问题: 有什么方法可以将cl.exe由/Fa生成的asm文件编译成一个dll(如果没有的话最好通过cl.exe可能 ml.exe)?
Is there any way to compile the asm file which cl.exe generates by /Fa
to a dll (preferably via cl.exe, if not possible with ml.exe)?
否:
- C/C++ 编译器 (cl.exe) 无法 assemble 汇编代码输入。它只需要 C 或 C++ 源代码作为输入。 assembler 是 MASM (ml.exe).
- cl.exe 的汇编代码输出通常不能直接输入 MASM。在某些情况下,它甚至不是有效的汇编代码。在其他情况下,MASM 不直接支持的代码中有指令、关键字和其他内容。如果 C/C++ 源代码使用异常,事情就会变得特别棘手。列表文件仅供参考之用。
我很不清楚你一开始为什么想要这样做。如果您的源代码是 C 或 C++,并且可以通过 MSVC 编译和链接,那么引入将它与汇编语言相互转换的额外中间步骤有什么意义呢?直接用cl.exe做个DLL就可以了
如果您绝对必须这样做,您将必须使用 MSVC 生成的 ASM 列表文件并在通过 MASM 运行 之前手动清理它。您可以通过关闭整个程序优化、关闭异常处理、关闭安全性 checks/cookies 并向链接器指示图像 不 来简化此清理任务包含安全的 SEH 处理程序。请注意,其中一些可能会破坏或更改代码的行为!您还需要为从运行时库调用的函数添加 EXTERN
定义。
虽然 Microsoft C 编译器生成的 ASM 源代码可能不是返回 MASM 的最佳输入,但这并不意味着它不会工作,至少在某些情况下(只是可能不复杂)。如果您查看由 C 编译器生成的 ASM 文件,您会发现 Microsoft 的某个人费尽心思插入各种 "hacky" 包含、指令、手动段定义和其他 MASM 细节来提供源文件至少有很小的机会被反馈到 MASM 并获得组装结果。只要您的期望值不高,我猜一个简单的 C 源文件,转换为 ASM 然后反馈回 MASM 如果您按顺序获得命令行选项,应该可以工作。
您需要记住的一个警告是,如果您像现在这样使用 CRT(即使用 memcmp),您需要允许默认入口点 ___DllMainCRTStartup@12从适当的 CRT .LIB 文件中选择,而不是指定您自己的文件。这允许在调用 DllMain 之前初始化 CRT,从而防止在调用依赖于此初始化的某些 CRT 函数时发生崩溃。话虽如此,Visual Studio 的旧版本,例如 7.1 (2003),您可以不初始化 CRT,具体取决于您使用的功能而不会出现崩溃。如果进程之前没有调用 mainCRTStarttup 或 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)
您可以实现此版本 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" :)
; 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
给定:prog.c 有一个入口点 prog
我通常
cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib
或
cl.exe /MD /Fo"prog.obj"
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib
在这两种情况下,结果 prog.dll 工作正常。
现在我执行了以下操作来获取 asm 文件而不是 obj 文件:
cl.exe /c /MD /Fa"prog"
这 "works" 也是如此。但是我不知道如何制作这个文件的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 字节参数的标准调用的编译器警告和关于未解析符号 _memcpy 的编译器错误。
问题: 有什么方法可以将cl.exe由/Fa生成的asm文件编译成一个dll(如果没有的话最好通过cl.exe可能 ml.exe)?
Is there any way to compile the asm file which cl.exe generates by
/Fa
to a dll (preferably via cl.exe, if not possible with ml.exe)?
否:
- C/C++ 编译器 (cl.exe) 无法 assemble 汇编代码输入。它只需要 C 或 C++ 源代码作为输入。 assembler 是 MASM (ml.exe).
- cl.exe 的汇编代码输出通常不能直接输入 MASM。在某些情况下,它甚至不是有效的汇编代码。在其他情况下,MASM 不直接支持的代码中有指令、关键字和其他内容。如果 C/C++ 源代码使用异常,事情就会变得特别棘手。列表文件仅供参考之用。
我很不清楚你一开始为什么想要这样做。如果您的源代码是 C 或 C++,并且可以通过 MSVC 编译和链接,那么引入将它与汇编语言相互转换的额外中间步骤有什么意义呢?直接用cl.exe做个DLL就可以了
如果您绝对必须这样做,您将必须使用 MSVC 生成的 ASM 列表文件并在通过 MASM 运行 之前手动清理它。您可以通过关闭整个程序优化、关闭异常处理、关闭安全性 checks/cookies 并向链接器指示图像 不 来简化此清理任务包含安全的 SEH 处理程序。请注意,其中一些可能会破坏或更改代码的行为!您还需要为从运行时库调用的函数添加 EXTERN
定义。
虽然 Microsoft C 编译器生成的 ASM 源代码可能不是返回 MASM 的最佳输入,但这并不意味着它不会工作,至少在某些情况下(只是可能不复杂)。如果您查看由 C 编译器生成的 ASM 文件,您会发现 Microsoft 的某个人费尽心思插入各种 "hacky" 包含、指令、手动段定义和其他 MASM 细节来提供源文件至少有很小的机会被反馈到 MASM 并获得组装结果。只要您的期望值不高,我猜一个简单的 C 源文件,转换为 ASM 然后反馈回 MASM 如果您按顺序获得命令行选项,应该可以工作。
您需要记住的一个警告是,如果您像现在这样使用 CRT(即使用 memcmp),您需要允许默认入口点 ___DllMainCRTStartup@12从适当的 CRT .LIB 文件中选择,而不是指定您自己的文件。这允许在调用 DllMain 之前初始化 CRT,从而防止在调用依赖于此初始化的某些 CRT 函数时发生崩溃。话虽如此,Visual Studio 的旧版本,例如 7.1 (2003),您可以不初始化 CRT,具体取决于您使用的功能而不会出现崩溃。如果进程之前没有调用 mainCRTStarttup 或 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)
您可以实现此版本 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" :)
; 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