Program statically linked to newlib failed to run in xv6 - c

I encountered some problems when running newlib-linked programs in xv6. (This is the newlib port I have used)
I used this toolchain to compile the newlib. There aren't any problems in compiling and I do get libc.a, libm.a and other library files.
Then I wrote a hello world program and linked it statically against newlib. The program is simply like this:
#include <stdio.h>
int main()
{ printf("hello world\n");
return 0;
}
But the executable generated is too big for the xv6 filesystem (That's a restriction of design), so I stripped it. After stripping the file size is 53k so it's now ok to put it in fs.
When I run "make qemu" I was able to go into the system, and other programs works fine. But when I run my test program, it stuck for a few second and then it says "panic: loaduvm: addr must be page aligned". Is it because I stripped my program, or there are patches or modifications I have to apply to xv6 source code, or some other reasons?
P.S. I'm using up-to-date version of xv6 from it's offical Github repo, and below is the flags I used to compile my test programs:
cc -fno-pic -static -fno-strict-aliasing -fvar-tracking -fvar-tracking-assignments -static-libgcc -nostartfiles -nostdlib -ffreestanding -nodefaultlibs -fno-builtin -m32 -Wall -MD -gdwarf-2 -fno-omit-frame-pointer -fno-stack-protector -I../include/newlib -o build/_test test.c -L../lib/newlib/ -L../lib/libnosys -e main -Ttext 0 -lc -lm -lnosys

The problem has been solved. I forgot to add a "-N" parameter when linking with GCC.
From my understanding, "-N" and "-Ttext 0" flags both keep the compiled programs aligned in 4k when it is loaded into memory, which is required by xv6.

Related

Why do I get extra system calls when compiling code directly to an executable vs. compiling to an object file and then manually linking?

I want to compile this C code with the GNU C Compiler on Ubuntu without linking any standard libraries, having only the following code execute.
static void exit(long long code)
{asm inline
("movq $60,%%rax\n"
"movq %[code],%%rdi\n"
"syscall"
:
:[code]"rm"(code)
:"rax"
,"rdi");}
static void write(long long fd,char *msg,long long len)
{asm inline
("movq $0x1,%%rax\n"
"movq %[fd],%%rdi\n"
"movq %[msg],%%rsi\n"
"movq %[len],%%rdx\n"
"syscall"
:
:[fd]"rm"(fd)
,[msg]"rm"(msg)
,[len]"rm"(len)
:"rax"
,"rdi"
,"rsi"
,"rdx");}
#define PRINT(msg) write(1,msg,sizeof(msg))
void _start()
{PRINT("Hello World.\n");
exit(0);}
I compiled with cc example.c -ffreestanding -nostartfiles -O3 -o example.
When I called the output file I saw a lot of extra system calls with strace that should not have been there:
brk
arch_prctl
access
mmap
arch_prctl
mprotect
I then compiled like this: cc example.c -c -O3 -o example.o; ld example.o -o example and it did not do the extra syscalls. It even made the filesize somewhat smaller.
The objdump -d of it was exactly the same. In the objdump -D I found some extra symbols (_DYNAMIC,__GNU_EH_FRAME_HDR,.interp) in the first case compared to the second, but still no sign of any extra syscalls in the code.
Do you know why I get the extra system calls with cc example.c -ffreestanding -nostartfiles -O3 -o example and not with cc example.c -c -O3 -o example.o; ld example.o -o example?
I found out what is happening.
If I compile the code with cc example.c -ffreestanding -nostartfiles -O3 -o example the compiler makes a dynamically linked executable. Dynamically linked executables have an .interp section. That is what I was seeing in my objdump -D.
Dynamically linked executables are executing via the program interpreter and the dynamic linker. The additional system calls I saw, came from the dynamic linker. I still do not know why the executable wants to dynamically link anything in a program that does not link any libraries and wants to be freestanding.
If you do not want the extra system calls from the dynamic linker - you should give gcc the extra -static option. The compiler does not automatically do this if there is no dynamic linking happening.

How to compile a C program with a personal library that includes threads

I created a library for my C programs and this includes threads. I usually work with Code::Blocks and I never had problems, but now I need to compile programs directly from terminal. I saw that I need to write -lpthread but also my library name (its name is my_lib.h). I tried to compile first the library with gcc my_lib.c -c and this works; after, I tried this gcc main.c my_lib.h -o main -lpthread, but this doesn't work.
So what is the correctly sintax to compile this program that uses my_lib.h?
I assume my_lib.c is just a module (object file) rather than shared library.
The compiling consists of two parts - compiling into object files and then linking:
# compiling (note the -c)
gcc -c my_lib.c
gcc -c main.c
# linking (no -c, just specify target with -o)
gcc -o main main.o my_lib.o -lpthread
Header files are never compiled (explicitly), they are just included from the .c files and therefore never produce .o file.

Cannot compile using ALSA

I am trying to create an C application on Debian GNU/Linux which uses the PortAudio interface. To do this I must compile my program with gcc -lrt -lasound -ljack -lpthread -o YOUR_BINARY main.c libportaudio.a from this docs.
For this I installed libasound2-dev, and I checked where the files are using apt-file search libasound.so, this is the output:
lib32asound2: /usr/lib32/libasound.so.2
lib32asound2: /usr/lib32/libasound.so.2.0.0
lib32asound2-dev: /usr/lib32/libasound.so
libasound2: /usr/lib/x86_64-linux-gnu/libasound.so.2
libasound2: /usr/lib/x86_64-linux-gnu/libasound.so.2.0.0
libasound2-dev: /usr/lib/x86_64-linux-gnu/libasound.so
So the libasound should be installed correctly, but when I compile my program with this makefile:
DMXTest: main.c libdmx.a
gcc -static -Wall main.c -L. -ldmx -lusb -lrt -lasound -ljack -lfftw3 -g -o main libportaudio.a
I get the following error: /usr/bin/ld: cannot find -lasound.
How can I link this library correctly?
You don't have libasound.a for -static, you will need that, or you can almost certainly just remove -static from the Makefile (likely in LDFLAGS or CFLAGS).
There's is a related Debian bug 522544, and a related Ubuntu bug #993959.
You may be able to build your own libasound from source, though as it also uses other libraries (notably libpthread.so, librt.so and libdl.so) I suspect it may remove some functionality when you build it statically, though it's supported with ./configure --enable-static at build time
(or try --enable-shared=no --enable-static=yes).
FWIW, the use of static binaries is "discouraged" by the glibc maintainers, though I don't agree...
To compile my code i used the following command
gcc -o rec_mic rec_mic.c -lasound
and it works perfectly, without create my own static library.

How to compile c program so that it doesn't depend on any library?

It seems even a hello world program depends on several libraries:
libc.so.6 => /lib64/libc.so.6 (0x00000034f4000000)
/lib64/ld-linux-x86-64.so.2 (0x00000034f3c00000)
How can I static link all stuff ?
Link with -static. "On systems that support dynamic linking, this prevents linking with the shared libraries."
Edit: Yes this will increase the size of your executable. You can go two routes, either do what Marco van de Voort recommends (-nostdlib, bake your own standard library or find a minimal one).
Another route is to try and get GCC to remove as much as it can.
gcc -Wl,--gc-sections -Os -fdata-sections -ffunction-sections -ffunction-sections -static test.c -o test
strip test
Reduces a small test from ~800K to ~700K on my machine, so the reduction isn't really that big.
Previous SO discussions:
Garbage from other linking units
How do I include only used symbols when statically linking with gcc?
Using GCC to find unreachable functions ("dead code")
Update2: If you are content with using just system calls, you can use gcc -ffreestanding -nostartfiles -static to get really small executable files.
Try this file (small.c):
#include <unistd.h>
void _start() {
char msg[] = "Hello!\n";
write(1, msg, sizeof(msg));
_exit(0);
}
Compile using: gcc -ffreestanding -nostartfiles -static -o small small.c && strip small. This produces a ~5K executable on my system (which still has a few sections that ought to be stripable). If you want to go further look at this guide.
Or use -nostdlib and implement your own libraries and startup code.
The various "assembler on *nix" sites can give you an idea how to do it.
If you just want your binary to be small, start by using 32-bit.

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