Linking extern declaration with definition - c

I have the following two files:
// t.c
#include<stdio.h>
extern int x;
int main(void)
{
printf("%d\n", x);
}
// tt.c
int x=4;
And then I compile it into two object files with:
$ gcc -c tt.c t.c
So now I have two object files, tt.o and t.o. When I do the following to build an executable:
$ gcc tt.o t.o -o out
How does the linker resolve the definition of x? Does it basically do a "two-pass" where it saves all global variables with external linkage first, and then does a lookup in each file that needs an external definition, or what's the process that happens to resolve those lookups?

Related

Use of extern variable in c

I have made two files in c i.e. file1.c file2.c. In file1.c I wrote
#include< stdio.h >
int s=10;
void main()
{
printf("This is file 1");
}
In file2.c
include < stdio.h >
extern int s;
void main() {
printf("%d",s);
}
When I compiled file2.c in ubuntu terminal I got undefined referenced to s error.
How can I resolve this error?
In the second case,
extern int s;
tells the compiler that "somewhere there" exists a variable s which has type int, but it actually does not "define" the variable. So, the linker has no clue where to find the variable, it cannot find the variable and throws the error.
You need to have a definition of the variable, either in a separate translation unit (the purpose of using extern) or in the same translation unit (if you want).
In file1.c
#include <stdio.h>
void myfunction( void );
int s=10;
void myfunction()
{
printf("This is file 1");
}
In file2.c
#include <stdio.h>
void myfunction( void );
extern int s;
int main( void )
{
myfunction();
printf("%d",s);
}
then compile (the example uses gcc
gcc -g -Wall -Wextra -pedantic -Wconversion -std=gnu11 -c file1.c -o file1.o
gcc -g -Wall -Wextra -pedantic -Wconversion -std=gnu11 -c file2.c -o file2.o
then link using:
gcc -g file1.o file2.o -o myexec
then run it as
./myexec
Of course, if your using Visual Studio, the command line statements will be slightly different

Can't figure out error with shared variables

source.c ::
int source=0;
int desti=0;
char str[50]="";
source.h::
extern int source;
extern int desti;
extern char str[50];
station1.c
#include"source.h"
#include<stdio.h>
main()
{
printf("%d %d",source,desti);
}
When I compile station1.c I get the following error:
undefined reference to 'desti'
undefined reference to 'source'
Could anyone please tell me where I have gone wrong?
What did your compile command line look like?
Try:
cc -c station1.c -o station1.o
cc -c source.c -o source.o
cc -o a.out station1.o source.o
The first two compile the files by themselves and puts the result in a .o file.
The last line combines the .o files into an executable named 'a.out'.
When we use extern modifier with any variables it is only declaration i.e. memory is not allocated for these variable. Hence in your casecompiler is showing error unknown symbol source & desti. To define a variable i.e. allocate the memory for extern variables it is necessary to initialize the variables.
initialize the variables in source.c
or another way is to compile with combining the object file
gcc -c source.c station1.c -Isource.h

How can I remove a symbol from a shared object?

Using GCC, how can I remove a symbol from a shared object after I've created the shared object? If I have three files in C manipulating symbol foo() like:
// a.c
int foo() { return 0xdead; }
int baz() { return 1; }
and
// b.c
int foo() { return 0xbeef; }
int bar() { return 0; }
and
// c.c
#include "stdio.h"
extern int foo();
extern int bar();
extern int baz();
int main() { printf("0x%x, 0x%x, 0x%x\n",foo(),bar(),baz()); return 0; }
Then I compile and run like:
% gcc a.c --shared -fPIC -o a.so
% gcc b.c --shared -fPIC -o b.so
% setenv LD_LIBRARY_PATH . # export LD_LIBRARY_PATH=. for bash systems
% gcc c.c a.so b.so -o c
% ./c
0xdead, 0x0, 0x1
How can I make it so that a.so no longer has symbol foo() after I've created a.so? I want the foo() defined in b.so to be used instead of a.so by deleting the foo() symbol from a.so. After foo() is deleted from a.so, rerunning c should generate a printout of:
0xbeef, 0x0, 0x1
In this toy example, I know I can simply re-order the libary names when I compile c.c with a.so and b.so, but how can I actually delete the symbol from a.so? I imagine that after deleting foo() from a.so, this grep of the nm output would yield nothing:
nm -a a.so | grep foo
Whereas right now it returns:
000000000000063c T foo
You should be able to use the -N (--strip-symbol) option of objcopy to achieve what you want:
$ objcopy -N foo a.so
Symbol visibility seems like a superior solution to select which functions are up for runtime linking and which are local to the library but still "extern" declared to allow usage from other .c files that comprise the library - http://gcc.gnu.org/wiki/Visibility .

How are static globals handled in multiple modules?

In C, declaring a variable static at the global level (outside any function) indicates that it is visible only to that linker object (typically, that .C file).
If the same .C file is part of multiple different libraries that are then linked together in a single executable, do conflicts arise?
For example:
MyFile.c
typedef struct {
[my important data];
} MyGlobalType;
static MyGlobalType globalData = { [...data...] };
Then if I have:
Plugin_Alpha.so: composed of MyFile.C + AlphaSource.C
Plugin_Beta.so: composed of MyFile.C + BetaSource.C
MainProgram.exe: composed of MainCode.C (which loads the two plugins)
Will Plugin_Alpha and Plugin_Beta have separate, isolated copies of globalData?
Or will they end up referring to the same structure?
Well, here's one way to find out:
File liba.c:
static int globalData;
int *GetGlobalData() { return &globalData; }
Compile into two separate shared libraries:
$ gcc liba.c -o liba.so -fPIC -shared
$ gcc liba.c -o libb.so -fPIC -shared
Main program:
#include <dlfcn.h>
#include <stdio.h>
int main(void)
{
// Error checking omitted for expository purposes
void *liba = dlopen("liba.so", RTLD_LAZY);
void *libb = dlopen("libb.so", RTLD_LAZY);
typedef int* (*FuncV_IP)(void);
FuncV_IP funca = (FuncV_IP)dlsym(liba, "GetGlobalData");
FuncV_IP funcb = (FuncV_IP)dlsym(libb, "GetGlobalData");
printf("Module A: GetGlobalData() ==> %p\n", funca());
printf("Module B: GetGlobalData() ==> %p\n", funcb());
dlclose(liba);
dlclose(libb);
return 0;
}
Compile and run it:
$ gcc main.c -ldl
$ LD_LIBRARY_PATH=. ./a.out
Output:
Module A: GetGlobalData() ==> 0x7fa97536d020
Module B: GetGlobalData() ==> 0x7fa97516b020
So therefore, each shared library gets its own copy of the global variables.

Why does CC not see my function definition in header?

I'm writing a simple application in ANSI C. I am using GCC in a Unix environment.
I have the following sample application:
//main.c
#include "foo.h"
int main()
{
int result;
result = add(1,5);
return0;
}
Header:
//foo.h
#ifndef FOO_H_INCLUDED
#define FF_H_INCLUDED
int add(int a, int b);
#endif
Implementation:
//foo.c
int add(int a, int b)
{
return a+b;
}
I am compiling my program with the following command:
cc main.c -o main.o
The compiler complains that 'reference to add is undefined'. Is this a linking problem? How do properly make use of my header?
Thanks!
You need to compile both your source files together:
cc main.c foo.c -o main
Also, in this case, -o produces an executable, so calling it main.o can be misleading.
Yet another tidbit, though unrelated to the question: the #ifndef and #define in foo.h don't match.
The header is not your current problem. Your current problem is that you're not compiling the add function definition in foo.c.
Try
cc main.c foo.c -o main.o
If you are trying to compile main.c into an assembled object file, you need to prevent gcc from trying to link. This is done via
cc -c main.c -o main.o
You can compile all other object files, then when you have all of your object files ready, you simply do
cc main.o obj1.o anotherOBJ.o -o myExecutableBinary
"undefined reference" is a linker error, not a compiler error.
The compiler sees the declaration in the header, but you have not compiled or linked the definition in foo.c. Your title uses the term definition incorrectly.

Resources