why asan linker flag is needed - c

Could someone help me understand, why after generating the object file with using ASan flag (compiler flag), when linking the object file still needs the same flag? (linker flag)
For example
clang -fsanitize=address -c test.c
clang -fsanitize=address test.o -o test.exe

When you compile your program with Address Sanitizer, it instruments every memory access and prefixes it with a check and includes the function calls to report memory access errors.
For e.g.
Sample program which leaks memory and try to access array beyond its size:
#include <stdio.h>
#include <stdlib.h>
void fun (void) {
void *p = malloc(1);
char a[] = "abc";
printf ("%c\n", a[4]);
}
int main (void) {
fun();
return 0;
}
Compiling:
# gcc -fsanitize=address -g -c test.c
# ls
test.c test.o
Linking without -fsanitize=address:
# gcc -g test.o -o test.exe
test.o: In function `fun':
/root/mywork/asan/sample7/test.c:4: undefined reference to `__asan_option_detect_stack_use_after_return'
/root/mywork/asan/sample7/test.c:4: undefined reference to `__asan_stack_malloc_1'
/root/mywork/asan/sample7/test.c:6: undefined reference to `__asan_report_store4'
/root/mywork/asan/sample7/test.c:8: undefined reference to `__asan_report_load1'
test.o: In function `_GLOBAL__sub_D_00099_0_fun':
/root/mywork/asan/sample7/test.c:14: undefined reference to `__asan_unregister_globals'
test.o: In function `_GLOBAL__sub_I_00099_1_fun':
/root/mywork/asan/sample7/test.c:14: undefined reference to `__asan_init'
/root/mywork/asan/sample7/test.c:14: undefined reference to `__asan_version_mismatch_check_v8'
/root/mywork/asan/sample7/test.c:14: undefined reference to `__asan_register_globals'
collect2: error: ld returned 1 exit status
The code of test.o is instrumented by Address Sanitizer. The Address Sanitizer runtime library replaces malloc() call with its own malloc() function call (which allocate requested amount of memory with redzone around it) and provides error reporting function like __asan_report_load1(), __asan_report_store4() etc. In order to resolve these functions, the -fsanitize=address flag is required at the time of linking to tell linker to check the ASan runtime library to resolve the references.
Linking with -fsanitize=address:
# gcc -fsanitize=address -g test.o -o test.exe
# ls
test.c test.exe test.o
If you don't want to use -fsanitize=address flag with linker, you can provide the Address Sanitizer library to the linker which it can use to resolve the references:
# ls
test.c test.o
# gcc -lasan -g test.o -o test.exe
# ls
test.c test.exe test.o

Related

undefined main during linking but defined during full compilitaion process

I am novice in C programming. So I learned different process of compilation(preproccessing, compiling, linking). My program is
#include <stdio.h>
#define testDefinition(x) printf(#x " is equal to %lf\n",x)
int main(void)
{
testDefinition(3.15);
return 0;
}
It is simple program which doesn't have any sense,but problem is when I use gcc -o test test.c it works fine, but when I do that
gcc -E test.c -o test.i
gcc -C test.i -o test.o
gcc test.o -o test
I get error
usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x24): undefined reference to `main'
collect2: error: ld returned 1 exit status
I am using Ubuntu 20.04 and GCC compiler.
test.o is already the executable, you did not pass -c.
$ gcc -E test.c -o test.i
$ gcc -C test.i -o test.o
$ ./test.o
3.15 is equal ....
Because of it, test.o is an ELF file and gcc treats it as shared library (I think). Because there are no source files passed in gcc test.o -o test there is no main, so it's undefined.
I guess, you wanted to do gcc -C -c test.i -o test.o to create an object file.

Different behavior between clang and gcc-10 when linking to static library containing global variables

