Undefined function sensing - c

I am trying to do this (is this possible?) with GCC compiler:
Specifiy a function but this function if is not implemented point to a NULL. Example:
extern void something(uint some);
And if this is unimplemented point to a NULL value.
So it's possible check like this:
something != NULL ? something(222) : etc.;
I would like solution with trough GCC (this could be solvable with function pointers).

This is definitely not portable, but gcc can do this with weak symbols on some platforms. I know this works on Linux and *BSD, but doesn't work on MacOS.
$ cat weak.c
#include <stdio.h>
extern int foo(void) __attribute__((__weak__));
int
main(int argc, char **argv)
{
int x = foo ? foo() : 42;
printf("%d\n", x);
return 0;
}
$ cat weak2.c
int
foo(void)
{
return 17;
}
$ cc -o weak weak.c && ./weak
42
$ cc -o weak weak.c weak2.c && ./weak
17
$

You can do this using GCC's weakref attribute:
extern void something(int);
static void something_else(int) __attribute__((weakref("something")));
int main()
{
if (something_else)
something_else(122);
}
If something is not defined in the program then the weak alias something_else will have an address of zero. If something is defined, something_else will be an alias for it.

Essentially you are trying to get the compiler to locate a function at the memory address 0 (NULL). This cannot be done in C without platform/compiler specific constructs.
One question though, is why you would ever want to do this. C is a static language, so if you know that the function will never exist during compilation you might as well just use the pre-processor to tell the rest of the program about this at compile time. Indeed these sorts of compile time substitutions are precisely why the preprocessor is there in the first place.
I would create a macro that you define if your function exists as follows:
#define THE_SOMETHING_FUNCTION_EXISTS
Then replace anywhere you would have tested for something == NULL with an #ifdef instead.
Of course, if the function’s existence might change at run-time then the correct way to implement the behaviour you want is to make something a function pointer.

Related

changing extern function pointer to extern pointer using preprocessor

I am using library that I shouldn't change it files, that including my h file.
the code of the library looks somthing like like:
#include "my_file"
extern void (*some_func)();
void foo()
{
(some_func)();
}
my problem is that I want that some_func will be extern function and not extern pointer to function (I am implementing and linking some_func). and that how main will call it.
that way I will save little run time and code space, and no one in mistake will change this global.
is it possible?
I thought about adding in my_file.h somthing as
#define *some_func some_func
but it won't compile because asterisk is not allowed in #define.
EDIT
The file is not compiled already, so changes at my_file.h will effect the compilation.
First of all, you say that you can't change the source of the library. Well, this is bad, and some "betrayal" is necessary.
My approach is to let the declaration of the pointer some_func as is, a non-constant writable variable, but to implement it as constant non-writable variable, which will be initialized once for all with the wanted address.
Here comes the minimal, reproducible example.
The library is implemented as you show us:
// lib.c
#include "my_file"
extern void (*some_func)();
void foo()
{
(some_func)();
}
Since you have this include file in the library's source, I provide one. But it is empty.
// my_file
I use a header file that declares the public API of the library. This file still has the writable declaration of the pointer, so that offenders believe they can change it.
// lib.h
extern void (*some_func)();
void foo();
I separated an offending module to try the impossible. It has a header file and an implementation file. In the source the erroneous assignment is marked, already revealing what will happen.
// offender.h
void offend(void);
// offender.c
#include <stdio.h>
#include "lib.h"
#include "offender.h"
static void other_func()
{
puts("other_func");
}
void offend(void)
{
some_func = other_func; // the assignment gives a run-time error
}
The test program consists of this little source. To avoid compiler errors, the declaration has to be attributed as const. Here, where we are including the declarating header file, we can use some preprocessor magic.
// main.c
#include <stdio.h>
#define some_func const some_func
#include "lib.h"
#undef some_func
#include "offender.h"
static void my_func()
{
puts("my_func");
}
void (* const some_func)() = my_func;
int main(void)
{
foo();
offend();
foo();
return 0;
}
The trick is, that the compiler places the pointer variable in the read-only section of the executable. The const attribute is just used by the compiler and is not stored in the intermediate object files, and the linker happily resolves all references. Any write access to the variable will generate a runtime error.
Now all of this is compiled in an executable, I used GCC on Windows. I did not bother to create a separated library, because it doesn't make a difference for the effect.
gcc -Wall -Wextra -g main.c offender.c lib.c -o test.exe
If I run the executable in "cmd", it just prints "my_func". Apparently the second call of foo() is never executed. The ERRORLEVEL is -1073741819, which is 0xC0000005. Looking up this code gives the meaning "STATUS_ACCESS_VIOLATION", on other systems known as "segmentation fault".
Because I deliberately compiled with the debugging flag -g, I can use the debugger to examine more deeply.
d:\tmp\StackOverflow\103> gdb -q test.exe
Reading symbols from test.exe...done.
(gdb) r
Starting program: d:\tmp\StackOverflow\103\test.exe
[New Thread 12696.0x1f00]
[New Thread 12696.0x15d8]
my_func
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00000000004015c9 in offend () at offender.c:16
16 some_func = other_func;
Alright, as I intended, the assignment is blocked. However, the reaction of the system is quite harsh.
Unfortunately we cannot get a compile-time or link-time error. This is because of the design of the library, which is fixed, as you say.
You could look at the ifunc attribute if you are using GCC or related. It should patch a small trampoline at load time. So when calling the function, the trampoline is called with a known static address and then inside the trampoline there is a jump instruction that was patched with the real address. So when running, all jump locations are directly in the code, which should be efficient with the instruction cache. Note that it might even be more efficient than this, but at most as bad as calling the function pointer. Here is how you would implement it:
extern void (*some_func)(void); // defined in the header you do not have control about
void some_func_resolved(void) __attribute__((ifunc("resolve_some_func")));
static void (*resolve_some_func(void)) (void)
{
return some_func;
}
// call some_func_resolved instead now

