I have a main function, but when tcc goes to link everything together, it says its undefined. Why is this?
I'm using a python build script, and arguments are passed as lists:
['v:/exe/tcc/tcc.exe', '-odist/***.exe', '-Llib/', '-llua5.1', '-lsoil', '-lSDL', '-lopengl32', 'build/luainterface\\msL.o', 'build/luainterface\\vector.o', 'build/rendering\\renderutil.o', 'build/structures\\crtree.o', 'build/structures\\uniqueid.o', 'build/structures\\vector.o', 'build/world\\blocklib.o', 'build/world\\chunk.o', 'build/world\\world.o', 'build/main.o']
The output is simply:
tcc: undefined symbol 'main'
My main function is defined in the file main.c (and doesn't have a header), with a couple of static functions.
Main function:
int main(int argc, char *argv[])
{
SDL_Surface* screen = render_initialize(1024,768);
lua_State* L = luaL_newstate();
//lua_atpanic(L,&Lpanic);
msL_registerState(L);
msL_openAllLibs(L);
int fail = luaL_dofile(L,"lua/main.luac");
if(fail)
{
fprintf(stderr, "Lua error: %s\n", lua_tostring(L,-1));
doexit(1);
}
lua_getfield(L,LUA_GLOBALSINDEX,"draw");
if(!lua_isfunction(L,-1))
{
lua_pop(L,1);
fprintf(stderr, "No draw function defined in global scope\n");
doexit(1);
}
lua_setfield(L,LUA_REGISTRYINDEX,"msL_drawfunction");
while(1)
{
lua_getfield(L,LUA_REGISTRYINDEX,"msL_drawfunction");
assert(lua_isfunction(L,-1));
int err = lua_pcall(L,0,0,0);
if(err)
{
fprintf(stderr,"Lua error: ");
switch(err)
{
case LUA_ERRRUN:
fprintf(stderr,"%s",lua_tostring(L,-1));
break;
case LUA_ERRMEM:
fprintf(stderr,"out of memory");
break;
default:
fprintf(stderr,"unknown error");
}
fprintf(stderr,"\n");
doexit(1);
}
render_flipbuffers(screen);
}
doexit(0);
}
EDIT: I ran the code through tcc with preprocessing only. Apparently the main function is being renamed to SDL_main, through some macro in SDL.
Add -lSDLmain to linker flags.
http://wiki.libsdl.org/moin.cgi/FAQWindows#I_get_.22Undefined_reference_to_.27WinMain.4016.27.22
Although things may be a little different in tcc.
Related
I'm trying to find a method to, from a program, check the presence of one or more ".c" files and load one or more functions of it.
Basically, I would have a "main" program which will check if the "script.c" file exists, and will launch (if it exists) the main() function of this one.
Here is the content of my "main" program before compilation:
int main(int argc, char *argv[]){
...
if(argc == 1){
FILE *file;
if((file = fopen("script.c", "r"))){
printf("file script.c loaded.");
// to compile the script.c file and modify on it the "main()" function to "_main()" (in order to be able to recompile it with the main library) before restarting the program
int ret = system("gcc -c script.c && objcopy --redefine-sym main=_main script.o && gcc main script.o -o main && ./main -l script.o");
printf("ret(0)=%d\n", ret);
}
else{
int ret = system("./main -l");
printf("ret(1)=%d\n", ret);
}
}
else{
if(argc == 3 && strcmp(argv[2], "script.o") == 0){
_main(argc, argv);
}
else{
printf("no file found.\n");
}
}
...
}
He is the content of my "script.c" file:
int main(int argc, char *argv[]){
...
printf("main() function in script.c loaded.\n");
...
}
If the script.c file exists, running main should give:
file script.c loaded.
ret(0)=0
main() function in script.c loaded.
If the script.c file does not exist, running main should give:
file script.c loaded.
ret(1)=0
no file found.
Obviously, this does not work for several reasons.
It is impossible to use the "main" program to recompile the script.o file (especially since this is supposed to be in use)
It is impossible to compile my "main" program with a _main() function that does not exist (on the 1st launch, and potentially on the second too if script.c dont found)
Do you have an idea for me to achieve my goal ?
So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...
PS: Having already seen it in other projects, I know it's possible, but I can't find the solution.
PS2: Only the executable file (main) and potentially the script.c file must be present (therefore no main.c...which therefore perhaps suggests that a "main" file should be merged with the "main.o" associated which would be unpacked and executed)
So from a single executable program (here "main") to be able to check the presence of an external file (here "script.c") and launch one or more functions from it...
I'm going to make an assumption that the main function you mentioned is not the most important and show how you can, from within your program, compile collections of functions into shared libraries that you load and then execute functions (other than main) in.
A simple driver could look like this:
// driver.c
#include <dlfcn.h> // to be able to dynamically load shared libraries
#include <stdio.h>
#include <stdlib.h>
// the signature of the `start` function you decide to have in all the files:
typedef void(*start_func_t)(void);
int main(int argc, char *argv[]){
char sys[1024];
for(int i = 1; i < argc; ++i) { // loop through all the arguments
// try to compile the argument into an object file
// (use a safer version than sprintf in real code)
sprintf(sys, "gcc -fPIC -c -o %s.o %s", argv[i], argv[i]);
if(system(sys)) {
printf("%d failed\n", sys);
exit(1);
}
// try to create a shared library from the object file
sprintf(sys, "gcc -shared -o libcurrent.so %s.o", argv[i]);
if(system(sys)) {
printf("%d failed\n", sys);
exit(1);
}
// load the shared library you just created
(void)dlerror();
void *handle = dlopen("./libcurrent.so", RTLD_NOW | RTLD_LOCAL);
if(!handle) {
puts(dlerror());
exit(1);
}
// lookup the "start" symbol in the shared library:
start_func_t start = dlsym(handle, "start");
if(!start) {
puts(dlerror());
exit(1);
}
// call the loaded function:
start();
dlclose(handle); // close the library
}
}
You need to link the above program with the dl library, so something like this should work:
gcc -o driver driver.c -ldl
Now, if you create some example files:
// t1.c
#include <stdio.h>
void start(void) { puts("Hello world"); }
// t2.c
#include <stdio.h>
void start(void) { puts("another file"); }
and then run:
./driver t1.c t2.c
It should produce this output if everything works out:
Hello world
another file
I also made a test to see how this works out if I put main in the library. That is, change the start_func_t signature to:
typedef int(*start_func_t)(int argc, char *argv[]);
and load and call main instead:
start_func_t start = dlsym(handle, "main");
if(!start) {
puts(dlerror());
exit(1);
}
// call the loaded function with some example arguments:
char *cargv[] = {
"foo", "hello", "world", NULL
};
start(3, cargv);
and change the test programs slightly:
// t1.c
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i = 0; i < argc; ++i) {
printf("t1: %s\n", argv[i]);
}
}
// t2.c
#include <stdio.h>
int main(int argc, char *argv[]) {
for(int i = 0; i < argc; ++i) {
printf("t2: %s\n", argv[i]);
}
}
and this worked fine too. However, main is a bit special and I'm not sure if this violates any rules.
I want to specify during run-time to ignore a function call for a function (which is of course defined) inside my executable. Please suggest some methodology for doing the same in C language on Linux.
Probably the best you can do is something like this:
// Filename mycode.c
int main()
{
// ...
#ifndef SOME_MACRO
someFUnction();
#endif
//...
}
int someFUnction()
{
// does something
}
To exclude the function call in main, you need to compile with
gcc -DSOME_MACRO mycode.c
If you will compile simply as
gcc mycode.c
then the function call will be enabled.
You cannot ignore function calls at runtime, you either call the function or you don't.
But let's assume for the sake of this answer that there exists a condition under which the function gets called and at least another condition under which the function is not called.
You can tell the program these conditions in several ways, for example per command-line, change of environment/file, and probably a long list more. For simplicity let's use the command-line and give the conditions in form of a argument to the executable. Additionally, because it is simple and short, use a signal.
File optional_functions.c
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
static void a(void)
{
puts("Function \"a\" called");
}
static void b(void)
{
puts("Function \"b\" called");
}
static void c(void)
{
puts("Function \"c\" called (by signal SIGINT)");
}
#include<signal.h>
#include<unistd.h>
static void signal_handler(int signal_number)
{
if (signal_number == SIGINT) {
c();
exit(EXIT_SUCCESS);
}
}
int main(int argc, char **argv)
{
void *dynlib;
void (*function_d) (void);
char *dynlib_error;
if (argc == 2) {
if (argv[1][0] == 'a') {
a();
} else if (argv[1][0] == 'b') {
b();
} else if (argv[1][0] == 'd') {
puts("External function \"d\" wanted, loading library");
dynlib = dlopen("libfunctiond.so", RTLD_LAZY);
if (dynlib == NULL) {
fprintf(stderr, "Failed loading lib: %s\n", dlerror());
exit(EXIT_FAILURE);
}
*(void **) (&function_d) = dlsym(dynlib, "d");
dynlib_error = dlerror();
if (dynlib_error != NULL) {
fprintf(stderr, "Failed calling function \"d\" fom lib: %s\n",
dynlib_error);
exit(EXIT_FAILURE);
}
(*function_d) ();
} else {
fprintf(stderr, "A function named \"%c\" does not exist, bailing out\n",
argv[1][0]);
exit(EXIT_FAILURE);
}
} else {
if (signal(SIGINT, signal_handler) == SIG_ERR) {
fprintf(stderr, "signal catching failed, bailing out\n");
exit(EXIT_FAILURE);
}
sleep(5);
puts("Signal catching timed out, assuming no function wanted in the first place.");
}
exit(EXIT_SUCCESS);
}
File functiond.h
#ifndef FUNCTIOND_H
#define FUNCTIOND_H
void d(void);
#endif
File functiond.c
#include <stdio.h>
#include "functiond.h"
void d(void)
{
puts("Function \"d\" called and says hello from the library");
}
Compile as
clang -Weverything -fPIC -c functiond.c
clang -shared -Wl,-soname,libfunctiond.so.1 -o libfunctiond.so.1.0 functiond.o
ln -sf libfunctiond.so.1.0 libfunctiond.so.1
ln -sf libfunctiond.so.1 libfunctiond.so
clang -Weverything -o optional_functions optional_functions.c example.c -ldl
Run it
$ ./optional_functions # waiting 5 seconds
Signal catching timed out, assuming no function wanted in the first place.
$ ./optional_functions # press CTRL+c in less than 5 seonds
^CFunction "c" called (by signal SIGINT)
$ ./optional_functions 1
A function named "1" does not exist, bailing out.
$ ./optional_functions a
Function "a" called
$ ./optional_functions b
Function "b" called
$ ./optional_functions d
External function "d" wanted, loading library
Failed loading lib: libfunctiond.so: cannot open shared object file: No such file or directory
That was expected. Either give dlopen() the complete path to the library or let the environment variable LD_LIBRARY_PATH do the job:
$ LD_LIBRARY_PATH=. ./optional_functions d
External function "d" wanted, loading library
Function "d" called and says hello from the library
It is not the proper way to make, install and and use dynamic libraries, of course, but again: for the sake of simplicity…
The IFUNC mechanism in recent ELF tools on (at least) Linux allows to choose a implementation of a function at runtime. Look at the iunc attribute in the GCC documentation for more detailed description: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
Another description of IFUNC mecanism : http://www.agner.org/optimize/blog/read.php?i=167
I would like to choose my implementation depending on the value of an environment variable. However, my experiments show me that the libc (at least the part about environment) is not yet initialized when the resolver function is run. So, the classical interfaces (extern char**environ or getenv()) do not work.
Does anybody know how to access the environment of a program in Linux at very early stage ? The environment is setup by the kernel at the execve(2) system call, so it is already somewhere (but where exactly ?) in the program address space at early initialization.
Thanks in advance
Vincent
Program to test:
#include <stdio.h>
#include <stdlib.h>
extern char** environ;
char** save_environ;
char* toto;
int saved=0;
extern int fonction ();
int fonction1 () {
return 1;
}
int fonction2 () {
return 2;
}
static typeof(fonction) * resolve_fonction (void) {
saved=1;
save_environ=environ;
toto=getenv("TOTO");
/* no way to choose between fonction1 and fonction2 with the TOTO envvar */
return fonction1;
}
int fonction () __attribute__ ((ifunc ("resolve_fonction")));
void print_saved() {
printf("saved: %dn", saved);
if (saved) {
printf("prev environ: %pn", save_environ);
printf("prev TOTO: %sn", toto);
}
}
int main() {
print_saved();
printf("main environ: %pn", environ);
printf("main environ[0]: %sn", environ[0]);
printf("main TOTO: %sn", getenv("TOTO"));
printf("main value: %dn", fonction());
return 0;
}
Compilation and execution:
$ gcc -Wall -g ifunc.c -o ifunc
$ env TOTO=ok ./ifunc
saved: 1
prev environ: (nil)
prev TOTO: (null)
main environ: 0x7fffffffe288
main environ[0]: XDG_VTNR=7
main TOTO: ok
main value: 1
$
In the resolver function, environ is NULL and getenv("TOTO") returns NULL. In the main function, the information is here.
Function Pointer
I found no way to use env in early stage legally. Resolver function runs in linker even earlier, than preinit_array functions. The only legal way to resolve this is to use function pointer and decide what function to use in function of .preinit_array section:
extern char** environ;
int(*f)();
void preinit(int argc, char **argv, char **envp) {
f = f1;
environ = envp; // actually, it is done a bit later
char *v = getenv("TOTO");
if (v && strcmp(v, "ok") == 0) {
f = f2;
}
}
__attribute__((section(".preinit_array"))) typeof(preinit) *__preinit = preinit;
ifunc & GNU ld inners
Glibc's linker ld contains a local symbol _environ and it is initialized, but it is rather hard to extract it. There is another way I found, but it is a bit tricky and rather unreliable.
At linker's entry point _start only stack is initialized. Program arguments and environmental values are sent to the process via stack. Arguments are stored in the following order:
argc, argv, argv + 1, ..., argv + argc - 1, NULL, ENV...
Linker ld shares a global symbol _dl_argv, which points to this place on the stack. With the help of it we can extract all the needful variables:
extern char** environ;
extern char **_dl_argv;
char** get_environ() {
int argc = *(int*)(_dl_argv - 1);
char **my_environ = (char**)(_dl_argv + argc + 1);
return my_environ;
}
typeof(f1) * resolve_f() {
environ = get_environ();
const char *var = getenv("TOTO");
if (var && strcmp(var, "ok") == 0) {
return f2;
}
return f1;
}
int f() __attribute__((ifunc("resolve_f")));
I have this c program:
#include <sys/types.h>
#include "ourhdr.h"
int glob = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";
int
main(void)
{
int var; /* automatic variable on the stack */
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
err_sys("write error");
printf("before fork\n"); /* we don't flush stdout */
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) { /* child */
glob++; /* modify variables */
var++;
} else
sleep(2); /* parent */
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
}
In the header file "ourhdr.h" (located in the same folder) i defined several functions, such as err_sys().
I get this error while compiling with gcc:
In function "main":
undefined reference to "err_sys"
How can i get this working? I can post the header file here if needed. Thank you.
** EDIT: ** This is the ourhdr.h file: http://pastebin.com/fMUiG4zU
You have included the header file with the declaration of err_sys. Ensure you have also an implementation that is passed to the linker. Background:
The compiler compiles a module to an object file:
g++ -c modul1.c generates modul1.o
g++ -c modul2.c generates modul2.o
Each of the modules can reference functions that are defined in a included header file. Up to here, no actual implementation of that function is needed.
In the next step, the linker links toghether all object files (and libraries):
g++ modul1.o modul2.o generates ./a.out or similar
In the second step, an implementation for all used functions is needed. Be sure you provided it!
(P.S.: Some compilers allow compiling and linking with one command, if you have multiple modules you can perhaps add them to a single gcc-call. I'd recomment to use make though)
I think what's likely to happen is that you have a header, ourhdr.h, containing the definition of the function, but the implementation is in a different file: ourhdr.c. In that case, if you try to compile without including ourhdr.c you'll get a reference error:
$ gcc main.c
/bin/ld: /tmp/ccVzNF6w.o: in function `main':
main.c:(.text+0x38): undefined reference to `err_sys'
To fix it, you need to compile like this:
$ gcc main.c ourhdr.c
Another option is to define the body of the function in ourhdr.h:
// ourhdr.h
#include <stdio.h>
void err_sys(const char* str);
void err_sys(const char* str) {
fprintf(stderr, "%s\n", str);
}
In that case, gcc main.c should work.
For me, it is compiling and working fine if you write the function name is written correctly.
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.