I have a statically linked library, containing a global variable barvar. I can compile the library with no problems with either gcc-10 or clang (this is on macOS Catalina). Interestingly, the behavior differs between the two when I try to link it into a program that uses the library. Here's the code:
In globvars.h, int barvar is declared:
#ifndef H_GLOBVARS_H
#define H_GLOBVARS_H
extern int barvar;
#endif
In globvars.c, int barvar is defined:
#include "globvars.h"
int barvar;
In foo.c, the function foo sets and prints barvar:
#include <stdio.h>
#include "globvars.h"
void foo()
{
barvar = 10;
printf("barvar is: %d\n", barvar);
return;
}
Here's test.c, the program that uses the library:
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
When I compile and link with gcc-10, no problems:
gcc-10 -c foo.c -o foo.o
gcc-10 -c globvars.c -o globvars.o
gcc-10 -c test.c -o test.o
gcc-ar-10 rcs liblinktest.a foo.o globvars.o
gcc -o testlinkrun test2.o -L. -llinktest
When I compile and link with clang, I get an undefined symbol error at the last step:
cc -c foo.c -o foo.o
cc -c globvars.c -o globvars.o
cc -c test.c -o test.o
ar rcs liblinktest.a foo.o globvars.o
cc -o testlinkrun test2.o -L. -llinktest
with error:
Undefined symbols for architecture x86_64:
"_barvar", referenced from:
_foo in liblinktest.a(foo.o)
Any ideas? Interestingly, it appears the only step that has to be done with gcc-10 is compiling globvars.c. I can use clang and the clang linker for all other steps, and everything is fine. Is it possible that clang is optimizing away all the variables in globvars.c? How can I prevent this?
As #EricPostpischil observed in this comment, the issue is that clang defaults to treating barvar as a common symbol. Either changing int barvar; to int barvar = 0;, or compiling with -fno-common, fix the issue.
Beginning with gcc-10, gcc's default behavior is -fno-common instead of -fcommon.

How to use extern symbols in shared library in C

I am trying to compile following test files to create a shared library:
answer.c
#include <stdio.h>
#include "add.h"
extern int myvar();
int answer()
{
printf("\r\n myvar:%d \r\n", myvar());
setSummand(20);
return add(22); // Will return 42 (=20+22)
}
add.c
#include <stdio.h>
int gSummand;
void setSummand(int summand)
{
printf("1Library is initialized\n");
gSummand = summand;
}
int add(int summand)
{
return gSummand + summand;
}
I want to create a shared library from the 2 files "answer.c" "add.c", I am using following commands:
gcc -c answer.c -o answer.o
gcc -c add.c -o add.o
gcc -shared add.o answer.o -o libtest.so
However third command gives following error:
answer.o:answer.c:(.text+0x9): undefined reference to `myvar'
answer.o:answer.c:(.text+0x9): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `myvar'
collect2: error: ld returned 1 exit status
Same setup links successfully if I use the following command to create static library instead of dynamic. Therefore, I don't see any error if I try following command:
ar rcs libtest.a add.o answer.o
Want to know if I am missing here something. Also want to know how to use external symbols in shared library.
ELF shared libraries need to be position independent. They will be mapped into the executable's address space at an address that isn't known until run time. This means no absolute address call instructions, such as might be used to call myvar().
You need to specify -fpic when you compile the source into object files, when those object files will be placed into a shared library. This tells the compiler to generate code that does not use absolute addresses, etc. so it can be position independent.
Example main.c file to use this library:
extern int answer(void);
int myvar() { return 1; }
int main(void) { return answer(); }
Example without -fpic:
[test]$ gcc -c add.c
[test]$ gcc -c answer.c
[test]$ gcc -shared add.o answer.o -o libtest.so
/usr/bin/ld: add.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: answer.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
Example with -fpic:
[test]$ gcc -fpic -c add.c
[test]$ gcc -fpic -c answer.c
[test]$ gcc -shared add.o answer.o -o libtest.so
[test]$ gcc main.c libtest.so
[test]$ LD_LIBRARY_PATH=. ./a.out
myvar:1
1Library is initialized

Linking two object files together causes segmentation fault 11

