dietlibc, lowfat, opentracker - compiling against alternative libc - c

I'm attempting to build opentracker. My system has the following:
| package | library | headers |
| lowfat | /usr/lib/libowfat.a | /usr/include/libowfat |
| dietlibc | /opt/diet/lib-x86_64/*.a | /usr/diet/include |
| glibc | /usr/lib/*.{a,so} | /usr/include |
Looking at the Makefile for opentracker, I see (essentially) the following:
PREFIX?=..
LIBOWFAT_HEADERS=$(PREFIX)/libowfat
LIBOWFAT_LIBRARY=$(PREFIX)/libowfat
CFLAGS+=-I$(LIBOWFAT_HEADERS) -Wall -pipe -Wextra
LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread -lpthread -lz
opentrackers: $(OBJECTS) $(HEADERS)
cc -o $# $(OBJECTS) $(LDFLAGS)
I've not compiled against an alternative libc before, so I'm including this information in case I've done this part wrong. When I invoke make, I need to point it at where my system has dietlibc and lowfat live. I'm doing it like this:
$ LDFLAGS=-L/opt/diet/lib-x86_64 make PREFIX=/opt/diet LIBOWFAT_HEADERS=/usr/include/libowfat LIBOWFAT_LIBRARY=/usr/lib
...
...
cc -o opentracker opentracker.o trackerlogic.o scan_urlencoded_query.o ot_mutex.o ot_stats.o ot_vector.o ot_clean.o ot_udp.o ot_iovec.o ot_fullscrape.o ot_accesslist.o ot_http.o ot_livesync.o ot_rijndael.o -L/opt/diet/lib-x86_64 -L/usr/lib -lowfat -pthread -lpthread -lz
/usr/bin/ld: /usr/lib/libowfat.a(io_fd.o):(.bss+0xb0): multiple definition of `first_deferred'; /usr/lib/libowfat.a(io_close.o):(.data+0x0): first defined here
...
... lots of warnings ...
/usr/bin/ld: opentracker.o: undefined reference to symbol '__ctype_b_loc##GLIBC_2.3'
/usr/bin/ld: /usr/lib/libc.so.6: error adding symbols: DSO missing from command line
Looks like there's two issues going on in there.
Multiple definitions of first_deferred
I see references to first_deferred in both io_close and io_fd, but they are in different sections.
$ objdump -t /usr/lib/libowfat.a | egrep '^[^:]+.o:|first_deferred' | grep -B1 first_deferred
io_close.o: file format elf64-x86-64
0000000000000000 g O .data 0000000000000008 first_deferred
--
io_fd.o: file format elf64-x86-64
00000000000000b0 g O .bss 0000000000000008 first_deferred
--
io_waituntil2.o: file format elf64-x86-64
0000000000000000 *UND* 0000000000000000 first_deferred
In io/io_fd.c, there's an #include io_internal.h and in that header there's an extern long first_deferred;. In io/io_close.c it's defined as long first_deferred=-1. So it doesn't look like it's double defined in the libowfat code itself. Did I compile lowfat wrong?
DSO missing from command line / symbol '__ctype_b_loc##GLIBC_2.3'
Since the Makefile is trying to compile against dietlibc, I'm a bit surprised that there's a reference to glibc (but, to be honest, also not surprised at all).
Here's the recipe for opentracker.o:
cc -c -o opentracker.o -march=x86-64 -mtune=generic -O2 -pipe -fno-plt -I/usr/include/libowfat -Wall -pipe -Wextra -O3 -DWANT_FULLSCRAPE opentracker.c
This doesn't appear to have the -L/opt/diet/lib-x86_64 argument from LDFLAGS that is used for the main executable. Should it? I don't think so as that's a linker argument so it would not make sense to add it to the compile command. I don't see any references to glibc in the object file:
$ objdump -t ./src/opentracker/opentracker.o | grep -c 'glib'
0

DSO missing from command line / symbol '__ctype_b_loc##GLIBC_2.3'
I found two permutations to solve this issue. Option one is to make sure the very first -L argument is the location of dietlibc's lib directory, so that all symbols are resolved from there first.
The other permutation was to invoke make via the /opt/diet/bin/diet wrapper program. From the dietlibc FAQ
Q: How do I install it? make install?
A: Yep. It will then install itself to /opt/diet, with the wrapper in
/opt/diet/bin/diet. Or you don't install it at all.
The diet libc comes with a wrapper called "diet", which can be found
in bin-$(ARCH)/diet, i.e. bin-i386/diet for most of us. Copy this
wrapper somewhere in your path (for example ~/bin) and then just
compile stuff by prepending diet to the command line, e.g. "diet gcc
-pipe -g -o t t.c".
Q: How do I compile programs using autoconf with the diet libc?
A: Set CC in the environment properly. For Bourne Shells:
$ CC="diet gcc -nostdinc" ./configure --disable-nls
That should be enough, but you might also want to set
--disable-shared and --enable-static for packages using libtool.
It's not explained anywhere on the website, as far as I can tell, what the wrapper program does. The code is annoying to read due to all the architecture specific #ifdefs, but the file comment indicates it just modifies the gcc command line in an architecture specific way. A quick scan suggests relevant args modifications include: -I/opt/diet/include when compiling, -nostdlib when linking, and possibly -Os.
Multiple definitions of first_deferred
I'm not happy with my workaround here. The symbol is defined in io_internal.h:
#ifndef my_extern
#define my_extern extern
#endif
my_extern long first_deferred;
Why is there a funny redefinition of the extern keyword? Read on. The initialization of this variable is in io_close.c:
#include "io_internal.h"
long first_deferred=-1;
And here's the interesting bit. In io_fd.c:
#define my_extern
#include "io_internal.h"
#undef my_extern
Why? Who knows. The author believes they are clever I guess and saved themselves some keystrokes? The effect of this is that my_extern is defined as an empty string, so when my_extern long first_deferred; is transcluded from the header, it appears as long first_deferred;. This is what leads there to be two locations for the symbol in the archive, as there are two files that reserve space for that symbol.
I'm not happy with my "solution", which was to remove the static initialization from io_close.c. Technically, that means the variable starts with random heap memory. A quick look at how it gets used suggests this is maybe not safe, but is probably safe enough. The variable is used as an index into an array. Thankfully iarray_get does a bounds check, so it's very likely that if(e) will be false and the variable will get set to -1 as it should be.
if (first_deferred!=-1) {
while (first_deferred!=-1) {
io_entry* e=iarray_get(&io_fds,first_deferred);
if (e) {
if (e->closed) {
e->closed=0;
close(first_deferred);
}
first_deferred=e->next_defer;
} else
first_deferred=-1; // can't happen
}
}

I can't provide a good explanation for those errors, but your post helped me to get it to compile so I figured I'd mention what I did.
The "first_deferred" error seems to come from using a newer version of libowfat, I got past that by using 0.31 instead.
I didn't come across the second error, but I was getting "__you_tried_to_link_a_dietlibc_object_against_glibc" errors which I got past by uninstalling dietlibc and compiling libowfat with glibc instead.
I compiled them the same way as the AUR packages:
https://aur.archlinux.org/packages/opentracker/
https://aur.archlinux.org/packages/libowfat/
Although, instead of installing libowfat, I just put it in the src directory and skipped fetching libowfat from CVS.

Related

Find all symbols in a directory

I am looking to figure out which C library to include when compiling a program that includes it as a header, in this case #include <pcre2.h>. The only way I've been able to figure out where the file is I need is to check for a specific symbol that I know needs to be exported. For example:
$ ls
CMakeCache.txt Makefile install_manifest.txt libpcre2-posix.pc pcre2_grep_test.sh
CMakeFiles a.out libpcre2-8.a pcre2-config pcre2_test.sh
CTestCustom.ctest cmake_install.cmake libpcre2-8.pc pcre2.h pcre2grep
CTestTestfile.cmake config.h libpcre2-posix.a pcre2_chartables.c pcre2test
$ objdump -t libpcre2-8.a|grep pcre2_compile
pcre2_compile.c.o: file format elf64-x86-64
0000000000000000 l df *ABS* 0000000000000000 pcre2_compile.c
00000000000100bc g F .text 00000000000019dd pcre2_compile_8
0000000000000172 g F .text 00000000000000e3 pcre2_compile_context_create_8
0000000000000426 g F .text 0000000000000055 pcre2_compile_context_copy_8
0000000000000557 g F .text 0000000000000032 pcre2_compile_context_free_8
And because the symbol pcre2_compile_8 exists in that file (after trying every other file...) I know that the library I need to include is pcre2-8, that is, I compile my code with:
$ gcc myfile.c -lpcre2-8 -o myfile; ./myfile
Two questions related to this:
Is there a simpler way to find a symbols in a batch of files (some of which are not elf files)? For example, something like objdump -t *? Or what's the closest thing to doing that?
Is there a better way to find out what the library value of -l<library> is? Or, what's the common way when someone downloads a new C program that they know what to add to their command-line so that the program works? (For me, I've just spent the last hour figuring out that it's -lpcre2-8 and not -lpcre or -lpcre2.
Usually, the function you call from the library will be a symbol defined by that library. But in PCRE2, due to different code unit sizes, the function you call (e.g. pcre2_compile) actually becomes a different symbol through preprocessor macros (e.g. pcre2_compile_8). You can find the symbol you need from the library by compiling your program and checking the undefined symbols:
$ cat test.c
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
int main() {
pcre2_compile("",0,0,NULL,NULL,NULL);
}
$ gcc -c test.c
$ nm -u test.o
U _GLOBAL_OFFSET_TABLE_
U pcre2_compile_8
Is there a simpler way to find a symbols in a batch of files?
You can search a directory (/usr/lib/ below) for the library files (.a or .so extension below), running nm for each and search for the undefined symbol (adapted from this question):
$ for lib in $(find /usr/lib/ -name \*.a -o -name \*.so)
> do
> nm -A --defined-only $lib 2>/dev/null| grep pcre2_compile_8
> done
/usr/lib/x86_64-linux-gnu/libpcre2-8.a:libpcre2_8_la-pcre2_compile.o:0000000000007f40 T pcre2_compile_8
Is there a better way to find out what the library value of -l is?
It is usually conveyed through the library documentation. For PCRE2, the second page of the documentation talks about the pcre-config tool that gives the appropriate flags:
pcre2-config returns the configuration of the installed PCRE2 libraries and the options required to compile a program to use them. Some of the options apply only to the 8-bit, or 16-bit, or 32-bit libraries, respectively, and are not available for libraries that have not been built.
[...]
--libs8 Writes to the standard output the command line options required to link with the 8-bit PCRE2 library (-lpcre2-8 on many systems).
[...]
--cflags Writes to the standard output the command line options required to compile files that use PCRE2 (this may include some -I options, but is blank on many systems).
So for this particular library, the recommended way to build and link is:
gcc -c $(pcre2-config --cflags) test.c -o test.o
gcc test.o -o test $(pcre2-config --libs8)

Cannot link to BLAS/ATLAS when trying to compile HPCC benchmark

I am trying to compile the HPCC benchmark on a small RHEL desktop. Everything seems fine until linking. My link command is
mpicc -DAdd_ -DF77_INTEGER=int -DStringSunStyle -I../../../include \
-I../../../include/myarch -I/path/to/my/ATLAS_build/include \
-I/usr/include/openmpi-x86_64 -fomit-frame-pointer -O3 -funroll-loops \
-W -Wall -lm -o ../../../../hpcc ../../../lib/bugzilla/libhpl.a \
/path/to/my/ATLAS_build/lib/libcblas.a \
/path/to/my/ATLAS_build/lib/libatlas.a -L/usr/lib64/openmpi/lib
The link fails with several errors, all related to BLAS/ATLAS objects that the linker can't find. A few of them are:
../../../lib/myarch/libhpl.a(HPL_dcopy.o): In function `HPL_dcopy':
HPL_dcopy.c:(.text+0x1e): undefined reference to `dcopy_'
../../../lib/myarch/libhpl.a(HPL_daxpy.o): In function `HPL_daxpy':
HPL_daxpy.c:(.text+0x2f): undefined reference to `daxpy_'
../../../lib/myarch/libhpl.a(HPL_dscal.o): In function `HPL_dscal':
HPL_dscal.c:(.text+0x22): undefined reference to `dscal_'
../../../lib/myarch/libhpl.a(HPL_idamax.o): In function `HPL_idamax':
HPL_idamax.c:(.text+0x1a): undefined reference to `idamax_'
../../../lib/myarch/libhpl.a(HPL_dgemv.o): In function `HPL_dgemv':
HPL_dgemv.c:(.text+0xba): undefined reference to `dgemv_'
HPL_dgemv.c:(.text+0x136): undefined reference to `dgemv_'
Here's what I really don't understand. Take dgemv for instance. libhpl.a does indeed invoke it:
>$ nm libhpl.a | grep dgemv
HPL_dgemv.o:
U dgemv_
Now, libcblas.a has a reference to it, but needs the version in ATLAS:
>$ nm libcblas.a | grep dgemv
cblas_dgemv.o:
U ATL_dgemv
Finally, does ATLAS have ATL_dgemv?
ATL_dgemv.o:
0000000000000000 T ATL_dgemv
So, yes, it certainly does. So CBLAS has a dgemv that HPCC should (I would think) be able to plug into, but it needs ATL_dgemv. But ATLAS has ATL_dgemv. So why can't the linker find everything it needs for HPCC?
Thanks.
Your logs indicate that libhpl.a needs the dgemv_ symbol that is not provided either by libcblas.a nor libatlas.a (I assume your last command was nm libatlas.a | grep dgemv).
The trailing underscore in dgemv_ strongly suggests it requires the Fortran BLAS(and not the C BLAS) library, so you can simply replace libcblas.a with libblas.a.
IIRC, an other option is to tweak the HPL config and direct it to use cblas instead of (Fortran) BLAS.

Correct usage of strip tool

Unpacked Linaro GCC 6.2-2016.11 toolchain occupies almost 3.4 GB of disc space and I want to make it smaller. My target is armv7-a+vfpv3+hard_float so I have already removed things I do not need (like ld.gold, libraries for Thumb, v8-a, v7ve etc) but it still occupies almost 1 GB.
So I want to use strip tool to remove redundant information from its binaries.
My main question is how to use strip safety, correctly and efficiently in this case?
In general we have different binary files in toolchain to which we can apply strip: *.exe, *.a, *.o.
As I can judge I can apply strip -s (remove all symbols) only to *.exe files (i.g. arm-eabi-gcc.exe). Am I right?
Is it possible to apply strip to libraries (i.g. libgcc.a)?
As I understood (see example above) symbols in libraries may be needed for further processing.
If yes, should I use --strip-debug instead (remove debugging symbols only)?
Example below illustrates these questions and reveals more.
Assume that we have three files:
// main.c:
#include "libgcc_test.h"
int main(void)
{
do_something();
return 0;
}
// libgcc_test.c:
void do_something(void)
{
return;
}
// libgcc_test.h:
void do_something(void);
In general we just compile each file separately to get object files which can be linked together:
$ ./arm-eabi-gcc.exe main.c -c
$ ./arm-eabi-gcc.exe libgcc_test.c -c
By analyzing object files we can see that do_something symbol is defined in libgcc_test.o and undefined in main.o, as expected:
$ ./arm-eabi-nm.exe main.o
U do_something
00000000 T main
$ ./arm-eabi-nm.exe libgcc_test.o
00000000 T do_something
If we apply strip -s to both files or only to main.o and try to link them, it works:
$ ./arm-eabi-nm.exe main.o
arm-eabi-nm.exe: main.o: no symbols
$ ./arm-eabi-nm.exe libgcc_test.o
arm-eabi-nm.exe: libgcc_test.o: no symbols
$ ./arm-eabi-ld.exe libgcc_test.o main.o -o main
arm-eabi-ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000
But if we apply strip -s only to libgcc_test.o, linker produces error message:
$ ./arm-eabi-strip.exe -s libgcc_test.o
$ ./arm-eabi-ld.exe libgcc_test.o main.o -o main
arm-eabi-ld.exe: warning: cannot find entry symbol _start; defaulting to 00008000
main.o: In function `main':
main.c:(.text+0x8): undefined reference to `do_something'
As I understand presence of unresolved symbol in an object file forces linker to resolve it. What happens if I remove this symbol from an object file before linking?
Is it correct and safe to remove symbols from object files before linking them together? If yes, which symbols can be removed?
In real project if we apply strip -s to toolchain libraries (libgcc.a, libc.a, libm.a, librdimon.a etc) it similarly produces a lot of "undefined reference to..." messages during linking stage.
But if we use --strip-debug option, linker produces messages for libraries like skipping incompatible libgcc.a when searching for -lgcc. If we revert libraries, it is linked successfuly.
What does skipping incompatible... message mean in this case?
Thank you for help.
Just to summarize how I did it. Maybe it will be useful for someone.
I just removed unnecessary libraries/executables and applied strip -s to *.exe files only.
After that all the toolchain appeared to be ~230 MB.

Loadable Bash Builtin

I'm writing a strcmp bash builtin. It compiles fine, but when I try to enable it, I get:
$ enable -f ./strcmp strcmp
bash: enable: cannot open shared object ./strcmp: ./strcmp: only ET_DYN and ET_EXEC can be loaded
The big parts of my builtin:
strcmp_builtin (list)
WORD_LIST *list;
char *strcmp_doc[] = {
(char *)NULL
};
struct builtin strcmp_struct = {
"strcmp", /* builtin name */
strcmp_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
strcmp_doc, /* array of long documentation strings. */
"strcmp 'string 1' 'string 2'", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
The compile line (from the expanded make file):
~/bash-4.2/examples/loadables $ gcc -fPIC -DHAVE_CONFIG_H -DSHELL \
-g -O2 -I. -I.. -I../.. -I../../lib -I../../builtins -I../../include \
-I~/bash-4.2 -I~/bash-4.2/lib -I~/bash-4.2/builtins -c \
-o strcmp strcmp.c
I have googled ET_DYN and ET_EXEC, and only found links to questions like this.
Did you notice the -c flag? That's keeping it from linking. Replace that with -shared, as #shr mentioned
A little follow up on an answer to my specific question (ET_DYN and ET_EXEC), as well as an expansion on WHY #stanparker's answer is correct.
ET_DYN and ET_EXEC are ELF Executable types. In the ELF header, there is a field Elf32_Half e_type or Elf64_Half e_type with several possibly ET_* enums. I'm guessing ET is "Executable Type", EXEC executable and DYN Dynamic. This should all be enough to show that the emitted artifact was not, in fact, an executable object of any kind, and should have encouraged looking closer at the GCC flags. (For more on the ELF headers, http://www.sco.com/developers/gabi/1998-04-29/ch4.eheader.html)
Now that we see we aren't linking, let's remove the -c flag. Then, we'll get a second error (this time somewhere in the compile),
$ gcc [...] -o strcmp.o strcmp.c
/usr/lib/gcc/i686-redhat-linux/4.6.0/../../../crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccaiMtdc.o: In function `strcmp_builtin':
~/bash-4.2/examples/loadables/strcmp.c:32: undefined reference to `make_builtin_argv'
collect2: ld returned 1 exit status
There are actually two errors here. The first is "undefined reference to `main'", the second is "undefined reference to `make_builtin_argv'" (a bash internal function). The last line is enough to show us GCC is dying during linking. The function _start is a common entry point defined by glibc, which itself actually calls main in the program. At this point, duh, we aren't making an executable, but a shared lib. Adding -shared to the command line gets us compiling perfectly.
So, why wasn't make giving me the "Correct" command line? Makefile.in doesn't dynamically test for source files, so I should have added the .c and .o targets by hand, then rerunning ./configure. After doing so, we get
$ make strcmp
gcc [...] -c -o strcmp.o strcmp.c
gcc -shared -Wl,-soname,strcmp -L./lib/termcap -o strcmp strcmp.o
Does it work?
$ enable -f ./strcmp strcmp
$ strcmp "hi" "ho"
$ echo $?
2
$ strcmp "hi" "ha"
$ echo $?
1
$ strcmp "hi" "hi"
$ echo $?
0
That's what I expect it to do, so it seems it does work.
Anyway, the point of me writing this up is that this is not the first time I've personally gotten messed up on GCC and C compiling in general. This is not the first time I've seen someone have these problems in general. There is a tremendous amount of work that goes into getting a successful C compile, and each phase is important. So, I'm writing this up to remind myself of exactly what GCC (cc, ld, and the elf libs) were doing, why the one little character here and there is important, and the overall discovery process. I haven't seen it typed up anywhere else, so here is what I have.
PS. For those interested in this builtin, it will be on my site, http://davidsouther.com/2011/08/bash-strcmp-builtin/
I'm not sure, but... Ever tried gcc -shared ?

Linking a C program directly with ld fails with undefined reference to `__libc_csu_fini`

I'm trying to compile a C program under Linux. However, out of curiosity, I'm trying to execute some steps by hand: I use:
the gcc frontend to produce assembler code
then run the GNU assembler to get an object file
and then link it with the C runtime to get a working executable.
Now I'm stuck with the linking part.
The program is a very basic "Hello world":
#include <stdio.h>
int main() {
printf("Hello\n");
return 0;
}
I use the following command to produce the assembly code:
gcc hello.c -S -masm=intel
I'm telling gcc to quit after compiling and dump the assembly code with Intel syntax.
Then I use th GNU assembler to produce the object file:
as -o hello.o hello.s
Then I try using ld to produce the final executable:
ld hello.o /usr/lib/libc.so /usr/lib/crt1.o -o hello
But I keep getting the following error message:
/usr/lib/crt1.o: In function `_start':
(.text+0xc): undefined reference to `__libc_csu_fini'
/usr/lib/crt1.o: In function `_start':
(.text+0x11): undefined reference to `__libc_csu_init'
The symbols __libc_csu_fini/init seem to be a part of glibc, but I can't find them anywhere! I tried linking against libc statically (against /usr/lib/libc.a) with the same result.
What could the problem be?
/usr/lib/libc.so is a linker script which tells the linker to pull in the shared library /lib/libc.so.6, and a non-shared portion, /usr/lib/libc_nonshared.a.
__libc_csu_init and __libc_csu_fini come from /usr/lib/libc_nonshared.a. They're not being found because references to symbols in non-shared libraries need to appear before the archive that defines them on the linker line. In your case, /usr/lib/crt1.o (which references them) appears after /usr/lib/libc.so (which pulls them in), so it doesn't work.
Fixing the order on the link line will get you a bit further, but then you'll probably get a new problem, where __libc_csu_init and __libc_csu_fini (which are now found) can't find _init and _fini. In order to call C library functions, you should also link /usr/lib/crti.o (after crt1.o but before the C library) and /usr/lib/crtn.o (after the C library), which contain initialisation and finalisation code.
Adding those should give you a successfully linked executable. It still won't work, because it uses the dynamically linked C library without specifying what the dynamic linker is. You'll need to tell the linker that as well, with something like -dynamic-linker /lib/ld-linux.so.2 (for 32-bit x86 at least; the name of the standard dynamic linker varies across platforms).
If you do all that (essentially as per Rob's answer), you'll get something that works in simple cases. But you may come across further problems with more complex code, as GCC provides some of its own library routines which may be needed if your code uses certain features. These will be buried somewhere deep inside the GCC installation directories...
You can see what gcc is doing by running it with either the -v option (which will show you the commands it invokes as it runs), or the -### option (which just prints the commands it would run, with all of the arguments quotes, but doesn't actually run anything). The output will be confusing unless you know that it usually invokes ld indirectly via one of its own components, collect2 (which is used to glue in C++ constructor calls at the right point).
I found another post which contained a clue: -dynamic-linker /lib/ld-linux.so.2.
Try this:
$ gcc hello.c -S -masm=intel
$ as -o hello.o hello.s
$ ld -o hello -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o hello.o -lc /usr/lib/crtn.o
$ ./hello
hello, world
$
Assuming that a normal invocation of gcc -o hello hello.c produces a working build, run this command:
gcc --verbose -o hello hello.c
and gcc will tell you how it's linking things. That should give you a good idea of everything that you might need to account for in your link step.
In Ubuntu 14.04 (GCC 4.8), the minimal linking command is:
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 \
/usr/lib/x86_64-linux-gnu/crt1.o \
/usr/lib/x86_64-linux-gnu/crti.o \
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/ \
-lc -lgcc -lgcc_s \
hello.o \
/usr/lib/x86_64-linux-gnu/crtn.o
Although they may not be necessary, you should also link to -lgcc and -lgcc_s, since GCC may emit calls to functions present in those libraries for operations which your hardware does not implement natively, e.g. long long int operations on 32-bit. See also: Do I really need libgcc?
I had to add:
-L/usr/lib/gcc/x86_64-linux-gnu/4.8/ \
because the default linker script does not include that directory, and that is where libgcc.a was located.
As mentioned by Michael Burr, you can find the paths with gcc -v. More precisely, you need:
gcc -v hello_world.c |& grep 'collect2' | tr ' ' '\n'
This is how I fixed it on ubuntu 11.10:
apt-get remove libc-dev
Say yes to remove all the packages but copy the list to reinstall after.
apt-get install libc-dev
If you're running a 64-bit OS, your glibc(-devel) may be broken. By looking at this and this you can find these 3 possible solutions:
add lib64 to LD_LIBRARY_PATH
use lc_noshared
reinstall glibc-devel
Since you are doing the link process by hand, you are forgetting to link the C run time initializer, or whatever it is called.
To not get into the specifics of where and what you should link for you platform, after getting your intel asm file, use gcc to generate (compile and link) your executable.
simply doing gcc hello.c -o hello should work.
Take it:
$ echo 'main(){puts("ok");}' > hello.c
$ gcc -c hello.c -o hello.o
$ ld hello.o -o hello.exe /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtn.o \
-dynamic-linker /lib/ld-linux.so.2 -lc
$ ./hello.exe
ok
Path to /usr/lib/crt*.o will when glibc configured with --prefix=/usr

Resources