Is it possible to declare a weak function by passing an argument to gcc?

We can declare weak function by using __attribute__((weak)) in C code files. I wonder if there exists a way to declare this during compile time from gcc and not write anything in the code files?
For e.g.
File: foo.h
int foo();
File: foo.c
#include<stdio.h>
int foo(){
printf("foo called from file\n");
return 1;
}
File: main.c
#include<stdio.h>
#include"foo.h"
int foo(){
printf("foo called from main");
return 1;
}
int main(){
foo();
return 0;
}
Is it possible to compile above code and export foo as weak from command line?
E.g. gcc --weak=foo.c:foo foo.c main.c
./a.out produces foo called from main.
I know that writing__attribute__((weak)) above foo() declaration in foo.c will call foo() in main.
The blog:
blog.microjoe.org/2017/unit-tests-c-cmocka-coverage-cmake.html
says that it is possible to do so....
There are two ways of declaring a weak symbol:
By passing an argument to GCC, telling it to export the symbol of this function as a weak symbol.
By putting a attribute((weak)) annotation before the function implementation.
I would say no, there is no such option.
This sounds a little bit like an XY-problem, perhaps you should state more clearly what problem you are trying to solve, instead of which solution you want to make work.
As an aside, your example would not work, since you're providing two definitions and not saying which one should be considered weak. It would have to be
# Remember this doesn't really work!
$ gcc --weak=foo.c:foo foo.c main.c
or something, i.e. you need to indicate in which file the weak definition resides.

Detect -nostdlib or just detect whether stdlib is available or not

I have a homework assignment that requires us to open, read and write to file using system calls rather than standard libraries. To debug it, I want to use std libraries when test-compiling the project. I did this:
#ifdef HOME
//Home debug prinf function
#include <stdio.h>
#else
//Dummy prinf function
int printf(const char* ff, ...) {
return 0;
}
#endif
And I compile it like this: gcc -DHOME -m32 -static -O2 -o main.exe main.c
Problem is that I with -nostdlib argument, the standard entry point is void _start but without the argument, the entry point is int main(const char** args). You'd probably do this:
//Normal entry point
int main(const char** args) {
_start();
}
//-nostdlib entry point
void _start() {
//actual code
}
In that case, this is what you get when you compile without -nostdlib:
/tmp/ccZmQ4cB.o: In function `_start':
main.c:(.text+0x20): multiple definition of `_start'
/usr/lib/gcc/i486-linux-gnu/4.7/../../../i386-linux-gnu/crt1.o:(.text+0x0): first defined here
Therefore I need to detect whether stdlib is included and do not define _start in that case.
The low-level entry point is always _start for your system. With -nostdlib, its definition is omitted from linking so you have to provide one. Without -nostdlib, you must not attempt to define it; even if this didn't get a link error from duplicate definition, it would horribly break the startup of the standard library runtime.
Instead, try doing it the other way around:
int main() {
/* your code here */
}
#ifdef NOSTDLIB_BUILD /* you need to define this with -D */
void _start() {
main();
}
#endif
You could optionally add fake arguments to main. It's impossible to get the real ones from a _start written in C though. You'd need to write _start in asm for that.
Note that -nostdlib is a linker option, not compile-time, so there's no way to automatically determine at compile-time that that -nostdlib is going to be used. Instead just make your own macro and pass it on the command line as -DNOSTDLIB_BUILD or similar.

How can I cast an char array to a function pointer in C?

