📄 tdump.txt
字号:
the name generated is _Foo; that is, the resulting name has the same
case but is preceded with a leading underscore. The generation of the
underscore is the default behavior and is necessary when you link to
the run time libraries. There is no 'printf()' symbol in the RTL
(!),but there is a '_printf()'.
While the C calling convention implies 'Case Sensitivity' and
'Generation of Underbars', Borland/Turbo C++ provides separate
settings for the generation of underbars and the calling convention
Generation of Underbars can be controlled from the Options | Compiler|
Advanced Code Generation Dialog, or the -u option from the command
line ( -u- would turn it off, it is on by default). The 'Calling
Convention' can be modified via the Options | Compiler |
Entry/ExitCode Dialog.
If our function 'Foo' is declared with the pascal modifier, for
example:
int pascal Foo( int );
(or if the default 'Calling Convention' is set to 'PASCAL') the
resulting name will be FOO--that is, all upper-case with no
underscore. The '_fastcall' modifier is similar to 'cdecl' in regards
to Case Sensitivity but the underscore character is replaced with '@'.
Hence:
int _fastcall Foo( int );
will result in the '@Foo' symbol.
Therefore, mismatching the calling conventions might result in
'Undefined Symbols.' Watch for clues in the undefined symbol name
provided in the Linker error messages (look at the Case Sensitivity
and any leading characters) to spot cases of incorrect settings in the
'Calling Convention' and/or 'Generation of Underbars'.
NAME MANGLING:
--------------
The C++ language uses yet another naming convention as part of its
implementation of 'type safe linkage.' Imagine a function myfunc()
which take two longs [void myfunc( long, long );]. What if someone has
it incorrectly prototyped in a calling module as taking two floats,
for example void myfunc( float, float );. The results of such a call
will be unpredictable. When using the C language, the linker would
resolve such a call since the symbol the compiler uses to call the
function taking two floats will be '_myfunc()', and the name the
compiler used in the module which implements the function taking two
longs is also '_myfunc()'.
In C++, however, the name the compiler generates for a function is a
'mangled' name: it is 'encrypted' based on the parameters types the
function expects. In the scenario described in the prior paragraph, the
call to myfunc() will not be resolved since the compiler generates
different names for 'void myfunc( float, float )' and 'void myfunc(
long, long )'.
Because a C++ function's mangled real name depends on the types of its
parameters, if unsigned chars is used as a compiler option, it changes
the name of functions declared to take a char, or char *. Unsigned
chars is off by default, it is turned on under the Options |Compiler |
Code generation menu. Or by specifying the -K option with the command
line compiler. Watch out for potential 'Undefined Symbol' messages
caused by a mismatched of char vs. unsigned char.
The 'virtual mechanism' of C++ is implemented via a table commonly
referred to as the Virtual Table or the VMT (Virtual Method Table).
Various settings of the Compiler dictate whether the Table ends up in
the Default Data Segment or in a Far Segment (namely Memory
Model, '_export' and 'huge' class modifiers, Virtual Table Control
Optionsetc). To further enforce 'type- safe-linkage', the
Borland/Turbo C++ compilers include the 'distance' of the Virtual Table
as part of its 'Name-Mangling' logic. This prevents the linker from
resolving function calls which would crash at run-time because of
mismatched 'Virtual Table Control' settings. In the same token,
Borland provides the 'Object Data Calling convention' for improved
efficiency of C++ code. Once again, the 'Name-mangling' algorithm also
reflects the enabling of 'Object Data Calling'. This ensures that
function calls involving mismatched 'Object Data Calling' convention
between caller and callee will be caught at link time (instead of
resulting in erratic run-time behavior).
To illustrate the effect of 'Virtual Table Control' and 'Object
DataCalling,' let's create a simple class and look at the effects of
the various settings on the resulting names:
class Test
{
public:
virtual int Process( void );
};
int main( void )
{
Test t;
return t.Process();
}
The following table illustrates the effects of Compiler Settings on
the *actual* name generated for the member function 'int
Test::Process(void)'.
+----------------------------------------------------------+
| Object Call. | Far V. Tbl. | Huge Md. | [ REAL NAME ] |
|--------------+-------------+-----------------------------+
| No | No | No > @Test@Process$qv |
|--------------+-------------+-----------------------------+
| No | Yes | No > @Test@0Process$qv |
|--------------+-------------+-----------------------------+
| Yes | No | No > @Test@1Process$qv |
|--------------+-------------+-----------------------------+
| Yes | No | Yes > @Test@2Process$qv |
+--------------+-------------+-----------------------------+
NOTE: Using the '_export' or 'huge' keyword when defining a class
results in Far Virtual Tables for the class.
'Undefined Symbol Messages' caused by mismatching Virtual Table
Controls or Object Data Calling conventions may be hard to identify; it
is often useful to use TDUMP.EXE to find the actual names of the
unresolved symbols (however, watch out of any '0', '1' or '2' following
the '@ClassName@' portion of the real names).
LANGUAGE USED
-------------
By default assemblers (including TASM) do not modify public
names--they merely convert symbols to upper case. With TASM, the /mx
option forces the assembler to treat public symbols with case
sensitivity. Without /mx, a call to _myfunc from an assembly module
looks like _MYFUNC to the linker (this causes undefined symbol errors
when linking C and assembly).
NOTE: TASM has an extension which causes the automatic generation of
underscores. See. .MODEL <model>, Language directives in the TASM
User's Guide.
As previously mentioned in the section about 'Name Mangling,' the
C++ language uses a different naming convention than does the C
language. This can result in undefined symbols when calling C from C++
(or vice-versa). C++ modules should use the 'extern "C"' syntax when
interfacing with C modules (see the Name Mangling section of
Programmer's Guide for the proper syntax).
LINKER SETTINGS
---------------
By default, the linker treats _myfunc and _MYFUNC as different
symbols. However, you can control whether the linker pays attention to
Case Sensitivity via the Options | Linker | Settings dialog (IDE), or
the /c option with TLINK (/c: Enables Case Sensitivity [default],
/c-turns the option off).
For example, if the option is disabled, a call to _myfunc could be
resolved to _MYFUNC.
When creating a Windows application, not only can you link to 'static'
modules (.OBJs or .LIBs which are a collection of .OBJs), but you can
also link to dynamic libraries where the resolution of the call is
completed by Windows at load time. Functions residing in DLLs and
called from an .EXE are said to be imported. Functions that are coded
in an .EXE or .DLL, and are called by either Windows, .EXEs, or .DLLs
are said to be exported.
Functions are imported in two ways: by listing them in the IMPORTS
section of the .DEF file, or by linking to an import library. Functions
can be exported by two methods: by using the _export keyword in the
source code or listing the functions in the EXPORTS section of the
.DEF file.
Suppose your application calls the symbol _myfunc which is in a
DLL. The linker can treat symbols coming from an import library, or
IMPORTS section of the .DEF file with or without case sensitivity,
(determined by the setting of case sensitive exports under the Options
| Linker | Settings Dialog or /C option on the TLINK command line). If
this setting is NOT enabled, then the Linker treats symbols in import
libs or IMPORTS sections as all uppercase. It then considers upper
case symbols during the link phase. At that point it is doing normal
linking using the setting of the case sensitive link option. If we are
importing both _myfunc and _MYFUNC without the /C option, the linker
can only resolve the call to _MYFUNC.
If you are calling _myfunc (a cdecl function) and are performing a
case sensitive link, but do not have case sensitivity on
EXPORTS, _myfunc will show up as undefined.
> Imported cdecl functions and C++ names will link when /c
> and /C are both enabled, or neither are enabled.
C++ names are always generated with lowercase letters. When importing
or exporting C++ names, it's recommended that you use both the /c
and/C options.
Now let's apply the above to some common scenarios and provide
possible diagnostics and suggestions:
PROBLEM:
All the functions in a 3rd party library are undefined!
SOLUTION:
3rd party libraries must be explicitly linked in. To explicitly
link to a 3rd party library from the IDE, open a project file and
insert the .LIB file into the project file. The project file also
needs to have all of your source code files listed in it. From
the command line, insert the .LIB on your command line to TLINK.
PROBLEM:
All the functions in the RTL are undefined!
SOLUTION:
You need to link in Cx.LIB, where x is the memory model. A
feature of the IDE in Turbo C++ and Borland C++ v2.x is that if
you put a .LIB in the project file which starts out as Cx where x
is a memory model, the new library overrides the normal run time
library, and the latter will not be linked in (for example, if
you're using a library named CSERVE.LIB). Rename any such
libraries, then the normal Cx.LIB will automatically be linked
in. (Borland C++ 4.x has a dialog for specifying which Run Time
Libraries should be linked in).
PROBLEM:
When mixing C and C++ modules (.c and .cpp source) symbols are
undefined.
SOLUTION:
Because of name mangling (see above) the symbol the linker sees
being called from a C++ module will not look like the symbol in
the Cmodule. To turn name mangling off when prototyping
functions:
// SOURCE.CPP
extern "C" {
int Cfunc1( void );
int Cfunc2( int );
}
NOTE: You can also disable name-mangling for functions written in
C++ and called from C.
A C++ compile will happen if the source code has a .CPP extension, or
Options | Compiler | C++ options use C++ compiler is set to always.
PROBLEM:
randomize and other macros are coming up as undefined symbols.
SOLUTION:
Turn keywords to Borland C++. Since some macros are not ANSI
compatible, the header files will not define them if compiled
with ANSI or UNIX keywords on.
PROBLEM:
min and max are coming up undefined.
SOLUTION:
These macros are only included in a C compile, and will not be
seen by the compiler if compiling in C++. In C, you must
#include <stdlib.h> to use them.
PROBLEM:
I cannot get my assembly modules to link with my C/C++ program.
SOLUTION:
For C++, see above. Otherwise, the .ASM must be assembled with
case sensitivity on public symbols (/mx for TASM). It must also
match the C naming convention, which will have an underscore in
front of the name. So given the following code in a C module,
int myfunc( void );
you need to
call _myfunc
from the assembly module. (NOTE: TASM has extensions which will
automatically generate underscores for you). Also, make sure the
.OBJ which has the assembly code is listed in the project file,
or on the tlink line.
PROBLEM:
wsprintf is coming up undefined.
SOLUTION:
In Borland C++ 2.0, to use wsprintf when case sensitive exports
is on, you need to reverse a define in windows.h via the
following:
#ifdef wsprintf
#undef wsprintf
#define wsprintf wsprintf
extern "C" int FAR cdecl wsprintf( LPSTR, LPSTR, ... );
#endif
To call wsprintf (or any cdecl imported function ) with case
sensitive exports off, you need to match an upper case name. Thus
windows.h #defines wsprintf to be WSPRINTF. wsprintf is one of the
cdecl functions from windows, so the compiler will generate a
lower case symbol for when calling it.
PROBLEM:
FIWRQQ and FIDRQQ are undefined
SOLUTION:
These symbols are in the EMU or FP87 library. You must link it
in explicitly when using TLINK, or set the IDE to link it in under
the Options | Compiler | Advanced Code Generation Floating point
box.
PROBLEM:
Warning attempt to export non-public symbol ...
SOLUTION:
The exports section of the .DEF file has a symbol which does not
match one the compiler generated in the source code. This happens
if:
o The source was compile in C++ (the symbol name is mangled).
Resolve by exporting with the _export keyword, compiling in C,
or by declaring the function as extern "C".
o Case sensitive exports is ON, you are exporting a PASCAL
function, and exporting it like: WndProc. Resolve by
exporting as WNDPROC or by turning case sensitive exports off.
o You are exporting a cdecl function. If declared as
int myfunc( void );
export as _myfunc and turn case sensitive exports on (or
just use the _export keyword).
NOTE: When using the '_export' keyword, it must be used in
the prototype of the function. For example:
int FAR _export myfunc( int );
PROBLEM:
C++ and DLL linking problems.
SOLUTION:
Classes declared in the DLL need to be declared as the following:
class _export A
{
...
};
When defined in the EXE, the same must be prototyped as:
class huge A
{
...
};
// see User's Guide for more information
Then link with /c and /C on (both case sensitive link and case
sensitive exports ENABLED) when building BOTH the .DLL and the
calling.EXE.
PROBLEM:
OWL and undefined symbols.
SOLUTION:
If you're linking to the static libraries:
- with BC 2.0, link in owlwx.lib, tclasswx.lib, and
sallocwx.lib. (You don't need sallocwx.lib with BC
v 3.x ).
- do NOT define _CLASSDLL in the code generation
dialog, or before including owl.h.
- link with /c and /C. (from IDE, under linker
options, case sensitive link and case sensitive
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -