Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/Makefile.common	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -118,5 +118,5 @@
 LIBDLTEST_PREFIX = $(LIB_PREFIX)/dltest
 
-START_FILES = $(LIBC_PREFIX)/arch/$(UARCH)/src/entry.o
+START_FILES = $(LIBC_PREFIX)/crt0.o $(LIBC_PREFIX)/crt1.o
 
 AFLAGS = --fatal-warnings
@@ -137,9 +137,16 @@
 endif
 
-ifeq ($(STATIC_BUILD),y)
-	BASE_LIBS = $(LIBC_PREFIX)/libc.a
-else
-	BASE_LIBS = $(LIBC_PREFIX)/libc.so.0
+ifneq ($(STATIC_BUILD),y)
 	LINK_DYNAMIC = y
+endif
+
+BASE_LIBS =
+
+ifneq ($(LIBRARY),libc)
+	ifeq ($(STATIC_BUILD),y)
+		BASE_LIBS += $(LIBC_PREFIX)/libc.a
+	else
+		BASE_LIBS += $(LIBC_PREFIX)/libc.so.0
+	endif
 endif
 
@@ -286,5 +293,5 @@
 
 LIB_CFLAGS = $(CFLAGS) -fPIC
-LIB_LDFLAGS = $(LDFLAGS) -shared -Wl,-soname,$(LSONAME)
+LIB_LDFLAGS = $(LDFLAGS) -shared -Wl,-soname,$(LSONAME) -Wl,--no-undefined,--no-allow-shlib-undefined
 
 AS_CFLAGS := $(addprefix -Xassembler ,$(AFLAGS))
@@ -340,8 +347,8 @@
 
 ifneq ($(filter %.cpp %.cc %.cxx, $(SOURCES)),)
