Weird linking situation - c

After some talking about linking in ##C on irc.freenode.net, I went to test some concepts I learned, and came up with this situation.
I have this file, named main.c:
int main(void) {
func();
return 0;
}
And this file, named test.c:
#include <stdio.h>
void func(void) {
printf("Hello.\n");
}
There's no test.h file.
I do this:
$ gcc -c main.c
$ gcc -c test.c
$ gcc main.o test.o
$ ./a.out
Hello.
$
and that works. Shouldn't gcc complain, on its first call, about not knowing function func() that is called in the main.c file? I didn't include any file with its prototype or implementation, and yet gcc can compile an object code and make a sane executable. What happened there that I'm missing?
Thank you.

Turn on a few warnings and you will be made painfully aware of the problems.
> gcc -Wall -c main.c
main.c: In function ‘main’:
main.c:2:5: warning: implicit declaration of function ‘func’
C will by default assume things about unknown functions. Good? Probably not. Historical.
Also gcc -std=c99 will throw the warning as well.

It works because all the argument types are matching (since you don't have anyone). You can make gcc complain by calling it gcc -c -Wall test.c

Related

Unable to identify issue GNU archiver. Compiling with *.o works but libname.a dosen't

I'm trying to make a static library (.a) but facing issues that I'm unable to understand. So in brief compiling with *.o succeeds but archiving them using ar and then using the .a file to compile gives me an undefined reference to 'symbol' error.
So here is a simple code.
test.c
#include <stdio.h>
#include <string.h>
int main()
{
hello_world();
return 0;
}
hello_world.c
#include<stdio.h>
void hello_world (void) {
printf("Hello World\n");
}
Compile.
gcc -c -o hello_world.o hello_world.c
ar crs libhello.a hello_world.o
gcc libhello.a -o test test.c
gives me the error
/tmp/ccsO7AJl.o: In function `main':
test.c:(.text+0xa): undefined reference to `hello_world'
Instead doing this works(Compiles and runs fine)
gcc -c -o hello_world.o hello_world.c
gcc hello_world.o -o test test.c
I have no idea what I have done wrong so any help is appreciated.
This is an almost duplicate of Why does the order of '-l' option in gcc matter? - but the behaviour can be replicated without the -l switch by specifying the archive name on command line.
The GNU linker as executed by GCC will, by default, link from left to right, and only use those .o files from the library archive that are needed to satisfy undefined references so far. Since your library precedes the main translation unit on the command line, hello_world is not required at the time the linker is processing it.
The solution is to mention the library after the translation units/object files that depend on it:
gcc -o test test.c libhello.a

Undefined reference error but symbol existing in the library

I get an undefined reference error for the example below. I have seen lots of questions that relate to this issue but believe I gave a stripped, reproducible, conceptual example as opposed specific issues in other questions,
dynlib.h:
void printMe_dyn();
dynlib.c:
#include <stdio.h>
#include "dynlib.h"
void printMe_dyn() {
printf("I am execuded from a dynamic lib");
}
myapp.c:
#include <stdio.h>
#include "dynlib.h"
int main()
{
printMe_dyn();
return 0;
}
Build steps:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
gcc -Wall -L. -ldynlib myapp.c -o myapp
Error:
/tmp/ccwb6Fnv.o: In function `main':
myapp.c:(.text+0xa): undefined reference to `printMe_dyn'
collect2: error: ld returned 1 exit status
Proof that the symbol is in the library:
nm libdynlib.so | grep printMe_dyn
00000000000006e0 T printMe_dyn
Am I using the correct compiler flags for building the dynamic
library?
Is the proof I've presented really an unambiguous proof?
What other approach could be taken to diagnose the issue?
The order of appearance of libraries matter.
To quote the online gcc manual
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.
You should be changing your compilation statement to
gcc -o myapp -Wall -L. myapp.c -ldynlib
to tell gcc to search for the symbols used in (compiled) myapp.c to be present in dynlib.
Just as additional notice. The same behavior one may obtain when the library has been built by gcc and linked to the c++ project. Like follows:
gcc -Wall -fpic -c dynlib.c
gcc -shared -o libdynlib.so dynlib.o
g++ -o myapp -Wall -L. myapp.cpp -ldynlib
In such case the reason is name-mangling used by g++. To have it turned off one must wrap C-function prototypes by extern "C" within C-library. For example like follows:
dynlib.h:
#ifdef __cplusplus
extern "C"{
#endif
void printMe_dyn();
#ifdef __cplusplus
}
#endif
The order of libraries in linker command line matters. Fix:
gcc -o myapp -Wall -L. myapp.c -ldynlib

dlopen fails to undefined symbol for function that is a prototype

I am writing a shared library on Linux (64-bit) with C11.
I created 3 C and H files.
dll.c
#include "dllman.h"
void start(){
pipeListeningThreadFunc( NULL );
}
dllman.h
#include <stdio.h>
void* pipeListeningThreadFunc( void* args );
dllman.c
#include "dllman.h"
void* pipeListeningThreadFunc( void* args ){
printf("Blah");
return NULL;
}
Compiling code as follows
gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dll.c
gcc -std=gnu11 -shared -fpic -o dll.so dll.o
Everything is okay until this point. dll.so file is created. But when I use dlopen function to load the library with as:
test.d
...
void* lh = dlopen("./dll.so", RTLD_NOW | RTLD_GLOBAL);
...
dlerror gives me:
dlopen error: ./dll.so: undefined symbol: pipeListeningThreadFunc
I don't understand what is wrong with this.
To be able to understand the problem, I moved the implementation of function pipeListeningThreadFunc to dllman.h, and compiled in same way. This time everything works properly.
What is wrong with defining function as prototype? Why can't it find the function when it is defined as prototype in header file and implemented in C file?
I think you meed to execute the following commands:
gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dll.c
gcc -std=gnu11 -c -Wall -Werror -fpic -lpthread dllman.c
gcc -std=gnu11 -shared -fpic -o dll.so dll.o dllman.o
Your commands are missing dllman.c
Linux allows to build libraries that are missing some symbols (in your case, dll.so doesn't contain pipeListeningThreadFunc function). However, when library is loaded, pipeListeningThreadFunc must be found anywhere - whether in this library or another library. Since this function doesn't exist, dlopen fails.

Why I need C header files?

It is a dumb question, I admit. Code will explain it better. Got these files:
hello.c:
#include <stdio.h>
void hello(char * s)
{
printf("hello, %s\n", s);
}
main.c:
int main()
{
hello("world!");
return 0;
}
makefile:
test : main.o hello.o
gcc -o test main.o hello.o
main.o : main.c
gcc -c main.c
hello.o : hello.c
gcc -c hello.c
.PHONY : clean
clean :
-rm test
-rm main.o
-rm hello.o
I can just "make" and "./test" it and it works.
Shouldn't I need to include something like hello.h in main.c just so the compiler knows the function prototype?
I didn't even include hello.c anywhere and it just works! How come main.c knows about the hello function?
If that works, when do I need .h files? I am new to C programming but I thought this concept was easy to grasp, now I am completely confused.
If you use the -Wall flag (and one should always use it, along with -Werror -Wextra), then you'd get the following message:
main.c: In function 'main':
main.c:3: warning: implicit declaration of function 'hello'
And the compiler effectively "guesses" what to do, which can lead to disaster in many circumstances.
Correctly using header files avoids this sort of warning.
You do not need header files; instead, your functions need prototypes. When you call hello passing it "world", C figures out that you are calling a one-argument function taking char*, and does everything right. This will not work, however, if the function takes a float, and you decide to ass it an int (try it, it is very instructive). For reasons of backward compatibility C will let you call functions without prototypes, but it is dangerous. For example, in case of your call of hello, the compiler thinks that you are calling a function returning an int. Technically, you are invoking undefined behavior, so your program works by accident.
Headers happen to provide the most convenient way to supply prototypes, but you can supply them in the code itself, like this:
void hello(char*);
int main()
{
hello("world!");
return 0;
}

Implicit Declaration Of Function

I've just organized my code by using headers, but just as I've done this, I got a warning that turned into an error when linking.
I have a code(use of a function that is inside a header) in test.c that is like this:
#include "test1.h"
/* Some code */
main()
{
Testing();
}
And my test1.h header is like this:
void Testing();
void print(int, int, int, const char*);
And at test1.c
void Testing()
{
print(0xF9, 27, 5, "\xC9\\xBB");
}
void print(int colour, int x, int y, const char *string)
{
volatile char *video=(volatile char*)0xB8000 + y*160 + x*2;
while(*string != 0)
{
*video=*string;
string++;
video++;
*video=colour;
video++;
}
}
When I try to compile the code, I got this:
ubuntu#eeepc:~/Development/Test$ gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
test.c: In function ‘main’:
test.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
At the time it's just a simple warning, but when I try to link it...
ubuntu#eeepc:~/Development/Test$ ld -T linker.ld -o kernel.bin loader.o test.o
test.o: In function main':
test.c:(.text+0xfc): undefined reference toTesting'
What I need to do?
Edit: To reflect the OP's question I have struck out some lines of my answer despite being upvoted...
Why is kernel.c flagged up in the compiler, even though you don't have it mentioned here? Am I missing something...
gcc -o test.o -c test.c -Wall -Wextra -nostdlib -nostartfiles -nodefaultlibs
kernel.c: In function ‘main’:
kernel.c:11: warning: implicit declaration of function ‘Testing’
ubuntu#eeepc:~/Development/Test$
maybe you need to do it this way somewhere in your header file as I'm judging you want kernel to access this function:
extern void Testing();
And, take out all your functions and place them in a separate .c file, they should not be in there in the first place... for example:
Testing.c
/* all your functions here */
Testing.h
/* Only global, external variables and function prototypes */
Hope this helps,
Best regards,
Tom.
I can't recreate your problem. This works as expected when I try to compile your code on an Ubuntu machine (Which based on your paste, I assume you're using.)
Are you sure the #include is happening correctly?
Try using -E instead of -c to see what the whole code the compiler is trying to compile looks like.
Somewhat of a shot in the dark here, since my C is a bit rusty, but does C allow you to put function bodies in a header? I don't recall that it does. Try moving the definition of Testing() and print() into a .c file? You could also try compiling as C++ as see if that fixes it, if you don't need/want C.
You included test.h into main.c, while your declarations, according to what your wrote, are in test1.h. Note the 1 in the name.
In addition to that, you are compiling test.c and linking test.o, while in reality the name of your file is test1.c. Again, note the 1 in the name.
Edit: Now you edited the name of the file included into main.c. After the edit it is safe to assert that most of the symptoms you describe are not possble with the current versions of the files. Re-verify what you are doing, post updated disgnostic information and/or post real code.
Still, you compiler and linker lines are referring to old file names.
i donno whats causing this , but i had this problem just now .
try to delete the .h file and put the declarations of the functions on the top of .c file itself .
in this case , delete the test1.h and put the declarations of functions of test1.c in test1.c.
and include test1.c in test.c
you wont get that warning message any more , nor the following linking errors .

Resources