Problems linking against a DLL - c++

I'm trying to use a third party DLL (I'm compiling using MinGW) but I'm facing some troubles. First of all, the DLL exports undecorated names, but the declaration of the functions seen in the header files contain "__stdcall". Appart of that, I'm using C++, but I've sorrounded the include with 'extern "C"'.
The error:
undefined reference to `Play_Stop#4'
I've tried to link directly to the DLL, as G++ is theorically capable of doing that, but I got some "undefined reference"s.
Then I tried to generate a .def file, using gendef (gendef theirDLL.dll) and later I used dlltool to generate an import lib:
dlltool -k --no-leading-underscore -d theirDLL.def -D theirDLL.dll -l theirDLL.a. Note that I used --no-leading-underscore as I observed with nm that all the functions were preceeded by one underscore, which was causing troubles.
However, even doing all of that, I don't get it to link properly. Any ideas?
I've checked that the linker founds the static library.
The function declaration in header file:
BOOL __stdcall Play_Stop(LONG nPort);
The include directive:
extern "C"{
#include "PlaySDK.h"
}
The nm command output (theirDLL.a)
...
daazs00103.o:
00000000 b .bss
00000000 d .data
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7
00000000 t .text
00000000 T Play_Stop#4
00000000 I __imp_Play_Stop#4
...
And the error:
undefined reference to `Play_Stop#4'
Thank you in advance!

Related

Why does this C++ project fail to build even when appropriate .lib is linked in?