-$(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBTAGS) $(CXX_BASE_LIBS)
+$(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBTAGS)
 	$(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -T $(LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ $(START_FILES) $(OBJECTS) $(LIBARGS) $(CXX_BASE_LIBS)
 else
-$(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBTAGS) $(BASE_LIBS)
+$(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBTAGS)
 	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -T $(LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ $(START_FILES) $(OBJECTS) $(LIBARGS) $(BASE_LIBS)
 endif
@@ -350,5 +357,5 @@
 
 ifneq ($(TEST_BINARY),)
-$(TEST_BINARY): $(LINKER_SCRIPT) $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBTAGS) $(BASE_LIBS)
+$(TEST_BINARY): $(LINKER_SCRIPT) $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBTAGS)
 	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -T $(LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ $(START_FILES) $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBARGS) $(BASE_LIBS)
 endif
@@ -368,5 +375,5 @@
 
 $(SLIBRARY): $(LIB_LINKER_SCRIPT) $(LIBRARY).la
-	$(CC) $(CFLAGS) $(LIB_LDFLAGS) $(EXTRA_LDFLAGS) -T $(LIB_LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ -Wl,--whole-archive $(LIBRARY).la -Wl,--no-whole-archive
+	$(CC) $(CFLAGS) $(LIB_LDFLAGS) $(EXTRA_LDFLAGS) -T $(LIB_LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ -Wl,--whole-archive $(LIBRARY).la -Wl,--no-whole-archive $(LIBARGS) $(BASE_LIBS)
 
 $(LSONAME):
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/Makefile	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -207,4 +207,10 @@
 include $(USPACE_PREFIX)/Makefile.common
 
+$(LIBC_PREFIX)/crt0.o: $(LIBC_PREFIX)/arch/$(UARCH)/src/entry.o
+	cp $< $@
+
+$(LIBC_PREFIX)/crt1.o: $(LIBC_PREFIX)/generic/crt/entry.o
+	cp $< $@
+
 $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld: $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld.in
 	$(CC) $(DEFS) $(CFLAGS) -DLIBC_PATH=$(CURDIR) -E -x c $< | grep -v "^\#" > $@
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -57,15 +57,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/abs32le/src/entry.c
===================================================================
--- uspace/lib/c/arch/abs32le/src/entry.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/abs32le/src/entry.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -30,8 +30,8 @@
  */
 
-#include "../../../generic/private/libc.h"
 #include <stddef.h>
 
 extern void _start(void);
+extern void __c_start(void *);
 
 /* Normally, the entry point is defined in assembly for the architecture. */
@@ -39,5 +39,5 @@
 void _start(void)
 {
-	__libc_main(NULL);
+	__c_start(NULL);
 }
 
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -57,15 +57,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/amd64/src/entry.S
===================================================================
--- uspace/lib/c/arch/amd64/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/amd64/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -29,5 +29,5 @@
 #include <abi/asmtool.h>
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -46,4 +46,4 @@
 
 	# %rdi was deliberately chosen as the first argument is also in %rdi
-	# Pass PCB pointer to __libc_main (no operation)
-	call __libc_main
+	# Pass PCB pointer to __c_start (no operation)
+	call __c_start
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -55,15 +55,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/arm32/src/entry.S
===================================================================
--- uspace/lib/c/arch/arm32/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/arm32/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -29,5 +29,5 @@
 #include <abi/asmtool.h>
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -51,7 +51,7 @@
 	sub fp, ip, #4
 
-	# Pass pcb_ptr to __libc_main as the first argument (in r0)
+	# Pass pcb_ptr to __c_start as the first argument (in r0)
 	mov r0, r1
-	bl __libc_main
+	bl __c_start
 
 .data
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -116,15 +116,23 @@
 
 	.init_array : {
-		PROVIDE (__init_array_start = .);
+#ifndef SHLIB
+		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
-		PROVIDE (__init_array_end = .);
+#ifndef SHLIB
+		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
-		PROVIDE (__fini_array_start = .);
+#ifndef SHLIB
+		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
-		PROVIDE (__fini_array_end = .);
+#ifndef SHLIB
+		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/ia32/src/entry.S
===================================================================
--- uspace/lib/c/arch/ia32/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ia32/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -32,5 +32,5 @@
 INTEL_SEP = 11
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -65,5 +65,5 @@
 	movl %esp, %ebp
 
-	# Pass the PCB pointer to __libc_main as the first argument
+	# Pass the PCB pointer to __c_start as the first argument
 	pushl %edi
-	call __libc_main
+	call __c_start
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -65,15 +65,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/ia64/src/entry.S
===================================================================
--- uspace/lib/c/arch/ia64/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ia64/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -29,5 +29,5 @@
 #include <abi/asmtool.h>
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -42,6 +42,6 @@
 	movl gp = __gp
 
-	# Pass PCB pointer as the first argument to __libc_main
+	# Pass PCB pointer as the first argument to __c_start
 	mov out0 = r2 ;;
-	br.call.sptk.many b0 = __libc_main
+	br.call.sptk.many b0 = __c_start
 
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -62,15 +62,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/mips32/src/entry.S
===================================================================
--- uspace/lib/c/arch/mips32/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/mips32/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -31,5 +31,4 @@
 
 .text
-.section .init, "ax"
 
 .set noreorder
@@ -51,9 +50,9 @@
 	.cprestore 16
 
-	# Pass pcb_ptr to __libc_main() as the first argument. It is already
+	# Pass pcb_ptr to __c_start() as the first argument. It is already
 	# in $a0. As the first argument is passed in $a0, no operation
 	# is needed.
 
-	jal __libc_main
+	jal __c_start
 	nop
 
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -55,15 +55,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/ppc32/src/entry.S
===================================================================
--- uspace/lib/c/arch/ppc32/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/ppc32/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -29,5 +29,5 @@
 #include <abi/asmtool.h>
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -45,6 +45,6 @@
 	stwu %r1, -16(%r1)
 
-	# Pass the PCB pointer to __libc_main() as the first argument.
+	# Pass the PCB pointer to __c_start() as the first argument.
 	# The first argument is passed in r3.
 	mr %r3, %r6
-	bl __libc_main
+	bl __c_start
Index: uspace/lib/c/arch/riscv64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/riscv64/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/riscv64/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -54,15 +54,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/riscv64/src/entry.c
===================================================================
--- uspace/lib/c/arch/riscv64/src/entry.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/riscv64/src/entry.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -30,7 +30,6 @@
  */
 
-#include "../../../generic/private/libc.h"
-
 extern void _start(void);
+extern void __c_start(void *);
 
 // FIXME: Implement properly.
@@ -38,5 +37,5 @@
 void _start(void)
 {
-	__libc_main((void *) 0);
+	__c_start(0);
 }
 
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -58,15 +58,23 @@
 
 	.init_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
 		KEEP (*(.init_array .ctors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__init_array_end = .);
+#endif
 	}
 
 	.fini_array : {
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_start = .);
+#endif
 		KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
 		KEEP (*(.fini_array .dtors))
+#ifndef SHLIB
 		PROVIDE_HIDDEN (__fini_array_end = .);
+#endif
 	}
 
Index: uspace/lib/c/arch/sparc64/src/entry.S
===================================================================
--- uspace/lib/c/arch/sparc64/src/entry.S	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/arch/sparc64/src/entry.S	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -29,5 +29,5 @@
 #include <abi/asmtool.h>
 
-.section .init, "ax"
+.text
 
 .org 0
@@ -46,5 +46,5 @@
 	add %g0, -0x7ff, %fp
 
-	# Pass pcb_ptr as the first argument to __libc_main()
-	call __libc_main
+	# Pass pcb_ptr as the first argument to __c_start()
+	call __c_start
 	mov %i1, %o0
Index: uspace/lib/c/generic/as.c
===================================================================
--- uspace/lib/c/generic/as.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/as.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -60,5 +60,5 @@
 {
 	return (void *) __SYSCALL5(SYS_AS_AREA_CREATE, (sysarg_t) base,
-	    (sysarg_t) size, (sysarg_t) flags, (sysarg_t) _end,
+	    (sysarg_t) size, (sysarg_t) flags, (sysarg_t) __progsymbols.end,
 	    (sysarg_t) pager_info);
 }
Index: uspace/lib/c/generic/async/server.c
===================================================================
--- uspace/lib/c/generic/async/server.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/async/server.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -1397,5 +1397,5 @@
 	// FIXME: The source has no business deciding destination address.
 	return ipc_answer_3(call->cap_handle, EOK, (sysarg_t) src, (sysarg_t) flags,
-	    (sysarg_t) _end);
+	    (sysarg_t) __progsymbols.end);
 }
 
@@ -1449,5 +1449,5 @@
 	assert(call);
 
-	return ipc_answer_2(call->cap_handle, EOK, (sysarg_t) _end,
+	return ipc_answer_2(call->cap_handle, EOK, (sysarg_t) __progsymbols.end,
 	    (sysarg_t) dst);
 }
Index: uspace/lib/c/generic/crt/entry.c
===================================================================
--- uspace/lib/c/generic/crt/entry.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
+++ uspace/lib/c/generic/crt/entry.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 CZ.NIC, z.s.p.o.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "../private/libc.h"
+
+/*
+ * We shouldn't be accessing these symbols directly from libc,
+ * since it would create unwanted relocations in shared library
+ * code. Instead, we refer to them here, in a file that's always
+ * statically linked to the main executable, and write their values
+ * to a special structure that resides in libc.
+ */
+
+extern init_array_entry_t __preinit_array_start[] __attribute__((weak));
+extern init_array_entry_t __preinit_array_end[] __attribute__((weak));
+extern init_array_entry_t __init_array_start[] __attribute__((weak));
+extern init_array_entry_t __init_array_end[] __attribute__((weak));
+extern fini_array_entry_t __fini_array_start[] __attribute__((weak));
+extern fini_array_entry_t __fini_array_end[] __attribute__((weak));
+extern int main(int, char *[]);
+extern unsigned char __executable_start[];
+extern unsigned char _end[];
+
+/* __c_start is only called from _start in assembly. */
+void __c_start(void *);
+
+void __c_start(void *pcb)
+{
+	__progsymbols = (progsymbols_t) {
+		.main = main,
+		.elfstart = __executable_start,
+		.end = _end,
+		.preinit_array = __preinit_array_start,
+		.preinit_array_len = __preinit_array_end - __preinit_array_start,
+		.init_array = __init_array_start,
+		.init_array_len = __init_array_end - __init_array_start,
+		.fini_array = __fini_array_start,
+		.fini_array_len = __fini_array_end - __fini_array_start,
+	};
+
+	__libc_main(pcb);
+}
+
Index: uspace/lib/c/generic/ddi.c
===================================================================
--- uspace/lib/c/generic/ddi.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/ddi.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -72,5 +72,5 @@
 {
 	return (errno_t) __SYSCALL5(SYS_PHYSMEM_MAP, (sysarg_t) phys,
-	    pages, flags, (sysarg_t) virt, (sysarg_t) _end);
+	    pages, flags, (sysarg_t) virt, (sysarg_t) __progsymbols.end);
 }
 
