printfs inside a shared object (dynamic library) not getting printed - printf

I have a shared object which i create on windows using Real View developer suite tool linked command on windows host-
armlink -o mylib.so <"my *.o files given here">
Then i link an application with this mylib.so shared library on linux using gcc tools.
I have printf statements inside functions in this mylib.so, but when I run the final executable, i do not get any printf outputs on console.(stdio.h is inlcuded wherever printfs are called)
So is there any known issue with shared libraries which cause printf or any system functions/system calls/run time library functions not to work correctly?
Or is that got to do with my peculiar setup of making a shared library on windows based compiler tool chain but linking this shared library with an application on linux-gcc compiler tools?
Thank you.
-AD

Since your target is arm, and I assume this is C it should not be a problem to compile some files on windows and then link on linux. Have you verified this however? I would suggest making a hello.so on windows, linked from hello.c:
#include <stdio.h>
void hello(void) {printf("Hello\n");}
and then link main from main.c on linux:
void hello(void);
int main(int argc, char *argv[]){ hello(); return 0; }
as a minimum compiler chain test.
If you call printf from code in defined in your final executable (i.e. not code from your shared library) do you get any output from that?
Does
strings --print-file-name -a mylib.so final_executable | grep "string from printf in shared library"
return two occurenses?
Are there any references to printf in
readelf -a mylib.so
readelf -a final_executable
?

Related

How do I print a version string/run some code when my library (.so) is executed?