I am attempting to build sample code from Actian Btrieve (https://docs.actian.com/psql/btrieve2v13/html/btest_8cpp-example.html)
It wouldn't build so I've simplified the code down to the following, just to get it working.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include "btrieveCpp.h"
#include <iostream>
int
main(int argc, char *argv[])
{
Btrieve::StatusCode status = Btrieve::STATUS_CODE_UNKNOWN;
std::cout << Btrieve::MAXIMUM_RECORD_LENGTH << std::endl;
//BtrieveFile btrieveFile;
std::cout << "test" << std::endl << status;
return 0;
}
That code builds and runs successfully. Libraries are statically linked and the compiler finds the btrieveCpp.h header file because I've included in the search path.
The build command looks like hte following (the breaks are just so you can read it more easily):
mingw32-g++.exe -Wall -fexceptions -g
-IC:\Dev\Actian\Zen-SDK-Btrieve2API-Windows-noarch-14.00.046.000\include -c
C:\Dev\C++\Btrieve1\btest.cpp -o obj\Debug\btest.o
mingw32-g++.exe -o bin\Debug\Btrieve1.exe obj\Debug\btest.o -static
Program Output
The program output looks like:
The Problem
However, if I uncomment the BtrieveFile line then I get errors when I build, which looks like the following:
Using Code::Blocks IDE
I'm using the Code::Blocks IDE and when I right-click the BtrieveFile item and choose Find Declaration then the IDE takes me to the .H file so it knows where the item is defined.
Also, keep in mind that the other item (Btrieve::MAXIMUM_RECORD_LENGTH) is also defined there (btrieveCpp.h), but it builds with no errors.
Here's where it takes me in the .H file:
What I've Tried
I thought this was because it needed the defintions provided by the .lib file so I added the appropriate .lib so the linker would find it and statically link it in.
I added the lib file as a dependency:
After that I attempted to build again but it still fails.
The build log looks like the following: You can see that the .lib is being linked in now.
-------- Build: Debug in Btrieve1 (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g
-IC:\Dev\Actian\Zen-SDK-Btrieve2API-Windows-noarch-14.00.046.000\include
-c C:\Dev\C++\Btrieve1\btest.cpp -o obj\Debug\btest.o
mingw32-g++.exe -o bin\Debug\Btrieve1.exe obj\Debug\btest.o -static C:\Dev\Actian\Zen-SDK-Btrieve2API-Windows-noarch-14.00.046.000\win32\x86\btrieveCpp.lib
c:/devtools/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe:
obj\Debug\btest.o: in function `main':
C:/Dev/C++/Btrieve1/btest.cpp:13: undefined reference to
'BtrieveFile::BtrieveFile()'
c:/devtools/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe:
C:/Dev/C++/Btrieve1/btest.cpp:13: undefined reference to
'BtrieveFile::~BtrieveFile()'
c:/devtools/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe:
C://Dev/C++/Btrieve1/btest.cpp:13: undefined reference to
'BtrieveFile::~BtrieveFile()'
collect2.exe: error: ld returned 1 exit
status
Process terminated with status 1 (0 minute(s), 2 second(s)) 4
error(s), 0 warning(s) (0 minute(s), 2 second(s))
Would you happen to know what I'm missing? Or what I need to do to resolve this?
EDIT - Changing Linkage
In btrieveC.h (included by btrieveCpp.h) there is indeed a block like the following:
#ifndef LINKAGE
#ifdef __GNUC__
#define LINKAGE
#else
#define LINKAGE __declspec(dllimport)
#endif
#endif
However, if make the switch so that #define LINKAGE __declspec(dllimport) is used and then build I see the following errors (below)
Notice that the names are mangled in output now?
Edit 2 - nm output of btrieveCpp.lib
nm -C C:\Dev\Actian\Zen-SDK-Btrieve2API-Windows-noarch-14.00.046.000\win32\x86\btrieveCpp.lib | findstr /I BtrieveFile
00000000 T ??0BtrieveFile##IAE#PAUbtrieve_file###Z
00000000 I _imp_??0BtrieveFile##IAE#PAUbtrieve_file###Z
00000000 T ??0BtrieveFile##QAE#XZ
00000000 I _imp_??0BtrieveFile##QAE#XZ
00000000 T ??0BtrieveFileAttributes##QAE#XZ
00000000 I _imp_??0BtrieveFileAttributes##QAE#XZ
00000000 T ??0BtrieveFileInformation##QAE#XZ
00000000 I _imp_??0BtrieveFileInformation##QAE#XZ
00000000 T ??1BtrieveFile##QAE#XZ
00000000 I _imp_??1BtrieveFile##QAE#XZ
00000000 T ??1BtrieveFileAttributes##QAE#XZ
00000000 I _imp_??1BtrieveFileAttributes##QAE#XZ
00000000 T ??1BtrieveFileInformation##QAE#XZ
00000000 I _imp_??1BtrieveFileInformation##QAE#XZ
00000000 T ??4BtrieveFile##QAEAAV0#ABV0##Z
00000000 I _imp_??4BtrieveFile##QAEAAV0#ABV0##Z
00000000 T ??4BtrieveFileAttributes##QAEAAV0#ABV0##Z
00000000 I _imp_??4BtrieveFileAttributes##QAEAAV0#ABV0##Z
00000000 T ??4BtrieveFileInformation##QAEAAV0#ABV0##Z
00000000 I _imp_??4BtrieveFileInformation##QAEAAV0#ABV0##Z
00000000 T ?BulkCreate#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkCreatePayload##PAVBtrieveBulkCreateResult###Z
00000000 I _imp_?BulkCreate#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkCreatePayload##PAVBtrieveBulkCreateResult###Z
00000000 T ?BulkRetrieveNext#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkRetrieveAttributes##PAVBtrieveBulkRetrieveResult##W4LockMode#3##Z
00000000 I _imp_?BulkRetrieveNext#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkRetrieveAttributes##PAVBtrieveBulkRetrieveResult##W4LockMode#3##Z
00000000 T ?BulkRetrievePrevious#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkRetrieveAttributes##PAVBtrieveBulkRetrieveResult##W4LockMode#3##Z
00000000 I _imp_?BulkRetrievePrevious#BtrieveFile##QAE?AW4StatusCode#Btrieve##PAVBtrieveBulkRetrieveAttributes##PAVBtrieveBulkRetrieveResult##W4LockMode#3##Z
00000000 T ?FileClose#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile###Z
00000000 I _imp_?FileClose#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile###Z
00000000 T ?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PAVBtrieveIndexAttributes##PBDW4CreateMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PAVBtrieveIndexAttributes##PBDW4CreateMode#3#W4LocationMode#3##Z
00000000 T ?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PAVBtrieveIndexAttributes##PB_WW4CreateMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PAVBtrieveIndexAttributes##PB_WW4CreateMode#3#W4LocationMode#3##Z
00000000 T ?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PBDW4CreateMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PBDW4CreateMode#3#W4LocationMode#3##Z
00000000 T ?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PB_WW4CreateMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileCreate#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFileAttributes##PB_WW4CreateMode#3#W4LocationMode#3##Z
00000000 T ?FileOpen#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile##PBD1W4OpenMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileOpen#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile##PBD1W4OpenMode#3#W4LocationMode#3##Z
00000000 T ?FileOpen#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile##PB_WPBDW4OpenMode#3#W4LocationMode#3##Z
00000000 I _imp_?FileOpen#BtrieveClient##QAE?AW4StatusCode#Btrieve##PAVBtrieveFile##PB_WPBDW4OpenMode#3#W4LocationMode#3##Z
00000000 T ?GetBalancedIndexes#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetBalancedIndexes#BtrieveFileInformation##QAEHXZ
00000000 T ?GetBtrieveFile#BtrieveCollection##IAEPAVBtrieveFile##XZ
00000000 I _imp_?GetBtrieveFile#BtrieveCollection##IAEPAVBtrieveFile##XZ
00000000 T ?GetBtrieveFile#BtrieveFile##IAEPAUbtrieve_file##XZ
00000000 I _imp_?GetBtrieveFile#BtrieveFile##IAEPAUbtrieve_file##XZ
00000000 T ?GetBtrieveFileAttributes#BtrieveFileAttributes##IAEPAUbtrieve_file_attributes##XZ
00000000 I _imp_?GetBtrieveFileAttributes#BtrieveFileAttributes##IAEPAUbtrieve_file_attributes##XZ
00000000 T ?GetBtrieveFileInformation#BtrieveFileInformation##IAEPAUbtrieve_file_information##XZ
00000000 I _imp_?GetBtrieveFileInformation#BtrieveFileInformation##IAEPAUbtrieve_file_information##XZ
00000000 T ?GetBtrieveFilePtr#BtrieveFile##IAEPAPAUbtrieve_file##XZ
00000000 I _imp_?GetBtrieveFilePtr#BtrieveFile##IAEPAPAUbtrieve_file##XZ
00000000 T ?GetClientTransactions#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetClientTransactions#BtrieveFileInformation##QAEHXZ
00000000 T ?GetContinuousOperation#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetContinuousOperation#BtrieveFileInformation##QAEHXZ
00000000 T ?GetCursorPosition#BtrieveFile##QAE_JXZ
00000000 I _imp_?GetCursorPosition#BtrieveFile##QAE_JXZ
00000000 T ?GetDuplicateRecordConflictCursorPosition#BtrieveFileInformation##QAE_JXZ
00000000 I _imp_?GetDuplicateRecordConflictCursorPosition#BtrieveFileInformation##QAE_JXZ
00000000 T ?GetDuplicateRecordConflictIndex#BtrieveFileInformation##QAE?AW4Index#Btrieve##XZ
00000000 I _imp_?GetDuplicateRecordConflictIndex#BtrieveFileInformation##QAE?AW4Index#Btrieve##XZ
00000000 T ?GetExplicitLocks#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetExplicitLocks#BtrieveFileInformation##QAEHXZ
00000000 T ?GetFileVersion#BtrieveFileInformation##QAE?AW4FileVersion#Btrieve##XZ
00000000 I _imp_?GetFileVersion#BtrieveFileInformation##QAE?AW4FileVersion#Btrieve##XZ
00000000 T ?GetFixedRecordLength#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetFixedRecordLength#BtrieveFileInformation##QAEHXZ
00000000 T ?GetFreeSpaceThreshold#BtrieveFileInformation##QAE?AW4FreeSpaceThreshold#Btrieve##XZ
00000000 I _imp_?GetFreeSpaceThreshold#BtrieveFileInformation##QAE?AW4FreeSpaceThreshold#Btrieve##XZ
00000000 T ?GetGatewayMajorVersion#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetGatewayMajorVersion#BtrieveFileInformation##QAEHXZ
00000000 T ?GetGatewayMinorVersion#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetGatewayMinorVersion#BtrieveFileInformation##QAEHXZ
00000000 T ?GetGatewayName#BtrieveFileInformation##QAE?AW4StatusCode#Btrieve##PADH#Z
00000000 I _imp_?GetGatewayName#BtrieveFileInformation##QAE?AW4StatusCode#Btrieve##PADH#Z
00000000 T ?GetGatewayName#BtrieveFileInformation##QAEPBDXZ
00000000 I _imp_?GetGatewayName#BtrieveFileInformation##QAEPBDXZ
00000000 T ?GetGatewayPatchLevel#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetGatewayPatchLevel#BtrieveFileInformation##QAEHXZ
00000000 T ?GetGatewayPlatform#BtrieveFileInformation##QAEHXZ
00000000 I _imp_?GetGatewayPlatform#BtrieveFileInformation##QAEHXZ
00000000 T ?GetHandleCount#BtrieveFileInformation##QAEHXZ
I note the class declaration has: class LINKAGE BtrieveFile. Is the symbol LINKAGE defined properly in your build -- should probably become __declspec(import) (cf. the docs) since you're using Windows libraries, even though you're building with gcc via mingw.
There is probably a block in Btrieve's headers that has ifdefs for that. Find that, define the right symbol project-wide, and you should then get the symbols imported properly. Then you'll just need to make sure the DLL is in your EXE's directory or the search path in order to run the EXE.
Update:
Alas, your new issues probably show that you can't do what you want because the library was built with a different compiler. See MinGW's Interoperability of Libraries Created by Different Compiler Brands. You probably need to use the same compiler (or at least a compatible one) that the library was built with, OR you need to get a version of the library built with GCC (or build it yourself, if that's an option). There is a free community edition of Visual Studio, if that helps.

Extract and link a 64bit gnu c++ lib from a 64bit mscv++ lib

I have built SpiderMonkey on Windows. They provide MSVC++ toolchain and I couldn't build it for mingw. I've built it for 64bit.
It is a DLL, I need to convert its lib to gnu C++ format (.lib to .a).
After looking on the web, I've found here how to do this, roughly:
gendef mozjs-45.dll
dlltool --as-flags=--64 -m i386:x86-64 -k --output-lib mozjs-45.a --input-def mozjs-45.def
I use TDM-GCC-64 under Code::Blocks. At link time it throws errors like:
undefined reference to `__imp__Z13JS_GetPrivateP8JSObject'
I have checked the lib content using:
nm libmozjs-45.a > libmozjs-45.nm
I see there are the same entries as in the def file exported, but that looks different than linker expects (I presume):
?JS_GetPrivate##YAPEAXPEAVJSObject###Z
Edit 1
I have managed to build SpiderMonkey with mingw-w64. Now, at linking time I get the following error:
undefined reference to `__imp__ZN17JSAutoCompartmentC1EP9JSContextP8JSObject'
Looking with nm at the lib, I have:
d000536.o:
0000000000000000 i .idata$4
0000000000000000 i .idata$5
0000000000000000 i .idata$6
0000000000000000 i .idata$7
0000000000000000 t .text
0000000000000000 I __imp__ZN17JSAutoCompartmentC1EP9JSContextP8JSObjectON7mozilla6detail19GuardObjectNotifierE
U _head_mozjs_45_dll
0000000000000000 T _ZN17JSAutoCompartmentC1EP9JSContextP8JSObjectON7mozilla6detail19GuardObjectNotifierE
Indeed, the definition of the class is:
class MOZ_RAII JS_PUBLIC_API(JSAutoCompartment)
{
JSContext* cx_;
JSCompartment* oldCompartment_;
public:
JSAutoCompartment(JSContext* cx, JSObject* target
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
JSAutoCompartment(JSContext* cx, JSScript* target
MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
~JSAutoCompartment();
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
Why the same compiler exports this as __imp__ZN17JSAutoCompartmentC1EP9JSContextP8JSObjectON7mozilla6detail19GuardObjectNotifierE, but, when referencing it, expects it as __imp__ZN17JSAutoCompartmentC1EP9JSContextP8JSObject?
Answer: missed a symbol definition that exclude MOZ_GUARD_OBJECT_NOTIFIER_PARAM from build.

Link errors while trying to compile statically an executable with clang on windows

I've been trying to shift my C++ work in windows on clang lately, and everything so far seems to work right except one thing: Making full static excecutables (without any external dll dependencies like libgcc libstdc++ etc...).
Let me give you an example.
We have the following simple program:
#include <string>
int main()
{
std::string s1 = "Happy";
std::string s2 = " Cow";
std::string s3 = s1 + s2;
return 0;
}
If we try to compile it using the following line:
clang++ -static -O0 -std=c++11 bug.cpp
We get the following link error:
F:/Programs/LLVM/bin/../lib/gcc/i686-w64-mingw32/4.8.2\libstdc++.a(string-inst.o):(.text$_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_[__ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_]+0x0): multiple definition of `std::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
C:\Users\THEART~1\AppData\Local\Temp\bug-4d96cd.o:(.text[__ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_]+0x0): first
defined here
collect2.exe: error: ld returned 1 exit status
clang++.exe: error: linker (via gcc) command failed with exit code 1 (use -v to see invocation)
We get the same result by using the following flags:
clang++ -static -static-libgcc -static-libstdc++ -O0 -std=c++11 bug.cpp
It should be noted that when using g++ the program compiles and links fine with any of the above two lines. Also obviously when removing the static flags the program compiles just fine with the clang too.
This bug has been chasing me for weeks, so last night i gave it all and started searching for anything that could have been causing it. After some hours of really heavy digging, i thought i should inspect and compare the intermediate output of the two compilers.
Looking on the symbols of the clang generated object file i saw this:
nm bug_clang.o
--------------------
00000000 b .bss
00000000 d .data
00000000 d .eh_frame
00000000 r .gcc_except_table
00000000 r .rdata
00000000 t .text
00000000 t .text
00000001 a #feat.00
U ___gxx_personality_v0
U ___main
U __Unwind_Resume
U __ZNSaIcEC1Ev
U __ZNSaIcED1Ev
U __ZNSs6appendERKSs
U __ZNSsC1EPKcRKSaIcE
U __ZNSsC1ERKSs
U __ZNSsD1Ev
00000000 T __ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
00000000 T _main
00000000 r GCC_except_table0
00000048 r GCC_except_table1
While inspecting the symbols on the g++ generated object file gave me this:
nm bug_g++.o
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .eh_frame$_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
00000000 d .gcc_except_table
00000000 r .rdata
00000000 r .rdata$zzz
00000000 t .text
00000000 t .text$_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
U ___gxx_personality_v0
U ___main
U __Unwind_Resume
U __ZNSaIcEC1Ev
U __ZNSaIcED1Ev
U __ZNSs6appendERKSs
U __ZNSsC1EPKcRKSaIcE
U __ZNSsC1ERKSs
U __ZNSsD1Ev
00000000 r __ZStL19piecewise_construct
00000000 T __ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_
00000000 T _main
As you can observe there are some internal symbols on the g++ generated object file that does not exist at all or are different in the clang generated object file, namely:
Entry "00000000 r
.eh_frame$_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_" is missing
(I suppose that it has something to do with the exception handling)
Entry "00000000 t .text$_ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_" is altered
(I believe that this one exists in the clang object file too as the second "00000000 t .text" entry)
I have not really in depth knowledge on the subject, but my bet would be, that the altered second internal symbol (the one i mention above) on the clang generated object file is the root cause of the problem.
So is this a bug on the clang compiler, or am i doing something wrong?
In case you ask, i am using LLVM v3.6 with MinGW-w64 4.8.2 on Windows that i set up using this guide: https://yongweiwu.wordpress.com/2014/12/24/installing-clang-3-5-for-windows/
Also may i note that another cause that really stalled me when trying to find the cause of the problem is that if i try to compile the snippet using -O2 everything works fine due to the inlining that the compiler does!
I really hope that anyone could help me solve this problem because its driving me nuts!

How to avoid standard include files during compilation

I am trying to use my own printf function so i don't want to include standard include files... so I am compiling my code with -nostdinc
I have created my program something like this:
extern int printf(const char*,...);
printf("Value:%d",1234);
//printf("\n");
It is working fine for this code, but when I use printf("\n") then it is showing undefined reference to 'putchar'.
If i comment printf("\n"); then nm command is showing
$ nm test1.o
U exit
00000000 T main
U printf
00000030 T _start
but if I use printf("\n"); then nm command is showing
$nm test1.o
U exit
00000000 T main
U printf
U putchar
0000003c T _start
I am not getting how and from where putchar is getting included
gcc version 4.8.2 (GCC)
gcc optimizes printf in certain situations. You can look at the function fold_builtin_printf here for the complete details. IIRC, it optimizes calls with one argument followed by a newline to puts/putchar. You can turn it off by specifying -fno-builtin(gcc docs).

Global constructor call not in .init_array section

I'm trying to add global constructor support on an embedded target (ARM Cortex-M3).
Lets say I've the following code:
class foobar
{
int i;
public:
foobar()
{
i = 100;
}
void inc()
{
i++;
}
};
foobar foo;
int main()
{
foo.inc();
for (;;);
}
I compile it like this:
arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o
When I look at the .init_array section with objdump it shows the .init_section has a zero size.
I do get an symbol named _Z41__static_initialization_and_destruction_0ii.
When I disassemble the object file I see that the global construction is done in the static_initialization_and_destruction symbol.
Why isn't a pointer added to this symbol in the .init_section?
I know it has been almost two years since this question was asked, but I just had to figure out the mechanics of bare-metal C++ initialization with GCC myself, so I thought I'd share the details here. There turns out to be a lot of out-of-date or confusing information on the web. For example, the oft-mentioned collect2 wrapper does not appear to be used for ARM ELF targets, since its arbitrary section support enables the approach described below.
First, when I compile the code above with the given command line using Sourcery CodeBench Lite 2012.09-63, I do see the correct .init_array section size of 4:
$ arm-none-eabi-objdump -h foo.o
foo.o: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
13 .init_array 00000004 00000000 00000000 0000010c 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA
...
When I look at the section contents, it just contains 0:
$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
0000 00000000 ....
However, there is also a relocation section that sets it correctly to _GLOBAL__sub_I_foo:
$ arm-none-eabi-objdump -x foo.o
...
RELOCATION RECORDS FOR [.init_array]:
OFFSET TYPE VALUE
00000000 R_ARM_TARGET1 _GLOBAL__sub_I_foo
In general, .init_array points to all of your _GLOBAL__sub_I_XXX initializer stubs, each of which calls its own copy of _Z41__static_initialization_and_destruction_0ii (yes, it is multiply-defined), which calls the constructor with the appropriate arguments.
Because I'm using -nostdlib in my build, I can't use CodeSourcery's __libc_init_array to execute the .init_array for me, so I need to call the static initializers myself:
extern "C"
{
extern void (**__init_array_start)();
extern void (**__init_array_end)();
inline void static_init()
{
for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
(*p)();
}
}
__init_array_start and __init_array_end are defined by the linker script:
. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}
This approach seems to work with both the CodeSourcery cross-compiler and native ARM GCC, e.g. in Ubuntu 12.10 for ARM. Supporting both compilers is one reason for using -nostdlib and not relying on the CodeSourcery CS3 bare-metal support.
Timmmm,
I just had the same issue on the nRF51822 and solved it by adding KEEP() around a couple lines in the stock Nordic .ld file:
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
While at it, I did the same to the fini_array area too. Solved my problem and the linker can still remove other unused sections...
You have only produced an object file, due to the -c argument to gcc. To create the .init section, I believe that you need to link that .o into an actual executable or shared library. Try removing the -c argument and renaming the output file to "foo", and then check the resulting executable with the disassembler.
If you look carefully _Z41__static_initialization_and_destruction_0ii would be called inside global constructor. Which inturn would be linked in .init_array section (in arm-none-eabi- from CodeSourcery.) or some other function (__main() if you are using Linux g++). () This should be called at startup or at main().
See also this link.
I had a similar issue where my constructors were not being called (nRF51822 Cortex-M0 with GCC). The problem turned out to be due to this linker flag:
-Wl,--gc-sections
Don't ask me why! I thought it only removed dead code.