Silent symbol collision? - c

Posted on the Raspberry Stackexchange before, closed as off-topic, so here I am.
The following program compiles cleanly with gcc main.c -lpigpio -lpthread -Wall -Wextra. I'm using gcc 8.3.0 (crosscompiler or normal compiler doesn't change anything).
// main.c
#include <stdio.h>
#include <pigpio.h>
void listen() {
printf("hi from listen\n");
}
int main() {
gpioInitialise();
printf("hi from main\n");
gpioTerminate();
return 0;
}
No warnings, yet the program happily prints
hi from listen
hi from main
The cause seems to be that gpioInitialise() tries to call listen(2) from <sys/sockets.h> here, but instead calls the function from main.c. Of course, this doesn't work and results in an error message from the pigpio library:
xxxx-xx-xx xx:xx:xx pthSocketThread: setsockopt() fail, closing socket -1
xxxx-xx-xx xx:xx:xx pthSocketThread: accept failed (Bad file descriptor)
Question: How come that gcc links a function with a completly different signature without throwing any errors? I know about static, but I want to make sense of this to learn from it. Surely it can't be as simple as listen(2) not being declared as static?

Linker allows you to interpose symbols like this for debugging, profiling, etc. purposes. Unfortunately at link stage the typing information is generally not available so linker can not perform any sanity checking to verify that expected and actual signatures match. One might argue that with -g this would be possible but noone cared enough to implement this (this might be a good home project though).
Static would help in your case because it would prevent listen from being exported and libc's listen from being overridden.
As a side note, on ELF systems (Linux) situation is ever worse because they allow runtime symbol interposition (i.e. libraries compete for who wins over symbol names at program startup). This is typically resolved with static or -fvisiblity=hidden (unfortunately many libraries do not use them).

Related

Resolve undefined reference by stripping unused code

Assume we have the following C code:
void undefined_reference(void);
void bad(void) {
undefined_reference();
}
int main(void) {}
In function bad we fall into the linker error undefined reference to 'undefined_reference', as expected. This function is not actually used anywhere in the code, though, and as such, for the execution of the program, this undefined reference doesn't matter.
Is it possible to compile this code successfully, such that bad simply gets removed as it is never called (similar to tree-shaking in JavaScript)?
This function is not actually used anywhere in the code!
You know that, I know that, but the compiler doesn't. It deals with one translation unit at a time. It cannot divine out that there are no other translation units.
But main doesn't call anything, so there cannot be other translation units!
There can be code that runs before and after main (in an implementation-defined manner).
OK what about the linker? It sees the whole program!
Not really. Code can be loaded dynamically at run time (also by code that the linker cannot see).
So neither the compiler nor linker even try to find unused function by default.
On some systems it is possible to instruct the compiler and the linker to try and garbage-collect unused code (and assume a whole-program view when doing so), but this is not usually the default mode of operation.
With gcc and gnu ld, you can use these options:
gcc -ffunction-sections -Wl,--gc-sections main.c -o main
Other systems may have different ways of doing this.
Many compilers (for example gcc) will compile and link it correctly if you
Enable optimizations
make function bad static. Otherwise, it will have external linkage.
https://godbolt.org/z/KrvfrYYdn
Another way is to add the stump version of this function (and pragma displaying warning)

Prevent my C code from printing (seriously slows down the execution)

I have an issue.
I finally found a way to use an external library to solve my numerical systems. This library automatically prints the matrices. It is fine for dim=5, but for dim=1.000.000, you understand the problem...
Those parasite "printf"s slow down considerably the execution, and I would like to get rid of them. The problem is: I don't know where they are ! I looked in every ".h" and ".c" file in my library: they are nowhere to be found.
I suspect they already are included in the library itself: superlu.so. I can't access them, thus.
How could I possibly prevent my C code from printing anything during the execution ?
Here is my Makefile. I use the libsuperlu-dev library, directly downloaded from Ubuntu. The .so file was already there.
LIB = libsuperlu.so
main: superlu.o read_file.o main.o sample_arrays.o super_csr.o
cc $^ -o $# $(LIB)
clean:
rm *.o
rm main
Just to explain the LD_PRELOAD method that was mentioned, that I use sometimes precisely for that usage (or, on the contrary to add some printf, for example, when I want to pipe the output of a GUI), here is how you can do a rudimentary version of it
myprint.c:
int printf(char *, ...){
return 0;
}
int putchar(int){
return 0;
}
Then
gcc -shared -std=gnu99 -o myprint.so myprint.c
Then
LD_PRELOAD=./myprint.so ./main
Forces the load of your printf and putchar symbols before any other library has the opportunity to load them force. So, no printing occurs. At least none with printf. But you may have to add some other functions to the list, such as fprintf, fputc, fputs, puts, ...
And of course, another problem of overloading the fthing functions (and even possibly the others), is that you might also prevent some wanted behavior. Such as writing files. Or interacting with some devices.
It may be even worse if those printing are done with low level write function. That one, you very likely can't afford to overload (unless you overload it with a function that calls the real write, loaded manually by dlopen) filtering only the ones that you want to avoid, based on target file descriptor (1) or on content of written data.
Note: if you want to verify if the libsuperlu.so is responsible of those printing, you can check with nm libsuperlu.so if it is referring to some well known printing functions, such as printf