I've seen some versions of libc.so which, when executed from the command line, will print a version string, like so:
$ /lib/libc.so.6
GNU C Library (Buildrood) stable release version 2.30.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTIBILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 7.4.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<https://www.gnu.org/software/libc/bugs.html>.
There's obviously some kind of entry point into this library, while still preserving main() for user programs.
I'd like to do this for my own library, to print useful information about how it was compiled, what it supports etc. My searches regarding this have not been fruitful, but perhaps I'm searching the wrong thing. How can I do this?
Position independent executables (PIE) are now the default on systems like Linux and OpenBSD [1]. So you can just build your shared library as you would a regular executable, and give the executable as an object argument to cc, LD_PRELOAD or dlopen() it as if it were a shared library.
The only thing you should make sure is that all the needed symbols are exported, which is NOT the default. So you should either use -Wl,-E (which would and cause it to export all symbols), or give it a list of exported symbols via -Wl,--dynamic-list=filename.
$ cc -Wl,--dynamic-list=<(echo '{func;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ cc -include stdio.h -xc - -x none ./shared.so -o main <<'EOT'
int main(){ extern void func(void); func(); }
EOT
$ ./shared.so
Shared library!
$ ./main
Exported function!
The problem with -Wl,-E is that it will also export the symbols from the crt*.o startup files, which may cause the "main" executable to reference them instead of pulling its own copy of the startup code. That doesn't look like a good idea.
A solution which would allow you to still use -Wl,-E instead of listing all the exported symbols would be to use -Wl,--version-script=file with a version script which localizes main, __libc_csu*, _start and the rest of the zoo:
cc -Wl,-E -Wl,--version-script=<(echo '{local:_*;data_start;main;};') -include stdio.h -o shared.so -xc - <<'EOT'
int main(){ printf("Shared library!\n"); }
void func(){ printf("Exported function!\n"); }
EOT
$ ./main
Exported function!
[1] on some systems like FreeBSD or NetBSD you still have to use -pie -fPIE in order to build a PIE executable, but not to link against one.

How to static link ncurses on AIX using xlc

I'm trying to use the ncurses library on AIX 7.1 to make use of panels which aren't included in the curses library that is standard on AIX. I have the ncurses library installed. The compile,link, and execute work fine with:
xlc ngoodbye.c -lncurses
The actual ncurses library is libncurses.a, which I understand is a static library. However, when I move the executable to another AIX host and execute I get:
Dependent module libncurses.a(libncurses.so.5) could not be loaded. Could not load module libncurses.a(libncurses.so.5). System error: No such file or directory.
How can I link the ncurses library so that the program will execute on other hosts where the ncurses library isn't installed? Note I'm using xlc on AIX, not gcc.
I've tried -bstatic but get link errors at compile time. Note that I'm not a developer so my experience in this area is limited. Thanks.
Both static and shared libraries in AIX are built as position independent (PIC). So even a "shared" library can be statically bound to an executable. You were on the right track with -bstatic, you just need to switch back to dynamic binding for the rest of the libraries you're linking to.
So try this for your final link:
xlc -o myexe myexe.o <other objects as needed> -bstatic -lncurses -bdynamic -lm <and other other libraries as needed>
I do this all the time to make sure that my production environment matches my development one.
Normally ".a" does mean a static library. However, in adapting the initial report (in 2008) describing the AIX 5 shared library configuration there was some miscommunication and ".a" was used for both static and shared libraries. That was finally corrected last year (see changelog).
AIX 4, by the way, used a much more complicated scheme, so shared libraries for ncurses were first implemented on AIX 5.
Packagers prefer shared libraries. So what you have is a shared library named libncurses.a (legal, but not conventional). This is not created with the archiver ar, but using the loader ld. To see that they are different, you can try
ar tv libncurses.a
(with the appropriate directory). Likely ar will say something like
ar: 0707-108 File libncurses.a is not an archive file.
while file may give a more informative message:
libncurses.a: executable (RISC System/6000) or object module not stripped
You can however build ncurses from source. In that case (no matter what version), the default builds static libraries. You need not install those into the system area, but can configure ncurses using the --prefix option to install into a different directory.
As suggested in another answer, there is a workaround using the -bdynamic and -bstatic options of AIX's ld (loader), e.g., changing
xlc -o foo foo.c -lncurses
to
xlc -o foo foo.c -bstatic -lncurses -ldynamic
However, this is partly dependent upon the loader's search path and the name of the archive. If the archive is named libncurses.a, the command works as given. If it is named libncurses.so (as in current sources), then this command is needed to link against the shared library:
xlc -o foo foo.c -brtl -lncurses
But this command (which one might suppose to provide the static linkage using the libncurses.so file) does not succeed:
xlc -o foo foo.c -brtl -bstatic -lncurses -bdynamic

Linker not taking local (user) boost installation with g++

I want to have local installation (in my home-folder (Linux), say $HOME/boost) of the boost C++ libraries in addition to a system-wide installed default of the boost libs. I built them from sorce and that worked fine.
After that, I set the environment variables CPLUS_INCLUDE_PATH and LD_LIBRARY_PATH to match the destination of the local installation, so both pointing to $HOME/boost/include and $HOME/boost/lib/, respectively.
In order to test that, I used the following code for testing the correct usage of CPLUS_INCLUDE_PATH for the headers:
#include <boost/version.hpp>
#include <iostream>
#include <iomanip>
int main()
{
std::cout << "Boost version: " << BOOST_LIB_VERSION << std::endl;
return 0;
}
Compiling it with g++ -o Test_boost_version test_boost_version.cpp works as expected, reporting the expected (local) version. Having CPLUS_INCLUDE_PATH empty gives me the boost-version of the default, system-wide installation. So far so good.
In order to test the linking, I used the following code (taken from the boost homepage:
#include <boost/regex.hpp>
#include <iostream>
#include <string>
int main()
{
std::string line;
boost::regex pat( "^Subject: (Re: |Aw: )*(.*)" );
while (std::cin)
{
std::getline(std::cin, line);
boost::smatch matches;
if (boost::regex_match(line, matches, pat))
std::cout << matches[2] << std::endl;
}
}
and built it with g++ -o Test_boost_linking test_boost_linking.cpp -lboost_regex.
Calling ldd Test_boost_linking however does NOT make use of the local installation (provided via LD_LIBRARY_PATH) but gives me: libboost_regex.so.1.42.0 => /usr/lib/libboost_regex.so.1.42.0 (0x00007f9264612000)
When I use g++ -o Test_boost_linking test_boost_linking.cpp -lboost_regex -L$HOME/boost/lib, ldd is reporting the correct library (libboost_regex.so.1.50.0 => $HOME/boost/lib/libboost_regex.so.1.50.0 (0x00007f6947d2a000)).
This is actually a problem for me since I want to set up my local environment such that a compilation will ignore the system-default boost installation and only use the local installation and I thought this is exactly what is achieved when setting the CPLUS_INCLUDE_PATH and LD_LIBRARY_PATH, but for the latter, this seems not to hold true.
So how can I make sure that using g++ -o Test_boost_linking test_boost_linking.cpp -lboost_regex (without -L) uses the local libraries?
[EDIT] Thinking of it further, I am wondering IF it is actually absolutely mandatory to use "-L$HOME/boost/lib" in the command-line (using LDFLAGS as environment variable seems to have no effect, probably just in combination with a Makefile) when using libraries in a non-standard directory?? Is this the case?
(BTW I think this will hold true also for other libraries, not only boost...)
(I used: g++ (Debian 4.4.5-8) 4.4.5)
Thank you.
You need to use the environment variable LIBRARY_PATH to let gcc know where to find the libraries at link time. LD_LIBRARY_PATH lets the program know where to find the dynamic libraries at runtime. This answer has more details. These links from "An Introduction to GCC" may also be useful: Compilation options:Environment Variables and Shared and Static Libraries

i386-mingw32-g++: error trying to exec 'cc1plus': execvp: No such file or directory

If I compile this QT c++ program in SuSE Linux
#include <iostream>
using namespace std;
int main ()
{
cout << "Hello World!";
return 0;
}
When I type
i386-mingw32-g++ helloworld.cpp
I get the following error
i386-mingw32-g++: error trying to exec 'cc1plus': execvp: No such file or directory
Is this because MinGW package which i installed contains only gcc in it.. hence i downloaded gcc-g++-3.4.5.rpm package and just copy pasted i386-mingw32-g++ and cc1plus executable along with C++ include files.
Pls reply.
Thanking You
Ugh. The cc1plus in gcc-g++-3.4.5.rpm is not for mingw32. You need the one for your distro.
e.g. for Fedora 10, use http://sourceforge.net/projects/outmodedbonsai/files/Mingw%20Cross-compiler/mingw-1.10-1.fc10.x86_64.rpm
Quoting from here:
It means that your shell could find
the g++ frontend of the GNU compiler
but that frontend couldn't find
cc1plus, the actual C++ compiler; it
could find cpp, the preprocessor, it
already ran. Go to the directory where
the g++ frontend is stored (type:
"which g++") and look for the file
cc1plus in that same directory or a
sub- directory thereof. If it isn't
there your compiler installation is
broken; if it is there some
configuration of it went berzerk.
Also, have a look at this thread.
suse cross-compile toolchain is here.
http://download.opensuse.org/repositories/CrossToolchain:/mingw/

Unable to Compile Objective C using Gnustep on windows

Hi i am a beginner learning objective c.
i am finding an error "hello.m:1:34: Foundation/Foundation.h: No such file or directory"
i came to know that i need to make a make file
may i know how to make the make file please
No need to create a makefile. If you start MinGW from "All Programs -> GNUstep -> Shell" as Pax indicates above, you can just compile your .m file.
My GNUstep installation is in c:\GNUstep\GNUstep\System. If yours is different, you should change the import of Foundation.h accordingly.
I did this:
Create c:\myprogs\obj-c\hello\hello.m that looks like this:
//---------- Hello.m
#import <../../GNUstep/System/Library/Headers/Foundation/Foundation.h>
int main(int argc, const char* argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSLog(#"Hello from Hello.m!");
[pool release];
return 0;
}
//----------
Start MinGW shell. (See above.)
On shell command line, change to directory where program code is located. (Note that, since this is not Unix, the Windows drive letter must be included.):
cd /c/myprogs/obj-c/hello
Compile the program:
gcc -o hello hello.m -I/c/GNUstep/GNUstep/System/Library/Headers \
-L /c/GNUstep/GNUstep/System/Library/Libraries -lobjc -lgnustep-base \
-fconstant-string-class=NSConstantString
(Note that "\" character allows us to extend command to multiple lines.)
I get the following informational messages when I compile:
Info: resolving ___objc_class_name_NSAutoreleasePool by linking to __imp____objc_class_name_NSAutoreleasePool (auto-import)
Info: resolving ___objc_class_name_NSConstantString by linking to __imp____objc_class_name_NSConstantString (auto-import)
Running resulting hello.exe gives me this:
2009-06-03 14:44:59.483 hello[1240] Hello from Hello.m!
That problem just looks like you haven't instructed gcc on where to find the relevant include files (i.e., the directory in which Foundation/Foundation.h resides).
Are you running gcc from under MinGW or from the command prompt. You should have a "All Programs -> GNUstep -> Shell" on your Start menu which brings up this shell.
A makefile for this should be as simple as:
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = YourProg
YourProg_OBJC_FILES = source_code.m
include $(GNUSTEP_MAKEFILES)/tool.make
If you will put your source codes into home directory in GNUStep, you don't need to provide relative location of Foundation framework.
Using a makefile such as the one specified by paxdiablo is probably the easiest, because rather than trying to remember an arcane command line each time, you set up the makefile and then call make from the source folder.
However, my experience under Windows suggested that GNUStep and Windows, even with the shell, won't build using that because it can't find all the make files it needs - add an environment variable GNUSTEP_MAKEFILES with a value of /GNUstep/System/Library/Makefiles and restart that shell, and then any errors from it being unable to find the standard makefiles should be history.
(I had tried using full paths to the makefiles, but found that this included the specific makefiles but then failed when trying to include further ones, hence going the easy route and adding an environment variable.)