Is it possible to assign with cast to a function pointer a string or char array and then run it?
I have defined a few functions int f1();, int f2();, and so on
In the main() function I have read a string fct_name and declared a pointer to function int (*pv)();
I need to do something like this:
the fct_name can have values "f1" , "f2" and so on..
pv = (some sort of cast)fct_name;
pv();
My point is I want to avoid conditional instructions in favor of direct assignment (because I have a large number of functions in my program)
The code must obviously run.
Assuming you don't have an external library and are trying to call functions declared in your executable, you can do a lookup yourself
#define REGISTER_FUNC(name) {#name, name}
struct funclist
{
const char* name;
void (*fp)(void); //or some other signature
};
struct funclist AllFuncs[] = {
REGISTER_FUNC(f1),
REGISTER_FUNC(f2),
REGISTER_FUNC(f3),
{NULL,NULL} //LAST ITEM SENTINEL
};
Now you can lookup your variable fct_name in AllFuncs. You can use a linear search if the number is small, or insert them all into a hash table for O(1) lookup.
Alternately, if your names really are f1, f2, etc. you can just do
void (*FuncList)(void)[] = {NULL, f1,f2,f3};
...
int idx = atol(fct_name+1);
if (idx && idx < MAX_FUNCS)
FuncList[idx]();
A variant of Carey's answer, in case you're on a *nix system. dlopen() opens up your library. RTLD_LAZY tells the loader to not bother resolving all the library's symbols right away, and to wait for you to try to access them. dlsym() looks up the symbol in question.
Edit: Updated the snippet to better fit your clarification:
#include <dlfcn.h>
int main(int argc, char *argv[])
{
void *handle = dlopen("libexample.so", RTLD_LAZY);
if (handle == NULL) {
// error
}
char fct_name[64];
// read input from terminal here
void *func = dlsym(handle, fct_name);
if (func != NULL) {
// call function here; need to cast as appropriate type
}
}
libexample.so would be a library with your functions, compiled as a shared library, like so:
gcc -Wall -o libexample.so example.c -shared -fPIC
That being said, if you're going to the trouble of compiling a shared library like this, you'll probably just want to call the functions in your binary. You can do that if you link your library in at compile-time:
gcc -Wall -o test test.c -L. -lexample
-L. tells the linker to look for libraries in the current directory (.) and -lexample tells it to link with a library named "libexample.so". If you do this, you can just call the library functions directly within your program.
You can't cast a char array to a function just because the array happens to contain the name of a function. What you need to do is put your function(s) in a DLL and then do this:
HMODULE dll = LoadLibrary("foo.dll");
pv func = (pv)GetProcAddress(module, fct_name);

How to make this code compile?

// File: foo.c
static int var;
void foo()
{
var++;
}
// end of file foo.c
// File bar.c:
static int var;
void bar()
{
var++;
}
// end of file bar.c
// file main.c
static int var;
void main()
{
foo();
bar();
printf("%d", var);
}
// end of file main.c
Question: Will the above program compile ? If so what will be the result ?
I tested the code and found it couldn't be compiled. I try to use extern in main.c to use the function foo() and bar() but it still couldn't be compiled.
main.c has a few minor problems - it should be something like this:
#include <stdio.h>
static int var;
extern void foo();
extern void bar();
int main(void)
{
foo();
bar();
printf("%d\n", var);
return 0;
}
It should build OK like this:
$ gcc -Wall main.c foo.c bar.c -o main
and the result should be:
$ ./main
0
I would expect it to compile and print 0 (though if you want to compile it as C++, you'll have to add declarations for foo() and bar(), and in either C or C++, you might get a warning that main() should really return an int).
Since var is defined as static in each of the three files, you really have three separate variables that all happen to have the same name. Perhaps it's easiest to think of each file as defining a struct that contains its static variables. What you've done is called foo(), which increments foo.var. Then you've called bar(), which increments bar.var. Then you've printed out main.var, which was initialized to zero, and never modified.
This compiles for me (although with a warning about the return type from main()).
The result, in terms of what main() will print, is undetermined because you have not initialized the value of var in main.c. The most likely result when the compiler is invoked without optimizations is zero because the OS will have zeroed the physical memory supplied to the process for data storage (the OS does this to avoid leaking confidential data between processes).
The static qualifier to the var variable definitions means that the variable is not visible outside the source file it is defined in. It also means that each of the three var variables gets its own storage location.
If we add a printf("[module name] *var=%p\n", &var) to foo(), bar() and main() respectively to print the address of the memory location that stores those three variables you should get something like this:-
foo() *var=0x8049620
bar() *var=0x8049624
main() *var=0x8049628
Note that each variable gets its own storage location. The code in each source file will access the version of var that is specific to to that source file. Using static like this in .c files is typically used to implement the concept of information hiding in C.
The code (as it is) will compile and result will be 0 (as Jerry explains) because static variable will have file scope.
But, if you include foo.c and bar.c in main.c, and compile as
gcc main.c
then the result will be 2 because there will only be one global variable var.

Resources