I am experimenting with externs and various methods of linking to better understand the linking process.
I have three files:
foo.c:
#include "foo.h"
int a = 4;
test.c:
#include <stdio.h>
#include "foo.h"
int main(int, char**);
int mymain();
int mymain() {
main(0, 0);
printf("test\r\n");
return 0;
}
int main(int argc, char** argv) {
printf("extern a has %d\r\n", a);
return 0;
}
foo.h:
extern int a; // defined in foo.c
If I build each file together and link at compile time using gcc like this:
gcc *.c -o final.bin
I can execute final.bin as:
./final.bin
and get expected output
extern a has 4
However, if I compile (but don't link) test.c and foo.c separately, then try and link the object files together at runtime to produce a binary, I get a segmentation fault 11 (which from what I can gather is some generic memory corruption bug like a normal segfault(?)
Here is my makefile I'm using to compile and link separately. Note I am specifying my own entry point and linking against libc to get printf()...
all: test.o foo.o
#echo "Making all..."
ld test.o foo.o -o together.bin -lc -e _mymain
test.o: test.c
#echo "Making test..."
gcc -c test.c -o test.o
foo.o: foo.c
#echo "Making foo..."
gcc -c foo.c -o foo.o
Output when running 'together.bin':
./together.bin
extern a has 4
test
Segmentation fault: 11
Perhaps my function signature for 'mymain' is wrong? My guess is that something is wrong with my 'myentry' usage.
Also, if anyone has any recommendations on good books for how linkers and loaders work, I am certainly in the market for one. I've heard mixed things about 'Linkers and Loaders', so I'm waiting on more opinions before I invest the time in that book in particular.
Thanks for any help on this... My understanding of linkers is sub-par to say the least.
Unless if you have a good reason to do so, just use gcc to link:
$ gcc test.o foo.o "-Wl,-e,_mymain" -o ./final.bin; ./final.bin
extern a has 4
test
gcc calls ld---though, with a few more arguments than you are providing in your example. If you want to know exactly how gcc invokes ld, use the -v option. Example:
$ gcc -v test.o foo.o "-Wl,-e,_mymain" -o ./final.bin
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -dynamic -arch x86_64 -macosx_version_min 10.12.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk -o ./final.bin test.o foo.o -e _mymain -lSystem /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/lib/darwin/libclang_rt.osx.a

cannot compile mongo-c-driver example

I try to write simple mongo c client. Source file (a.c):
#include <stdio.h>
#define MONGO_HAVE_STDINT
#include <mongo.h>
void mongo_init_c(mongo *con)
{
mongo_init(con);
}
int main() {
return 0;
}
And i try to compile it with:
gcc -I/usr/local/include -L/usr/local/lib -lmongoc a.c
But get an error:
a.c:(.text+0xd): undefined reference to `mongo_init'
Files /usr/local/include/mongo.h and /usr/local/lib/libmongoc.so exists
How can I correctly compile a.c?
p.s. mongo-2.0.4, gcc-4.6, mongo-c-driver - pulled from github
update
$ nm /usr/local/lib/libmongoc.so | grep init
000034e0 T _init
0000dd10 T bson_init
0000c740 T bson_init_data
0000c7b0 T bson_init_finished_data
0000dc10 T bson_init_size
0000d060 T bson_iterator_init
0000a5e0 T gridfile_init
00009af0 T gridfile_writer_init
000095e0 T gridfs_init
00010a18 R initialBufferSize
00005f40 T mongo_cursor_init
00008da0 T mongo_env_sock_init
00005d90 T mongo_init
000057b0 T mongo_init_sockets
00004800 T mongo_md5_init
00005e40 T mongo_replica_set_init
00005f00 T mongo_replset_init
00005b80 T mongo_write_concern_init
$ gcc -I/usr/local/include -L/usr/local/lib -Wall -Werror -lmongoc a.c
/tmp/cccuNEp1.o: In function `mongo_init_c':
a.c:(.text+0xd): undefined reference to `mongo_init'
Try linking the library after the source file, like gcc a.c -lmongoc. This is because you're using a traditional single-pass linker, which expects to satisfy dependencies with subsequent, not previous, objects specified on the command line.

Resources