I have not included the <unistd.h> header file, why can I still invoke the getpid() function successfully?

Code as below:
int main (int argc, char *argv[]) {
long pid = (long)getpid();
long test = pid + 1;
}
Have not included any head files, still can compile code successfully and still can run program successfully.
Why?
Environment info: Ubuntu 18.04.2 LTS, gcc (Ubuntu 4.8.5-4ubuntu8) 4.8.5
Have not included any head files,still can compile code successfully.
still can run program successfuly.Why?
Why not?
All question of whether the particular code presented conforms to the language standard notwithstanding, language non-conformance does not imply that compilation or execution must fail. Instead, you get undefined behavior, which can manifest in any manner within the power of the machine to produce, including compiling successfully and running as intended.
In your particular case, however, you are using GCC 4.8.5. The GCC 4.8 series defaults to compiling for the C90 standard, with GNU extensions. C90 allows calls to functions with no in-scope declaration, for compatibility with earlier, pre-standardization practice. That is no longer allowed in C99 or later, but many implementations nevertheless continue to accept it as an extension.
It should be understood, however, that C interprets some argument lists differently when the called function has an in-scope prototype than when it doesn't (which may be the case even for functions that are declared, because not all declarations provide prototypes). You may be able to get away with calling undeclared functions under some circumstances, but it is poor style, and if you do it enough then it will bite you at some point.
Note also that GCC 4 definitely has the ability to emit warnings about usage such as yours, even when compiling in C90 or GNU90 mode. You would be well served to turn on the -Wall option when you compile, and maybe additional warning options as well.
Normally, to use a dynamic library function you would have to link against the specified library at compile time through the -l switch, like for example gcc -lm prog.c when using the mathematic functions (from libm).
However, since it's so common, GCC always links the standard C library by default, meaning that doing gcc prog.c is actually the same as doing gcc -lc prog.c. This is always done whether you include any header or not.
The second thing that makes this work, is that GCC assumes any function that has not been declared at compile time to have the signature int func(void). In this case, the signature is quite similar to the one of the real getpid() function.
If you take a look at your compiled program with the ldd tool to show which dynamic libraries are required, you'll see that the program is linked against libc:
$ ldd prog
linux-vdso.so.1 (0x00007ffede7d0000)
==> libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0f47018000)
/lib64/ld-linux-x86-64.so.2 (0x00007f0f475b9000)
When your program runs, it asks the dynamic loader where (at which address) to find the getpid function before calling it the first time. The dynamic loaders checks the loaded libraries, and finds a function with that name in libc, so everything seems to work without a problem.
You can tell GCC to not link against the standard library by default using the -nostdlib compiler switch, but this is not that useful in your case. The real solution is to always treat warnings about implicit function declarations as errors (-Werror=implicit-function-declaration).
If your compiler doesn't give this warning by default, I would suggest you to upgrade it to a newer version. GCC 4 is definitely not the latest version available for Ubuntu 18.
$ sudo apt update
$ sudo apt upgrade

Redirecting assert fail messages

