I'm writing an application using libao for audio output. The portion
of my program that calls into libao lives in a shared object:
// playao.c
// compile with: gcc -shared -o libplayao.so playao.c -lao -lm
#include <ao/ao.h>
#include <stdio.h>
#include <math.h>
void playao(void) {
int i;
unsigned char samps[8000];
ao_initialize();
ao_sample_format sf;
sf.bits = 8;
sf.rate = 8000;
sf.channels = 1;
sf.byte_format = AO_FMT_NATIVE;
sf.matrix = "M";
ao_device *device = ao_open_live(ao_default_driver_id(), &sf, NULL);
if(!device) {
puts("ao_open_live error");
ao_shutdown();
return;
}
for(i = 0; i < 8000; ++i) {
float time = (float)i / 8000;
float freq = 440;
float angle = time * freq * M_PI * 2;
float value = sinf(angle);
samps[i] = (unsigned char)(value * 127 + 127);
}
if(!ao_play(device, (char *)samps, 8000)) {
puts("ao_play error");
}
ao_close(device);
ao_shutdown();
}
If I link against this shared object in a program, it works fine:
// directlink.c
// compile with: gcc -o directlink directlink.c libplayao.so -Wl,-rpath,'$ORIGIN'
void playao(void);
int main(int argc, char **argv) {
playao();
return 0;
}
However, if I use dlopen/dlsym to invoke it, there are no errors, but the
program does not cause any sound to be emitted:
// usedl.c
// compile with: gcc -o usedl usedl.c -ldl
#include <dlfcn.h>
#include <stdio.h>
int main(int argc, char **argv) {
void *handle = dlopen("./libplayao.so", RTLD_LAZY);
if(!handle) {
puts("dlopen failed");
return 1;
}
void *playao = dlsym(handle, "playao");
if(!playao) {
puts("dlsym failed");
dlclose(handle);
return 1;
}
((void (*)(void))playao)();
dlclose(handle);
return 0;
}
However, running usedl with LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libao.so.4
does work. So there's something about libao that wants to be loaded when the
program starts up, and doesn't like being loaded any later.
Why is this? Is there any way to work around this, so that libao works
correctly even if loaded later in the program's execution?
I'm running Debian 10 "buster" if it matters.
I asked about this on the #xiph channel on Freenode and xiphmont suggested turning turning on verbose mode. Once I did that, the failing case started getting the message:
ERROR: Failed to load plugin /usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so => dlopen() failed
So libao itself is trying to dlopen something, and it's failing. It's not showing me any more details, so I ran the program under GDB and set a breakpoint on dlopen. After hitting the dlopen breakpoint for libalsa and running finish, I tried finding what the error was by using print (const char *)dlerror(). And with this, I get a more detailed error:
/usr/lib/x86_64-linux-gnu/ao/plugins-4/libalsa.so: undefined symbol: ao_is_big_endian
So ao's libalsa plugin is trying to reference symbols back in libao, but it's not finding them. Why could this be? Referencing the dlopen documentation, I see:
Zero or more of the following values may also be ORed in flags:
RTLD_GLOBAL: The symbols defined by this shared object will be made available for symbol resolution of subsequently loaded shared objects.
RTLD_LOCAL: This is the converse of RTLD_GLOBAL, and the default if neither flag is specified. Symbols defined in this shared object are not made available to resolve references in subsequently loaded shared objects.
Because my dlopen call only used RTLD_LAZY and didn't include RTLD_GLOBAL or RTLD_LOCAL, it defaulted to RTLD_LOCAL, which does not expose the symbols in the shared object (like ao_is_big_endian) to subsequently loaded shared objects (like libalsa.so).
So, I tried changing the code from:
void *handle = dlopen("./libplayao.so", RTLD_LAZY);
To:
void *handle = dlopen("./libplayao.so", RTLD_LAZY | RTLD_GLOBAL);
And lo and behold, it works!
Related
The Actual Problem
I have an executable that by default uses EGL and SDL 1.2 to handle graphics and user input respectively. Using LD_PRELOAD, I have replaced both with GLFW.
This works normally unless the user has installed the Wayland version of GLFW, which depends on EGL itself. Because all the EGL calls are either stubbed to do nothing or call GLFW equivalents, it doesn't work (ie. eglSwapBuffers calls glfwSwapBuffers which calls eglSwapBuffers and so on). I can't remove the EGL stubs because then it would call both EGL and GLFW and the main executable is closed-source so I can't modify that.
Is there any way to make LD_PRELOAD affect the main executable but not GLFW? Or any other solution to obtain the same effect?
The Simplified Problem
I made a simplified example to demonstrate the problem.
Main Executable:
#include <stdio.h>
extern void do_something();
int main() {
do_something();
fputs("testing B\n", stderr);
}
Shared Library:
#include <stdio.h>
void do_something() {
fputs("testing A\n", stderr);
}
Preloaded Library:
#include <stdio.h>
int fputs(const char *str, FILE *file) {
// Do Nothing
return 0;
}
When the preloaded library isn't used, the output is:
testing A
testing B
When it is used, the output is nothing.
I'm looking for a way to make the preloaded library only affect the main executable, that the output would be:
testing A
Thank you!
You can check if the return address is in the executable or the library, and then call either the "real" function or do your stub code, like this:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static struct {
ElfW(Addr) start, end;
} *segments;
static int n;
static int (*real_fputs)(const char *, FILE *);
static int callback(struct dl_phdr_info *info, size_t size, void *data) {
n = info->dlpi_phnum;
segments = malloc(n * sizeof *segments);
for(int i = 0; i < n; ++i) {
segments[i].start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
segments[i].end = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr + info->dlpi_phdr[i].p_memsz;
}
return 1;
}
__attribute__((__constructor__))
static void setup(void) {
real_fputs = dlsym(RTLD_NEXT, "fputs");
dl_iterate_phdr(callback, NULL);
}
__attribute__((__destructor__))
static void teardown(void) {
free(segments);
}
__attribute__((__noinline__))
int fputs(const char *str, FILE *file) {
ElfW(Addr) addr = (ElfW(Addr))__builtin_extract_return_addr(__builtin_return_address(0));
for(int i = 0; i < n; ++i) {
if(addr >= segments[i].start && addr < segments[i].end) {
// Do Nothing
return 0;
}
}
return real_fputs(str, file);
}
This has some caveats, though. For example, if your executable calls a library function that tail-calls a function you're hooking, then this will incorrectly consider that library call an executable call. (You could mitigate this problem by adding wrappers for those library functions too, that unconditionally forward to the "real" function, and compiling the wrapper code with -fno-optimize-sibling-calls.) Also, there's no way to distinguish whether anonymous executable memory (e.g., JITted code) originally came from the executable or a library.
To test this, save my code as hook_fputs.c, your main executable as main.c, and your shared library as libfoo.c. Then run these commands:
clang -fPIC -shared hook_fputs.c -ldl -o hook_fputs.so
clang -fPIC -shared libfoo.c -o libfoo.so
clang main.c ./libfoo.so
LD_PRELOAD=./hook_fputs.so ./a.out
Implement the interposing library separately for the two cases.
Create a wrapper script or program that uses ldd to find out the exact EGL library version and their paths the target binary is dynamically linked against; then, using ldd on the the GLFW library, to find out whether it is linked against EGL or not. Finally, have it execute the target binary with the path to the appropriate interposing library in LD_PRELOAD environment variable.
I'm trying out the examples in the xmlrpc-c documentation:
#include <stdio.h>
#include <xmlrpc.h>
#include <xmlrpc_server.h>
//#include <xmlrpc_server_abyss.h>
#include <xmlrpc_abyss.h>
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/util.h>
static xmlrpc_value *
sample_add(xmlrpc_env * const envP,
xmlrpc_value * const paramArrayP,
void * const serverContext) {
xmlrpc_int32 x, y, z;
/* Parse our argument array. */
xmlrpc_decompose_value(envP, paramArrayP, "(ii)", &x, &y);
if (envP->fault_occurred)
return NULL;
/* Add our two numbers. */
z = x + y;
/* Return our result. */
return xmlrpc_build_value(envP, "i", z);
}
int
main (int const argc,
const char ** const argv) {
xmlrpc_server_abyss_parms serverparm;
xmlrpc_registry * registryP;
xmlrpc_env env;
xmlrpc_env_init(&env);
registryP = xmlrpc_registry_new(&env);
xmlrpc_registry_add_method(
&env, registryP, NULL, "sample.add", &sample_add, NULL);
serverparm.config_file_name = argv[1];
serverparm.registryP = registryP;
printf("Starting XML-RPC server...\n");
xmlrpc_server_abyss(&env, &serverparm, XMLRPC_APSIZE(registryP));
return 0;
}
I try to compile using gcc:
gcc source.c
nohting fancy and I get:
/tmp/ccfGuc6A.o: In function sample_add':
source.c:(.text+0x38): undefined reference toxmlrpc_decompose_value'
source.c:(.text+0x6d): undefined reference to xmlrpc_build_value'
/tmp/ccfGuc6A.o: In functionmain':
source.c:(.text+0x96): undefined reference to xmlrpc_env_init'
source.c:(.text+0xa5): undefined reference toxmlrpc_registry_new'
source.c:(.text+0xd8): undefined reference to xmlrpc_registry_add_method'
source.c:(.text+0x117): undefined reference toxmlrpc_server_abyss'
collect2: error: ld returned 1 exit status
these functions exist in the:
/usr/include/xmlrpc-c/base.h
whihc I have referenced:
include
I think I'm not passing the right options to link, I don't know how it's done though.
thanks
You definitely don't pass the correct argument for the linker. Just including a header file doesn't actually make the linker link with the library, you need to use the -l (lower-case L) option to tell the linker which libraries you need to link with, like
gcc source.c -lxmlrpc
I believe that xml-rpc-c comes with a helper program, intended to help you get the linking right. Its documented here
http://xmlrpc-c.sourceforge.net/doc/xmlrpc-c-config.html
I just read about init and fini sections in ELF files and gave it a try:
#include <stdio.h>
int main(){
puts("main");
return 0;
}
void init(){
puts("init");
}
void fini(){
puts("fini");
}
If I do gcc -Wl,-init,init -Wl,-fini,fini foo.c and run the result the "init" part is not printed:
$ ./a.out
main
fini
Did the init part not run, or was it not able to print somehow?
Is there a any "official" documentation about the init/fini stuff?
man ld says:
-init=name
When creating an ELF executable or shared object, call
NAME when the executable or shared object is loaded, by
setting DT_INIT to the address of the function. By
default, the linker uses "_init" as the function to call.
Shouldn't that mean, that it would be enough to name the init function _init? (If I do gcc complains about multiple definition.)
Don't do that; let your compiler and linker fill in the sections as they see fit.
Instead, mark your functions with the appropriate function attributes, so that the compiler and linker will put them in the correct sections.
For example,
static void before_main(void) __attribute__((constructor));
static void after_main(void) __attribute__((destructor));
static void before_main(void)
{
/* This is run before main() */
}
static void after_main(void)
{
/* This is run after main() returns (or exit() is called) */
}
You can also assign a priority (say, __attribute__((constructor (300)))), an integer between 101 and 65535, inclusive, with functions having a smaller priority number run first.
Note that for illustration, I marked the functions static. That is, the functions won't be visible outside the file scope. The functions do not need to be exported symbols to be automatically called.
For testing, I suggest saving the following in a separate file, say tructor.c:
#include <unistd.h>
#include <string.h>
#include <errno.h>
static int outfd = -1;
static void wrout(const char *const string)
{
if (string && *string && outfd != -1) {
const char *p = string;
const char *const q = string + strlen(string);
while (p < q) {
ssize_t n = write(outfd, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1 || errno != EINTR)
break;
}
}
}
void before_main(void) __attribute__((constructor (101)));
void before_main(void)
{
int saved_errno = errno;
/* This is run before main() */
outfd = dup(STDERR_FILENO);
wrout("Before main()\n");
errno = saved_errno;
}
static void after_main(void) __attribute__((destructor (65535)));
static void after_main(void)
{
int saved_errno = errno;
/* This is run after main() returns (or exit() is called) */
wrout("After main()\n");
errno = saved_errno;
}
so you can compile and link it as part of any program or library. To compile it as a shared library, use e.g.
gcc -Wall -Wextra -fPIC -shared tructor.c -Wl,-soname,libtructor.so -o libtructor.so
and you can interpose it into any dynamically linked command or binary using
LD_PRELOAD=./libtructor.so some-command-or-binary
The functions keep errno unchanged, although it should not matter in practice, and use the low-level write() syscall to output the messages to standard error. The initial standard error is duplicated to a new descriptor, because in many instances, the standard error itself gets closed before the last global destructor -- our destructor here -- gets run.
(Some paranoid binaries, typically security sensitive ones, close all descriptors they don't know about, so you might not see the After main() message in all cases.)
It is not a bug in ld but in the glibc startup code for the main executable. For shared objects the function set by the -init option is called.
This is the commit to ld adding the options -init and -fini.
The _init function of the program isn't called from file glibc-2.21/elf/dl-init.c:58 by the DT_INIT entry by the dynamic linker, but called from __libc_csu_init in file glibc-2.21/csu/elf-init.c:83 by the main executable.
That is, the function pointer in DT_INIT of the program is ignored by the startup.
If you compile with -static, fini isn't called, too.
DT_INIT and DT_FINI should definitely not be used, because they are old-style, see line 255.
The following works:
#include <stdio.h>
static void preinit(int argc, char **argv, char **envp) {
puts(__FUNCTION__);
}
static void init(int argc, char **argv, char **envp) {
puts(__FUNCTION__);
}
static void fini(void) {
puts(__FUNCTION__);
}
__attribute__((section(".preinit_array"), used)) static typeof(preinit) *preinit_p = preinit;
__attribute__((section(".init_array"), used)) static typeof(init) *init_p = init;
__attribute__((section(".fini_array"), used)) static typeof(fini) *fini_p = fini;
int main(void) {
puts(__FUNCTION__);
return 0;
}
$ gcc -Wall a.c
$ ./a.out
preinit
init
main
fini
$
I created a program in C and I tried to compile it. When I use my gcc 4.8.1 compiler in Widows everything worked and my program too.
I compiled with the following arguments:
gcc -std=c99 -O2 -DCONTEST -s -static -lm children.c
But in linux I getting the following error:
/usr/lib/gcc/i486-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
collect2: error: ld returned 1 exit status
Why is that? My programm is working and I can't understand why I getting compiling errors in linux.
My code is:
/*---------------------*/
/* included files */
/*---------------------*/
#include <stdio.h>
#include <stdlib.h>
/*---------------------*/
/* defined constants */
/* for restriction */
/*---------------------*/
#define MIN 1
#define MAX 1000000
#define IOERROR 5 // 'Input/Output Error'
/*---------------------*/
/* function prototypes */
/*---------------------*/
int main();
FILE *read_input(const char *filename_r);
int count_children(FILE *input);
int pass_heights(FILE *input, int *children, int size);
int check_tall(const int *children, int size);
void write_output(const int total,const char *filename_w);
/*---------------------*/
/* start of program */
/*---------------------*/
int main() {
const char *filename_r = "xxx.in";
const char *filename_w = "xxx.out";
FILE *input = read_input(filename_r);
int size = count_children(input);
int *children = malloc(size * sizeof *children);
if (children==NULL)
exit(1); //General application error
pass_heights(input, children, size);
fclose(input);
int total = check_tall(children, size);
free(children);
write_output(total,filename_w);
return 0;
}
FILE *read_input(const char *filename_r) {
FILE *input = fopen(filename_r, "r");
if(input == NULL)
exit(IOERROR);
return input;
}
int count_children(FILE *input) {
int count = 0;
fscanf(input, "%d",&count);
if(count > MAX || count < MIN)
exit(1); //General application error
return count;
}
int pass_heights(FILE *input, int *children, int size) {
for(int i = 0; i < size; i++)
fscanf(input, "%d",&children[i]);
return *children;
}
int check_tall(const int *children, int size) {
int total = 0;
int tmp_max = 0;
for(int i = size - 1; i >= 0; i--)
{
if(children[i] > tmp_max) {
tmp_max = children[i];
total++;
}
}
return total;
}
void write_output(const int total,const char *filename_w) {
FILE *output = fopen(filename_w, "w");
if(output == NULL)
exit(IOERROR);
fprintf(output, "%d\n", total);
fclose(output);
}
You used -static option, which modifies the way executable is linked.
I was unable to reproduce your exact error message, but on my Linux it says that it is unable to link with -lc in static mode, and under my OSX it says that it is unable to locate -lcrt0.o. For me in both case, this means that the system is unable to locate the static stub.
If you remove -static it should work. If not, your problem is very strange.
The error you show indicates the linker is not finding the main() function in your code. As it is evident that you have included it in the source file, it is also evident you are not compiling with that command line (or you are compiling in other directory where you have a non-main() source called children.c, perhaps the build system makes a touch children.c if it doesn't find the source, and then compiles it --on that case it will not have a main() routine). Check that the files are properly created and where, as I think you aren't compiling that file anyway.
Try to use simple options before you go to more complicated ones. Try something like:
gcc -std=c99 -o children children.c
before trying to experiment with optimization or static linking anyway. Also, dynamic linking is normally better than static, so you'll get smaller executables (8Kb vs. 800Kb, and multiple copies of libc loaded per executable). Also, you don't need to include -lm as you aren't using any of the <math.h> functions (having it doesn't hurt anyway).
I have compiled your source with the following command line without any problem, but I do have support for statically linked executables and perhaps you don't (the command line I have put above would work in any linux, I suppose)
$ make CC='gcc' CFLAGS='-std=c99 -O2 -DCONTEST' LDFLAGS='-s -static -lm' children
gcc -std=c99 -O2 -DCONTEST -s -static -lm children.c -o children
children.c: In function ‘pass_heights’:
children.c:81:11: warning: ignoring return value of ‘fscanf’, declared with attribute warn_unused_result [-Wunused-result]
children.c: In function ‘count_children’:
children.c:69:11: warning: ignoring return value of ‘fscanf’, declared with attribute warn_unused_result [-Wunused-result]
When loaded a shared library is opened via the function dlopen(), is there a way for it to call functions in main program?
Code of dlo.c (the lib):
#include <stdio.h>
// function is defined in main program
void callb(void);
void test(void) {
printf("here, in lib\n");
callb();
}
Compile with
gcc -shared -olibdlo.so dlo.c
Here the code of the main program (copied from dlopen manpage, and adjusted):
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void callb(void) {
printf("here, i'm back\n");
}
int
main(int argc, char **argv)
{
void *handle;
void (*test)(void);
char *error;
handle = dlopen("libdlo.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
*(void **) (&test) = dlsym(handle, "test");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
exit(EXIT_FAILURE);
}
(*test)();
dlclose(handle);
exit(EXIT_SUCCESS);
}
Build with
gcc -ldl -rdynamic main.c
Output:
[js#HOST2 dlopen]$ LD_LIBRARY_PATH=. ./a.out
here, in lib
here, i'm back
[js#HOST2 dlopen]$
The -rdynamic option puts all symbols in the dynamic symbol table (which is mapped into memory), not only the names of the used symbols. Read further about it here. Of course you can also provide function pointers (or a struct of function pointers) that define the interface between the library and your main program. It's actually the method what i would choose probably. I heard from other people that it's not so easy to do -rdynamic in windows, and it also would make for a cleaner communication between library and main program (you've got precise control on what can be called and not), but it also requires more house-keeping.
Yes, If you provide your library a pointer to that function, I'm sure the library will be able to run/execute the function in the main program.
Here is an example, haven't compiled it so beware ;)
/* in main app */
/* define your function */
int do_it( char arg1, char arg2);
int do_it( char arg1, char arg2){
/* do it! */
return 1;
}
/* some where else in main app (init maybe?) provide the pointer */
LIB_set_do_it(&do_it);
/** END MAIN CODE ***/
/* in LIBRARY */
int (*LIB_do_it_ptr)(char, char) = NULL;
void LIB_set_do_it( int (*do_it_ptr)(char, char) ){
LIB_do_it_ptr = do_it_ptr;
}
int LIB_do_it(){
char arg1, arg2;
/* do something to the args
...
... */
return LIB_do_it_ptr( arg1, arg2);
}
The dlopen() function, as discussed by #litb, is primarily provided on systems using ELF format object files. It is rather powerful and will let you control whether symbols referenced by the loaded library can be satisfied from the main program, and generally does let them be satisfied. Not all shared library loading systems are as flexible - be aware if it comes to porting your code.
The callback mechanism outlined by #hhafez works now that the kinks in that code are straightened out.