@@ -145,5 +145,5 @@
 	return (errno_t) __SYSCALL6(SYS_DMAMEM_MAP, (sysarg_t) size,
 	    (sysarg_t) map_flags, (sysarg_t) flags | DMAMEM_FLAGS_ANONYMOUS,
-	    (sysarg_t) phys, (sysarg_t) virt, (sysarg_t) _end);
+	    (sysarg_t) phys, (sysarg_t) virt, (sysarg_t) __progsymbols.end);
 }
 
Index: uspace/lib/c/generic/elf/elf_mod.c
===================================================================
--- uspace/lib/c/generic/elf/elf_mod.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/elf/elf_mod.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -356,4 +356,8 @@
 		    (void *)((uint8_t *)entry->p_vaddr + elf->bias);
 
+		if (entry->p_filesz == 0) {
+			DPRINTF("Zero-sized ELF interp string.\n");
+			return EE_INVALID;
+		}
 		if (elf->info->interp[entry->p_filesz - 1] != '\0') {
 			DPRINTF("Unterminated ELF interp string.\n");
Index: uspace/lib/c/generic/libc.c
===================================================================
--- uspace/lib/c/generic/libc.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/libc.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -61,4 +61,6 @@
 #endif
 
+progsymbols_t __progsymbols;
+
 static bool env_setup = false;
 
@@ -116,8 +118,14 @@
 	 * C++ Static constructor calls.
 	 */
-	ptrdiff_t init_array_entries = (__init_array_end - __init_array_start);
 
-	for (int i = init_array_entries - 1; i >= 0; --i)
-		__init_array_start[i]();
+	if (__progsymbols.preinit_array) {
+		for (int i = __progsymbols.preinit_array_len - 1; i >= 0; --i)
+			__progsymbols.preinit_array[i]();
+	}
+
+	if (__progsymbols.init_array) {
+		for (int i = __progsymbols.init_array_len - 1; i >= 0; --i)
+			__progsymbols.init_array[i]();
+	}
 
 	/*
@@ -125,5 +133,5 @@
 	 * according the result
 	 */
-	int retval = main(argc, argv);
+	int retval = __progsymbols.main(argc, argv);
 	exit(retval);
 }