We have a software project with real-time constraints largely written in C++ but making use of a number of C libraries, running in a POSIX operating system. To satisfy real-time constraints, we have moved almost all of our text logging off of stderr pipe and into shared memory ring buffers.
The problem we have now is that when old code, or a C library, calls assert, the message ends up in stderr and not in our ring buffers with the rest of the logs. We'd like to find a way to redirect the output of assert.
There are three basic approaches here that I have considered:
1.) Make our own assert macro -- basically, don't use #include <cassert>, give our own definition for assert. This would work but it would be prohibitively difficult to patch all of the libraries that we are using that call assert to include a different header.
2.) Patch libc -- modify the libc implementation of __assert_fail. This would work, but it would be really awkward in practice because this would mean that we can't build libc without building our logging infra. We could make it so that at run-time, we can pass a function pointer to libc that is the "assert handler" -- that's something that we could consider. The question is if there is a simpler / less intrusive solution than this.
3.) Patch libc header so that __assert_fail is marked with __attribute__((weak)). This means that we can override it at link-time with a custom implementation, but if our custom implementation isn't linked in, then we link to the regular libc implementation. Actually I was hoping that this function already would be marked with __attribute__((weak)) and I was surprised to find that it isn't apparently.
My main question is: What are the possible downsides of option (3) -- patching libc so that this line: https://github.com/lattera/glibc/blob/master/assert/assert.h#L67
extern void __assert_fail (const char *__assertion, const char *__file,
unsigned int __line, const char *__function)
__THROW __attribute__ ((__noreturn__));
is marked with __attribute__((weak)) as well ?
Is there a good reason I didn't think of that the maintainers didn't already do this?
How could any existing program that is currently linking and running successfully against libc break after I patch the header in this way? It can't happen, right?
Is there a significant run-time cost to using weak-linking symbols here for some reason? libc is already a shared library for us, and I would think the cost of dynamic linking should swamp any case analysis regarding weak vs. strong resolution that the system has to do at load time?
Is there a simpler / more elegant approach here that I didn't think of?
Some functions in glibc, particularly, strtod and malloc, are marked with a special gcc attribute __attribute__((weak)). This is a linker directive -- it tells gcc that these symbols should be marked as "weak symbols", which means that if two versions of the symbol are found at link time, the "strong" one is chosen over the weak one.
The motivation for this is described on wikipedia:
Use cases
Weak symbols can be used as a mechanism to provide default implementations of functions that can be replaced by more specialized (e.g. optimized) ones at link-time. The default implementation is then declared as weak, and, on certain targets, object files with strongly declared symbols are added to the linker command line.
If a library defines a symbol as weak, a program that links that library is free to provide a strong one for, say, customization purposes.
Another use case for weak symbols is the maintenance of binary backward compatibility.
However, in both glibc and musl libc, it appears to me that the __assert_fail function (to which the assert.h macro forwards) is not marked as a weak symbol.
https://github.com/lattera/glibc/blob/master/assert/assert.h
https://github.com/lattera/glibc/blob/master/assert/assert.c
https://github.com/cloudius-systems/musl/blob/master/include/assert.h
You don't need attribute((weak)) on symbol __assert_fail from glibc. Just write your own implementation of __assert_fail in your program, and the linker should use your implementation, for example:
#include <stdio.h>
#include <assert.h>
void __assert_fail(const char * assertion, const char * file, unsigned int line, const char * function)
{
fprintf(stderr, "My custom message\n");
abort();
}
int main()
{
assert(0);
printf("Hello World");
return 0;
}
That's because when resolving symbols by the linker the __assert_fail symbol will already be defined by your program, so the linker shouldn't pick the symbol defined by libc.
If you really need __assert_fail to be defined as a weak symbol inside libc, why not just objcopy --weaken-symbol=__assert_fail /lib/libc.so /lib/libc_with_weak_assert_fail.so. I don't think you need to rebuild libc from sources for that.
If I were you, I would probably opt for opening a pipe(2) and fdopen(2)'ing stderr to take the write end of that pipe. I'd service the read end of the pipe as part of the main poll(2) loop (or whatever the equivalent is in your system) and write the contents to the ring buffer.
This is obviously slower to handle actual output, but from your write-up, such output is rare, so the impact ought to be negligable (especially if you already have a poll or select this fd can piggyback on).
It seems to me that tweaking libc or relying on side-effects of the tools might break in the future and will be a pain to debug. I'd go for the guaranteed-safe mechanism and pay the performance price if at all possible.

Compiling without libc

I want to compile my C-code without the (g)libc. How can I deactivate it and which functions depend on it?
I tried -nostdlib but it doesn't help: The code is compilable and runs, but I can still find the name of the libc in the hexdump of my executable.
If you compile your code with -nostdlib, you won't be able to call any C library functions (of course), but you also don't get the regular C bootstrap code. In particular, the real entry point of a program on Linux is not main(), but rather a function called _start(). The standard libraries normally provide a version of this that runs some initialization code, then calls main().
Try compiling this with gcc -nostdlib -m32:
// Tell the compiler incoming stack alignment is not RSP%16==8 or ESP%16==12
__attribute__((force_align_arg_pointer))
void _start() {
/* main body of program: call main(), etc */
/* exit system call */
asm("movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
__builtin_unreachable(); // tell the compiler to make sure side effects are done before the asm statement
}
The _start() function should always end with a call to exit (or other non-returning system call such as exec). The above example invokes the system call directly with inline assembly since the usual exit() is not available.
The simplest way to is compile the C code to object files (gcc -c to get some *.o files) and then link them directly with the linker (ld). You will have to link your object files with a few extra object files such as /usr/lib/crt1.o in order to get a working executable (between the entry point, as seen by the kernel, and the main() function, there is a bit of work to do). To know what to link with, try linking with the glibc, using gcc -v: this should show you what normally comes into the executable.
You will find that gcc generates code which may have some dependencies to a few hidden functions. Most of them are in libgcc.a. There may also be hidden calls to memcpy(), memmove(), memset() and memcmp(), which are in the libc, so you may have to provide your own versions (which is not hard, at least as long as you are not too picky about performance).
Things might get clearer at times if you look at the produced assembly (use the -S flag).

Resources