BCB使用VC的DLL,implib的-f参数是什么意思?

ooolinux 2020-11-09 10:29:06
Borland Implib Version 3.0.22 Copyright (c) 1991, 2000 Inprise Corporation

Syntax: IMPLIB [options] libname[.lib] [@respfile | srcname] [srcname ...]
Options:
-a Add '_' alias for MS flavor cdecl functions
-c Case sensitive symbols
-f Force imports by name (with hints)
-w No Warnings

Respfile may contain a list of source files to process.
Wildcards are ok for .DLL and .DEF file names.

对于VC的DLL,如果导出函数用默认的__cdecl调用方式,使用 implib -af 参数吗?
如果导出函数用__stdcall调用方式,implib要用什么参数?
如何从导出的函数名比如 _addfun@4 之类判断导出函数是用哪种调用方式?
...全文
698 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
ooolinux 2020-11-17
  • 打赏
  • 举报
回复
引用 24 楼 早打大打打核战争的回复:
[quote=引用 23 楼 ooolinux 的回复:][quote=引用 22 楼 早打大打打核战争 的回复:]因为一个DLL和使用它的exe/dll的相对位置关系是不确定的,只有在运行时加载之后才能确定下来

最终生成的exe里没有符号名,为什么import lookup table里又有符号呢?[/quote]

import lookup table里的符号是DLL的导出符号,不是源程序中引用的符号,这两者有关系,但不是同一个符号,源程序中引用的符号,比如fadd,在链接后已经不存在了(除非有调试信息),只有对某个地址的调用,但是因为这个地址在DLL中,链接时是无法确定其位置的,所以需要在PE文件中保存mport lookup table和import address table,由加载程序在加载exe/dll时设置,也就是所谓“动态链接”了
[/quote] 大概明白一些了
  • 打赏
  • 举报
回复
引用 23 楼 ooolinux 的回复:
[quote=引用 22 楼 早打大打打核战争 的回复:]因为一个DLL和使用它的exe/dll的相对位置关系是不确定的,只有在运行时加载之后才能确定下来

最终生成的exe里没有符号名,为什么import lookup table里又有符号呢?[/quote]

import lookup table里的符号是DLL的导出符号,不是源程序中引用的符号,这两者有关系,但不是同一个符号,源程序中引用的符号,比如fadd,在链接后已经不存在了(除非有调试信息),只有对某个地址的调用,但是因为这个地址在DLL中,链接时是无法确定其位置的,所以需要在PE文件中保存mport lookup table和import address table,由加载程序在加载exe/dll时设置,也就是所谓“动态链接”了
  • 打赏
  • 举报
回复
因为一个DLL和使用它的exe/dll的相对位置关系是不确定的,只有在运行时加载之后才能确定下来
ooolinux 2020-11-16
  • 打赏
  • 举报
回复
引用 20 楼 早打大打打核战争 的回复:
_fadd是给链接器用的,让连接器修正调用fadd的模块中call xxxx的地址(因为这个地址在编译该模块生成obj的时候是不能确定的),在最终生成的exe/dll中已经没有这个符号(除非带调试信息编译)。
在PE格式中有import lookup table和import address table,windows加载程序在加载exe/dll时会检查import lookup table的每个符号,获取其地址,然后填入import address table,所以调用dll中的函数实际只是调用了import address table中的一个入口,调用时已不需要符号名

有点复杂。。
就是说编译阶段调用函数的地址是不确定的,连接器链接以后地址就确定了?如果地址确定了,PE为什么还需要import lookup table和import address table?是进程使用独立虚拟内存地址空间需要内存映射的原因吗?
  • 打赏
  • 举报
回复
_fadd是给链接器用的,让连接器修正调用fadd的模块中call xxxx的地址(因为这个地址在编译该模块生成obj的时候是不能确定的),在最终生成的exe/dll中已经没有这个符号(除非带调试信息编译)。
在PE格式中有import lookup table和import address table,windows加载程序在加载exe/dll时会检查import lookup table的每个符号,获取其地址,然后填入import address table,所以调用dll中的函数实际只是调用了import address table中的一个入口,调用时已不需要符号名
ooolinux 2020-11-16
  • 打赏
  • 举报
