首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用cl.exe将asm文件编译成dll

用cl.exe将asm文件编译成dll
EN

Stack Overflow用户
提问于 2016-12-06 23:52:00
回答 2查看 4.1K关注 0票数 3

给定:带有入口点prog的PROCE.c

我通常是这样

代码语言:javascript
复制
cl.exe /MD /LD /Fe"prog.dll" /Fo"prog" "prog.c" /link ext.lib

代码语言:javascript
复制
cl.exe /MD /Fo"prog.obj"
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib

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

现在,我执行了以下操作以获得一个asm文件,而不是obj文件:

代码语言:javascript
复制
cl.exe /c /MD /Fa"prog"

到目前为止,这种“效果”也很好。但是我不知道如何创建这个文件的dll。

试过:

代码语言:javascript
复制
ml.exe /c /Cx /coff prog.asm
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link ext.lib

结果: prog.dll没有入口点prog

再试:

代码语言:javascript
复制
ml.exe /c /Cx /coff prog.asm
cl.exe /MD /LD /Fe"prog.dll" "prog.obj" /link /entry:prog ext.lib

结果:编译器警告错误的入口点_prog不使用12字节参数进行std调用,以及编译器关于未解析符号_memcpy的错误。

问题:有什么方法可以将cl.exe生成的cl.exe文件编译成动态链接库(最好是通过cl.exe,如果ml.exe不可能)?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-12-07 12:59:22

有没有办法将cl.exe生成的/Fa文件编译成动态链接库(最好是通过cl.exe,如果ml.exe不可能的话)?

否:

  1. C/C++编译器(cl.exe)不能装配程序集代码输入.它只接受C或C++源代码作为输入。汇编程序是MASM (ml.exe)。
  2. 一般来说,cl.exe的程序集代码输出不能直接输入MASM。在某些情况下,它甚至不是有效的程序集代码。在其他情况下,MASM不直接支持代码中发出的指令、关键字和其他内容。如果C/C++源代码使用异常,情况就会变得特别复杂。清单文件仅用于信息目的。

我非常不清楚你为什么一开始就想这么做。如果您的源代码是C或C++,并且可以由MSVC编译和链接,那么引入转换汇编语言的附加中间步骤又有什么意义呢?只需直接使用cl.exe创建DLL即可。

如果您绝对必须这样做,您将不得不接受MSVC生成的ASM列表文件,并在通过MASM运行它之前手动清理它。您可以通过关闭整个程序优化、关闭异常处理、关闭安全检查/cookie以及向链接器指示映像不包含安全的SEH处理程序,从而简化清理任务。请注意,其中一些可能会破坏或更改代码的行为!您还需要为从运行库调用的函数添加EXTERN定义。

票数 6
EN

Stack Overflow用户

发布于 2016-12-08 08:47:45

虽然由Microsoft编译器生成的ASM源代码可能不是MASM的最佳输入,但这并不意味着它无法工作,至少在某些情况下(可能不是复杂的)。如果您查看由C编译器生成的ASM文件,您会发现Microsoft的某个人在插入各种"hacky“包含、指令、手动段定义和其他MASM细节时遇到了很大的麻烦,从而使源文件至少有很小的机会被反馈到MASM中,并获得一个组装的结果。只要你把你的期望调低,我想一个简单的C源文件,转换成ASM,然后反馈到MASM,如果你把命令行选项按顺序排列的话,应该可以工作。

您需要记住的一个警告是,如果您像您正在做的那样使用CRT (即使用memcmp),您将希望从适当的CRT .LIB文件中选择默认的入口点.LIB,而不是指定您自己的。这允许在调用DllMain之前初始化CRT,从而防止在调用依赖于此初始化的某些CRT函数时崩溃。尽管如此,Visual的旧版本,如7.1 (2003),您可以不初始化CRT,这取决于您使用的是哪些函数,而不存在崩溃的风险。如果进程以前没有调用过mainCRTStarttup或DllMainCRTStartup,则function的更新版本将抛出异常,而不管调用哪个CRT函数。

出于教育目的,让我们使用MSVC 7.1 (2003)来解决前面描述的切入点问题,我们不会担心初始化CRT,这样您就可以显式地指定您自己的入口点。我认为你击中了以下链接器警告:

代码语言:javascript
复制
warning LNK4086: entrypoint '_prog@XX' is not __stdcall with 12 bytes of arguments; image may not run

在指定自己的DLL入口点时,链接器需要一个DllMain签名(这是12个参数字节和stdcall,因此函数本身清除了参数本身);正式的情况是:

代码语言:javascript
复制
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

您可以实现entrypoint函数,如这个版本的pr.c所示:

代码语言:javascript
复制
#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环境变量,则可以使用以下命令构建上面的源代码:

代码语言:javascript
复制
cl.exe /nologo /c /MD /Fa./prog.asm prog.c
link.exe /nologo /dll /subsystem:console /entry:prog prog.obj kernel32.lib

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

代码语言:javascript
复制
ml.exe /c /coff /Cx prog.asm
link.exe /nologo /dll /subsystem:console /entry:prog prog.obj kernel32.lib

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

代码语言:javascript
复制
#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都产生了以下输出:

代码语言:javascript
复制
Result of memcmp: 1
LoadLibrary result: 0x10000000 / code=0x0
Result of memcmp: 1

下面列出编译器生成的MSVC7.1ASM文件,以供参考。请注意文件如何将自身称为“清单”:)

代码语言:javascript
复制
; 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
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41007063

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档