@@ -136,8 +144,7 @@
 	 * when the respective constructor is called.
 	 */
-	ptrdiff_t fini_array_entries = (__fini_array_end - __fini_array_start);
 
-	for (int i = 0; i < fini_array_entries; ++i)
-		__fini_array_start[i]();
+	for (int i = 0; i < __progsymbols.fini_array_len; ++i)
+		__progsymbols.fini_array[i]();
 
 	if (env_setup) {
@@ -148,8 +155,5 @@
 
 	__SYSCALL1(SYS_TASK_EXIT, false);
-
-	/* Unreachable */
-	while (true)
-		;
+	__builtin_unreachable();
 }
 
@@ -157,8 +161,5 @@
 {
 	__SYSCALL1(SYS_TASK_EXIT, true);
-
-	/* Unreachable */
-	while (true)
-		;
+	__builtin_unreachable();
 }
 
Index: uspace/lib/c/generic/private/libc.h
===================================================================
--- uspace/lib/c/generic/private/libc.h	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/private/libc.h	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -36,4 +36,9 @@
 #define LIBC_PRIVATE_LIBC_H_
 
+#include <types/common.h>
+
+/* Type of the main C function. */
+typedef int (*main_fn_t)(int, char **);
+
 /**
  * Used for C++ constructors/destructors
@@ -43,14 +48,20 @@
 typedef void (*fini_array_entry_t)();
 
-extern init_array_entry_t __init_array_start[];
-extern init_array_entry_t __init_array_end[];
-extern fini_array_entry_t __fini_array_start[];
-extern fini_array_entry_t __fini_array_end[];
+typedef struct {
+	main_fn_t main;
+	const void *elfstart;
+	const void *end;
+	init_array_entry_t *preinit_array;
+	int preinit_array_len;
+	init_array_entry_t *init_array;
+	int init_array_len;
+	fini_array_entry_t *fini_array;
+	int fini_array_len;
+} progsymbols_t;
 
-extern unsigned char _end[];
+extern progsymbols_t __progsymbols;
 extern void __libc_main(void *) __attribute__((noreturn));
 extern void __libc_exit(int) __attribute__((noreturn));
 extern void __libc_abort(void) __attribute__((noreturn));
-extern int main(int, char *[]);
 
 #endif
Index: uspace/lib/c/generic/rtld/module.c
===================================================================
--- uspace/lib/c/generic/rtld/module.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/rtld/module.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -51,4 +51,6 @@
 #include <rtld/module.h>
 
+#include "../private/libc.h"
+
 /** Create module for static executable.
  *
@@ -73,8 +75,8 @@
 
 	const elf_segment_header_t *tls =
-	    elf_get_phdr(__executable_start, PT_TLS);
+	    elf_get_phdr(__progsymbols.elfstart, PT_TLS);
 
 	if (tls) {
-		uintptr_t bias = elf_get_bias(__executable_start);
+		uintptr_t bias = elf_get_bias(__progsymbols.elfstart);
 		module->tdata = (void *) (tls->p_vaddr + bias);
 		module->tdata_size = tls->p_filesz;
Index: uspace/lib/c/generic/tls.c
===================================================================
--- uspace/lib/c/generic/tls.c	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/generic/tls.c	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -45,4 +45,6 @@
 #include <elf/elf.h>
 
+#include "private/libc.h"
+
 #ifdef CONFIG_RTLD
 #include <rtld/rtld.h>
@@ -61,5 +63,5 @@
 
 	const elf_segment_header_t *tls =
-	    elf_get_phdr(__executable_start, PT_TLS);
+	    elf_get_phdr(__progsymbols.elfstart, PT_TLS);
 
 	if (tls == NULL)
@@ -88,9 +90,9 @@
 
 	const elf_segment_header_t *tls =
-	    elf_get_phdr(__executable_start, PT_TLS);
+	    elf_get_phdr(__progsymbols.elfstart, PT_TLS);
 	if (tls == NULL)
 		return NULL;
 
-	uintptr_t bias = elf_get_bias(__executable_start);
+	uintptr_t bias = elf_get_bias(__progsymbols.elfstart);
 	size_t align = max(tls->p_align, _Alignof(tcb_t));
 
@@ -128,5 +130,5 @@
 #endif
 	const elf_segment_header_t *tls =
-	    elf_get_phdr(__executable_start, PT_TLS);
+	    elf_get_phdr(__progsymbols.elfstart, PT_TLS);
 
 	assert(tls != NULL);
Index: uspace/lib/c/include/elf/elf.h
===================================================================
--- uspace/lib/c/include/elf/elf.h	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/c/include/elf/elf.h	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -41,6 +41,4 @@
 #include <libarch/elf.h>
 
-extern const uint8_t __executable_start[];
-
 extern const elf_segment_header_t *elf_get_phdr(const void *, unsigned);
 extern uintptr_t elf_get_bias(const void *);
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision c2c4127e98d81c1d3c0bee95147d80082f1b7e66)
+++ uspace/lib/posix/Makefile	(revision 2eadda9562ba40a94f02c6d055a17a045521838d)
@@ -37,7 +37,5 @@
 SPECS = gcc.specs
 LIBC_LINKER_SCRIPT = $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld
-LIBC_STARTUP_FILE = $(START_FILES)
 EXPORT_LINKER_SCRIPT = link.ld
-EXPORT_STARTUP_FILE = crt0.o
 
 EXPORT_FILES = \
@@ -47,6 +45,7 @@
 	$(LIBSOFTINT_PREFIX)/libsoftint.a \
 	$(LIBC_PREFIX)/libc.a \
+	$(LIBC_PREFIX)/crt0.o \
+	$(LIBC_PREFIX)/crt1.o \
 	$(LIBRARY).a \
-	$(EXPORT_STARTUP_FILE) \
 	$(EXPORT_LINKER_SCRIPT) \
 	$(SPECS)
@@ -95,5 +94,6 @@
 	-L$$(HELENOS_EXPORT_ROOT)/lib \
 	-T link.ld \
-	$(EXPORT_STARTUP_FILE)
+	$$(HELENOS_EXPORT_ROOT)/lib/crt0.o \
+	$$(HELENOS_EXPORT_ROOT)/lib/crt1.o
 
 EXPORT_LDLIBS = \