回复
引用 22 楼 早打大打打核战争 的回复:
因为一个DLL和使用它的exe/dll的相对位置关系是不确定的,只有在运行时加载之后才能确定下来

最终生成的exe里没有符号名,为什么import lookup table里又有符号呢?
  • 打赏
  • 举报
回复
那是因为CB编译器对cdecl调用约定的函数默认生成了前导下划线(32位编译器对除了非cdecl调用约定的函数外的所有符号默认生成前导下划线),所以你在源程序中引用的fadd,在obj中生成的符号名实际是_fadd,如果implib从dll生成的lib中的fadd没有前导下划线,链接时就会找不到符号
ooolinux 2020-11-15
  • 打赏
  • 举报
回复
引用 18 楼 早打大打打核战争 的回复:
那是因为CB编译器对cdecl调用约定的函数默认生成了前导下划线(32位编译器对除了非cdecl调用约定的函数外的所有符号默认生成前导下划线),所以你在源程序中引用的fadd,在obj中生成的符号名实际是_fadd,如果implib从dll生成的lib中的fadd没有前导下划线,链接时就会找不到符号

vcdll.lib里的连接符号是_fadd,为什么最终能调用到vcdll.dll里的fadd导出函数?名字都不一样。
  • 打赏
  • 举报
回复
c++方式导出函数可以逆推它的调用约定、参数个数和类型,c方式导出函数则没有这些信息
gcc、clang、cb中有工具c++filt.exe可以用于还原可读符号名,vc++中的类似工具是undname.exe
  • 打赏
  • 举报
回复
_test@@ZAXXZ 这种是c++方式导出,不是c方式导出,在c++中称之为name mangling,是为了保证连接时符号名唯一而使用的一种方法,在源程序中并不直接使用_test@@ZAXXZ这样的名字,而是使用test,由编译器维护符号名和二进制格式(lib、dll等)中的导出名之间的对应关系,比如两个重载函数名在源程序中是一样的,但在lib、dll中的导出名则不一样
ooolinux 2020-11-14
  • 打赏
  • 举报
回复
引用 16 楼 早打大打打核战争的回复:
C方式导出符号名唯一的修饰就是加不加前导下划线
帮我看看11楼的问题
  • 打赏
  • 举报
回复
C方式导出符号名唯一的修饰就是加不加前导下划线

ooolinux 2020-11-14
  • 打赏
  • 举报
回复
引用 14 楼 早打大打打核战争 的回复:
c++方式导出函数可以逆推它的调用约定、参数个数和类型,c方式导出函数则没有这些信息
gcc、clang、cb中有工具c++filt.exe可以用于还原可读符号名,vc++中的类似工具是undname.exe

C方式导出函数应该也有一定的名字修饰或者不修饰,但是没有包含足够的信息来逆推它的调用约定、参数个数和类型。
ooolinux 2020-11-13
  • 打赏
  • 举报
回复
引用 4 楼 早打大打打核战争的回复:
如果DLL中的函数名是C方式导出,是看不出来调用约定、几个参数的
那implib用哪个参数只能靠猜?
  • 打赏
  • 举报
回复
如果DLL中的函数名是C方式导出,是看不出来调用约定、几个参数的
ooolinux 2020-11-13
  • 打赏
  • 举报
回复
试了_stdcall和_cdecl,看来这个说的没错了: —————————— c++builder和vc描述符定义的区别 在c++builder中 __cdecl的函数输出前会带:"_" __stdcall无特征,只输出函数名 __fastcall函数输出前带:"@" 都无"@nn"后缀格式! 在vc中 __cdecl无特征,只输出函数名 __stdcall的函数输出前会带:"_"后缀带:"@nn" __fastcall函数输出前带:"@"后缀带:"@nn
ooolinux 2020-11-13
  • 打赏
  • 举报
回复
我又把DLL两个导出函数改为用_cdecl调用约定试验了一下, tdump -ea vcdll.dll ****************************************************************************** Exports from vcdll.dll 2 exported name(s), 2 export addresse(s). Ordinal base is 1. Sorted by Name: RVA Ord. Hint Name -------- ---- ---- ---- 00001020 1 0000 fadd 00001010 2 0001 iadd ****************************************************************************** 发现implib必须使用-a或者-aa参数。如果implib无参数,则C++Builder编译时出现链接错误: [ilink32 Error] Error: Unresolved external '_iadd' referenced from E:\C\USING VC DLL 2\WIN32\DEBUG\UNIT1.OBJ [ilink32 Error] Error: Unresolved external '_fadd' referenced from E:\C\USING VC DLL 2\WIN32\DEBUG\UNIT1.OBJ ****************************************************************************** (1)是不是C++Builder对于iadd(1,5)函数调用,编译成目标代码变成_iadd(1,5)调用?然而vcdll.dll的_cdecl调用约定的导出函数名不加修饰依然为iadd,因为implib无参数,vcdll.lib里的名字与DLL里的名字不变也是iadd,(2)所以链接时找不到_iadd函数符号链接出错?(3)如果implib使用-a参数,vcdll.lib里的名字对DLL里的名字加一个_前缀变为_iadd,所以链接正常?这样理解对不对?感觉有点反了,(4)vcdll.lib里的_iadd名字最终怎么调用到vcdll.dll里的iadd函数的?问题有点多~
abc_ustone 2020-11-13
  • 打赏
  • 举报
回复
ooolinux 2020-11-13
  • 打赏
  • 举报
回复
晚上重新把VC2010装上,写了个控制台DLL试验了一下,导出函数用_stdcall调用约定,查看导出函数名变为: tdump -ea vcdll.dll ****************************************************************************** Exports from vcdll.dll 2 exported name(s), 2 export addresse(s). Ordinal base is 1. Sorted by Name: RVA Ord. Hint Name -------- ---- ---- ---- 00001020 1 0000 _fadd@16 00001010 2 0001 _iadd@8 ****************************************************************************** 然后发现高版本C++Builder的implib参数多了两个: Embarcadero Implib Version 3.4.0 Copyright (c) 1991-2016 Embarcadero Technologies, Inc. Syntax: IMPLIB [options] libname[.lib] [@respfile | srcname] [srcname ...] Options: -a Add '_' alias for MS flavor cdecl functions -aa Force the alias even if the function already starts with '_' -c Case sensitive symbols -f Force imports by name (with hints) -s Don't convert stdcall names from Microsoft mangling -w No Warnings Respfile may contain a list of source files to process. Wildcards are ok for .DLL and .DEF file names. ****************************************************************************** 实际上implib很宽容,除了 implib -s vcdll.lib vcdll.dll 用-s参数生成的vcdll.lib不行以外,用无参数、-a参数或者-aa参数生成的vcdll.lib加入C++Builder工程编译,都能正确调用vcdll.dll中导出的C函数。
ooolinux 2020-11-13
  • 打赏
  • 举报
回复
引用 4 楼 早打大打打核战争 的回复:
如果DLL中的函数名是C方式导出,是看不出来调用约定、几个参数的

百度了一下:
调用约定
调用约定(Calling convention)决定以下内容:函数参数的压栈顺序,由调用者还是被调用者把参数弹出栈,以及产生函数修饰名的方法。VC支持以下调用约定:
_cdecl
按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于"C"函数或者变量,修饰名是在函数名前加下划线。对于"C++"函数,有所不同。
如函数void test(void)的修饰名是_test;对于不属于一个类的"C++"全局函数,修饰名是_test@@ZAXXZ(怎么感觉像乱码??)。
这是MFC缺省调用约定。由于是调用者负责把参数弹出栈,所以可以给函数定义个数不定的参数,如printf函数。
_stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于"C"函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号"@"及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于"C++"函数,则有所不同。所有的Win32 API函数都遵循该约定。
——————
如果这个资料是对的,导出的C函数名跟调用约定还是有一定关系的?
加载更多回复(5)

13,825

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