Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/Makefile.common	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -35,4 +35,5 @@
 #   DEFS               compiler defines
 #   EXTRA_CFLAGS       additional flags to pass to C compiler
+#   LINKER_SCRIPT      linker script
 #   PRE_DEPEND         targets required for dependency check
 #
@@ -112,6 +113,4 @@
 LIBPOSIX_PREFIX = $(LIB_PREFIX)/posix
 LIBDLTEST_PREFIX = $(LIB_PREFIX)/dltest
-
-STARTUP_OBJECT = $(LIBC_PREFIX)/arch/$(UARCH)/src/entry.o
 
 AFLAGS = --fatal-warnings
@@ -141,7 +140,12 @@
 BASE_LIBS += $(LIBSOFTFLOAT_PREFIX)/libsoftfloat.a $(LIBSOFTINT_PREFIX)/libsoftint.a
 
-ifneq ($(LINK_DYNAMIC),y)
+ifeq ($(LINK_DYNAMIC),y)
+	LINKER_SCRIPT ?= $(LIBC_PREFIX)/arch/$(UARCH)/_link-dlexe.ld
+else
 	LDFLAGS += -static
-endif
+	LINKER_SCRIPT ?= $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld
+endif
+
+LIB_LINKER_SCRIPT = $(LIBC_PREFIX)/arch/$(UARCH)/_link-shlib.ld
 
 INCLUDES_FLAGS = $(LIBC_INCLUDES_FLAGS)
@@ -297,11 +301,11 @@
 
 ifneq ($(BINARY),)
-$(BINARY): $(OBJECTS) $(LIBTAGS) $(BASE_LIBS)
-	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -Wl,-Map,$@.map -o $@ $(STARTUP_OBJECT) $(OBJECTS) $(LIBARGS) $(BASE_LIBS)
+$(BINARY): $(LINKER_SCRIPT) $(OBJECTS) $(LIBTAGS) $(BASE_LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -T $(LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ $(OBJECTS) $(LIBARGS) $(BASE_LIBS)
 endif
 
 ifneq ($(TEST_BINARY),)
-$(TEST_BINARY): $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBTAGS) $(BASE_LIBS)
-	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -Wl,-Map,$@.map -o $@ $(STARTUP_OBJECT) $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBARGS) $(BASE_LIBS)
+$(TEST_BINARY): $(LINKER_SCRIPT) $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBTAGS) $(BASE_LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS) -T $(LINKER_SCRIPT) -Wl,-Map,$@.map -o $@ $(TEST_OBJECTS) $(TEST_BINARY_LIBS) $(LIBARGS) $(BASE_LIBS)
 endif
 
@@ -319,6 +323,6 @@
 	$(AR) rc $@ $(LOBJECTS)
 
-$(SLIBRARY): $(LIBRARY).la
-	$(CC) $(CFLAGS) $(LIB_LDFLAGS) $(EXTRA_LDFLAGS) -Wl,-Map,$@.map -o $@ -Wl,--whole-archive $(LIBRARY).la -Wl,--no-whole-archive
+$(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
 
 $(LSONAME):
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/lib/c/Makefile	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -33,4 +33,12 @@
 CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
 
+LINKER_SCRIPTS = \
+	$(LIBC_PREFIX)/arch/$(UARCH)/_link.ld \
+	$(LIBC_PREFIX)/arch/$(UARCH)/_link-shlib.ld \
+	$(LIBC_PREFIX)/arch/$(UARCH)/_link-dlexe.ld
+
+PRE_DEPEND =
+EXTRA_OUTPUT = $(LINKER_SCRIPTS)
+EXTRA_CLEAN = $(LINKER_SCRIPTS)
 LIBRARY = libc
 SOVERSION = 0.0
@@ -182,4 +190,13 @@
 include $(USPACE_PREFIX)/Makefile.common
 
+$(LIBC_PREFIX)/arch/$(UARCH)/_link.ld: $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld.in
+	$(CC) $(DEFS) $(CFLAGS) -DLIBC_PATH=$(CURDIR) -E -x c $< | grep -v "^\#" > $@
+
+$(LIBC_PREFIX)/arch/$(UARCH)/_link-shlib.ld: $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld.in
+	$(CC) $(DEFS) $(CFLAGS) -DLIBC_PATH=$(CURDIR) -DSHLIB -E -x c $< | grep -v "^\#" > $@
+
+$(LIBC_PREFIX)/arch/$(UARCH)/_link-dlexe.ld: $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld.in
+	$(CC) $(DEFS) $(CFLAGS) -DLIBC_PATH=$(CURDIR) -DDLEXE -E -x c $< | grep -v "^\#" > $@
+
 AUTOCHECK = $(realpath $(ROOT_PATH)/tools/autocheck.awk)
 
Index: uspace/lib/c/arch/abs32le/_link.ld.in
===================================================================
--- uspace/lib/c/arch/abs32le/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/abs32le/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,62 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x1000;
+
+	.data : {
+		*(.data);
+		*(.data.rel*);
+	} :data
+
+	.got.plt : {
+		*(.got.plt);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.sbss : {
+		*(.scommon);
+		*(.sbss);
+	}
+
+	.bss : {
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/amd64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/amd64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/amd64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,75 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+	debug PT_NOTE;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x1000;
+
+	.data : {
+		*(.data);
+		*(.data.rel*);
+	} :data
+
+	.got.plt : {
+		*(.got.plt);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/arm32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/arm32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/arm32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,60 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x1000;
+
+	.data : {
+		*(.opd);
+		*(.data .data.*);
+		*(.sdata);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.sbss);
+		*(.scommon);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/ia32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/ia32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,134 @@
+#ifndef SHLIB
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+#endif
+
+PHDRS {
+#if defined(DLEXE)
+	interp PT_INTERP;
+#endif
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+#if defined(SHLIB) || defined(DLEXE)
+	dynamic PT_DYNAMIC;
+#endif
+	debug PT_NOTE;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+#if defined(SHLIB) || defined(DLEXE)
+	.rel.plt : {
+		*(.rel.plt);
+	}
+	/*
+	 *.rel.dyn MUST FOLLOW IMMEDIATELY after .rel.plt
+	 * without alignment gap or DT_REL will be broken
+	 */
+	.rel.dyn : {
+		*(.rel.*);
+	} :text
+
+	.plt : {
+		*(.plt);
+	} :text
+
+	.dynsym : {
+		*(.dynsym);
+	} :text
+
+	.dynstr : {
+		*(.dynstr);
+	} :text
+
+	.hash : {
+		*(.hash .gnu.hash);
+	} :text
+#endif
+
+#if defined(DLEXE)
+	.interp : {
+		*(.interp);
+	} :interp :text
+#endif
+
+	. = . + 0x1000;
+
+#if defined(SHLIB) || defined(DLEXE)
+	.dynamic : {
+		*(.dynamic);
+	} :data :dynamic
+#endif
+
+	.data : {
+		*(.data);
+	} :data
+
+#if defined(SHLIB) || defined(DLEXE)
+	.data.rel : {
+		*(.data.rel .data.rel.*);
+	} :data
+
+	.got : {
+		*(.got);
+	} :data
+#endif
+
+	.got.plt : {
+		*(.got.plt);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.dynbss);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/ia64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ia64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/ia64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,69 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	/* Workaround proper alignment of the .init section */
+	. = ALIGN(., 16);
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x4000;
+
+	.got : {
+		/* Tell the linker where we expect GP to point. */
+		__gp = .;
+		*(.got .got.*);
+	} :data
+
+	.data : {
+		*(.opd);
+		*(.data .data.*);
+		*(.sdata);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.sbss);
+		*(.scommon);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/mips32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/mips32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,67 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(__start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x4000;
+
+	.data : {
+		*(.data);
+		*(.data.rel*);
+	} :data
+
+	.got : {
+		_gp = .;
+		*(.got);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.sbss : {
+		*(.scommon);
+		*(.sbss);
+	}
+
+	.bss : {
+		*(.bss);
+		*(COMMON);
+	} :data
+
+	_end = .;
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/mips32eb/_link.ld.in
===================================================================
--- uspace/lib/c/arch/mips32eb/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/mips32eb/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,1 @@
+../mips32/_link.ld.in
Index: uspace/lib/c/arch/ppc32/_link.ld.in
===================================================================
--- uspace/lib/c/arch/ppc32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/ppc32/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,72 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+	debug PT_NOTE;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x1000;
+
+	.data : {
+		*(.data);
+		*(.sdata);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.sbss);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/riscv64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/riscv64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/riscv64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,71 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+	debug PT_NOTE;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+		*(.srodata .srodata.*);
+	} :text
+
+	. = . + 0x1000;
+
+	.data : {
+		*(.data);
+		*(.sdata);
+		*(.data.rel*);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.scommon);
+		*(.sbss);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/c/arch/sparc64/_link.ld.in
===================================================================
--- uspace/lib/c/arch/sparc64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
+++ uspace/lib/c/arch/sparc64/_link.ld.in	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -0,0 +1,76 @@
+STARTUP(LIBC_PATH/arch/UARCH/src/entry.o)
+ENTRY(_start)
+
+PHDRS {
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	data PT_LOAD FLAGS(6);
+	tls PT_TLS;
+	debug PT_NOTE;
+}
+
+SECTIONS {
+#ifdef SHLIB
+	. = SEGMENT_START("text-segment", 0);
+#else
+	. = SEGMENT_START("text-segment", 0x400000);
+	PROVIDE (__executable_start = .);
+#endif
+	. = . + SIZEOF_HEADERS;
+
+	.init : {
+		*(.init);
+	} :text
+
+	.text : {
+		*(.text .text.*);
+		*(.rodata .rodata.*);
+	} :text
+
+	. = . + 0x4000;
+
+	.got : {
+		 *(.got*);
+	} :data
+
+	.data : {
+		*(.data);
+		*(.sdata);
+	} :data
+
+	.tdata : {
+		*(.tdata);
+		*(.tdata.*);
+		*(.gnu.linkonce.td.*);
+	} :data :tls
+
+	.tbss : {
+		*(.tbss);
+		*(.tbss.*);
+		*(.gnu.linkonce.tb.*);
+	} :data :tls
+
+	.bss : {
+		*(.sbss);
+		*(COMMON);
+		*(.bss);
+	} :data
+
+	_end = .;
+
+#ifdef CONFIG_LINE_DEBUG
+	.comment 0 : { *(.comment); } :debug
+	.debug_abbrev 0 : { *(.debug_abbrev); } :debug
+	.debug_aranges 0 : { *(.debug_aranges); } :debug
+	.debug_info 0 : { *(.debug_info); } :debug
+	.debug_line 0 : { *(.debug_line); } :debug
+	.debug_loc 0 : { *(.debug_loc); } :debug
+	.debug_pubnames 0 : { *(.debug_pubnames); } :debug
+	.debug_pubtypes 0 : { *(.debug_pubtypes); } :debug
+	.debug_ranges 0 : { *(.debug_ranges); } :debug
+	.debug_str 0 : { *(.debug_str); } :debug
+#endif
+
+	/DISCARD/ : {
+		*(*);
+	}
+}
Index: uspace/lib/pcut/Makefile
===================================================================
--- uspace/lib/pcut/Makefile	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/lib/pcut/Makefile	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -36,4 +36,4 @@
 
 test-libpcut-%: $(LIBRARY).a
-	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(STARTUP_OBJECT) $^ $(LIBRARY).a $(BASE_LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(STARTUP) $^ $(LIBRARY).a $(BASE_LIBS)
 
Index: uspace/lib/pcut/update-from-master.sh
===================================================================
--- uspace/lib/pcut/update-from-master.sh	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/lib/pcut/update-from-master.sh	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -80,5 +80,5 @@
 
 test-libpcut-%: $(LIBRARY).a
-	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(STARTUP_OBJECT) $^ $(LIBRARY).a $(BASE_LIBS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(STARTUP) $^ $(LIBRARY).a $(BASE_LIBS)
 
 EOF_MAKEFILE_TAIL
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/lib/posix/Makefile	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -36,5 +36,7 @@
 
 SPECS = gcc.specs
-LIBC_STARTUP_FILE = $(STARTUP_OBJECT)
+LIBC_LINKER_SCRIPT = $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld
+LIBC_STARTUP_FILE = $(shell sed -n -e 's/^.*STARTUP(\(.*\)).*$$/\1/p' $(LIBC_LINKER_SCRIPT))
+EXPORT_LINKER_SCRIPT = link.ld
 EXPORT_STARTUP_FILE = crt0.o
 
@@ -47,4 +49,5 @@
 	$(LIBRARY).a \
 	$(EXPORT_STARTUP_FILE) \
+	$(EXPORT_LINKER_SCRIPT) \
 	$(SPECS)
 
@@ -52,5 +55,5 @@
 EXTRA_CLEAN = $(INCLUDE_LIBC)
 
-EXTRA_OUTPUT = $(SPECS) $(EXPORT_STARTUP_FILE)
+EXTRA_OUTPUT = $(SPECS) $(EXPORT_LINKER_SCRIPT) $(EXPORT_STARTUP_FILE)
 
 SOURCES = \
@@ -87,5 +90,6 @@
 
 EXPORT_LDFLAGS = \
-	-L$$(HELENOS_EXPORT_ROOT)/lib
+	-L$$(HELENOS_EXPORT_ROOT)/lib \
+	-T link.ld
 
 EXPORT_LDLIBS = \
@@ -107,4 +111,7 @@
 	echo '$(EXPORT_LDLIBS)' >> $@.new
 	mv $@.new $@
+
+$(EXPORT_LINKER_SCRIPT): $(LIBC_LINKER_SCRIPT)
+	sed 's/STARTUP(.*)/STARTUP(crt0.o)/' $< > $@
 
 $(EXPORT_STARTUP_FILE): $(LIBC_STARTUP_FILE)
Index: uspace/srv/loader/Makefile
===================================================================
--- uspace/srv/loader/Makefile	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ uspace/srv/loader/Makefile	(revision fc0b2a8b439bd4294aa93f37af1e7fe305fbee77)
@@ -29,19 +29,6 @@
 
 USPACE_PREFIX = ../..
-ROOT_PATH = $(USPACE_PREFIX)/..
-CONFIG_MAKEFILE = $(ROOT_PATH)/Makefile.config
 
-include $(CONFIG_MAKEFILE)
-
-ifeq ($(UARCH),ia64)
-	# IA64 has a peculiar linker script with a fixed data segment address.
-	# Because the loader is a separate nonrelocatable binary in the same
-	# address space as the application, we provide a modified copy of
-	# the default linker script to work around that.
-	EXTRA_LDFLAGS = -T elf64_ia64_loader.x
-else
-	# On all other architectures, we can simply move the text segment.
-	EXTRA_LDFLAGS = -Wl,-Ttext-segment=0x70000000
-endif
+EXTRA_LDFLAGS = -Wl,-Ttext-segment=0x70000000
 
 BINARY = loader
Index: uspace/srv/loader/elf64_ia64_loader.x
===================================================================
--- uspace/srv/loader/elf64_ia64_loader.x	(revision ed88c8e9e48e792fdd0df46568e33e36eb624db3)
+++ 	(revision )
@@ -1,263 +1,0 @@
-/* Default linker script, for normal executables */
-/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
-   Copying and distribution of this script, with or without modification,
-   are permitted in any medium without royalty provided the copyright
-   notice and this notice are preserved.  */
-OUTPUT_FORMAT("elf64-ia64-little", "elf64-ia64-little",
-	      "elf64-ia64-little")
-OUTPUT_ARCH(ia64)
-ENTRY(_start)
-SEARCH_DIR("=/lib");
-SECTIONS
-{
-  /* Read-only sections, merged into text segment: */
-  PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x7FFF000000000000)); . = SEGMENT_START("text-segment", 0x7FFF000000000000) + SIZEOF_HEADERS;
-  .interp         : { *(.interp) }
-  .note.gnu.build-id : { *(.note.gnu.build-id) }
-  .hash           : { *(.hash) }
-  .gnu.hash       : { *(.gnu.hash) }
-  .dynsym         : { *(.dynsym) }
-  .dynstr         : { *(.dynstr) }
-  .gnu.version    : { *(.gnu.version) }
-  .gnu.version_d  : { *(.gnu.version_d) }
-  .gnu.version_r  : { *(.gnu.version_r) }
-  .rel.init       : { *(.rel.init) }
-  .rela.init      : { *(.rela.init) }
-  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
-  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
-  .rel.fini       : { *(.rel.fini) }
-  .rela.fini      : { *(.rela.fini) }
-  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
-  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
-  .rel.data.rel.ro   : { *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) }
-  .rela.data.rel.ro   : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
-  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
-  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
-  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
-  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
-  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
-  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
-  .rel.ctors      : { *(.rel.ctors) }
-  .rela.ctors     : { *(.rela.ctors) }
-  .rel.dtors      : { *(.rel.dtors) }
-  .rela.dtors     : { *(.rela.dtors) }
-  .rel.got        : { *(.rel.got) }
-  .rela.got       : { *(.rela.got) }
-  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
-  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
-  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
-  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
-  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
-  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
-  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
-  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
-  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
-  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
-  .rel.iplt       :
-    {
-      PROVIDE_HIDDEN (__rel_iplt_start = .);
-      *(.rel.iplt)
-      PROVIDE_HIDDEN (__rel_iplt_end = .);
-    }
-  .rela.iplt      :
-    {
-      PROVIDE_HIDDEN (__rela_iplt_start = .);
-      *(.rela.iplt)
-      PROVIDE_HIDDEN (__rela_iplt_end = .);
-    }
-  .rel.plt        :
-    {
-      *(.rel.plt)
-    }
-  .rela.plt       :
-    {
-      *(.rela.plt)
-    }
-  .rela.IA_64.pltoff   : { *(.rela.IA_64.pltoff) }
-  .init           :
-  {
-    KEEP (*(SORT_NONE(.init)))
-  } =0x00300000010070000002000001000400
-  .plt            : { *(.plt) }
-  .iplt           : { *(.iplt) }
-  .text           :
-  {
-    *(.text.unlikely .text.*_unlikely .text.unlikely.*)
-    *(.text.exit .text.exit.*)
-    *(.text.startup .text.startup.*)
-    *(.text.hot .text.hot.*)
-    *(.text .stub .text.* .gnu.linkonce.t.*)
-    /* .gnu.warning sections are handled specially by elf32.em.  */
-    *(.gnu.warning)
-  } =0x00300000010070000002000001000400
-  .fini           :
-  {
-    KEEP (*(SORT_NONE(.fini)))
-  } =0x00300000010070000002000001000400
-  PROVIDE (__etext = .);
-  PROVIDE (_etext = .);
-  PROVIDE (etext = .);
-  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
-  .rodata1        : { *(.rodata1) }
-  .sdata2         :
-  {
-    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
-  }
-  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
-  .opd            : { *(.opd) }
-  .IA_64.unwind_info   : { *(.IA_64.unwind_info* .gnu.linkonce.ia64unwi.*) }
-  .IA_64.unwind   : { *(.IA_64.unwind* .gnu.linkonce.ia64unw.*) }
-  .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
-  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
-  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table
-  .gcc_except_table.*) }
-  .gnu_extab   : ONLY_IF_RO { *(.gnu_extab*) }
-  /* These sections are generated by the Sun/Oracle C++ compiler.  */
-  .exception_ranges   : ONLY_IF_RO { *(.exception_ranges
-  .exception_ranges*) }
-  /* Adjust the address for the data segment.  We want to adjust up to
-     the same address within the page on the next page up.  */
-  . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
-  /* Exception handling  */
-  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
-  .gnu_extab      : ONLY_IF_RW { *(.gnu_extab) }
-  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
-  .exception_ranges   : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
-  /* Thread Local Storage sections  */
-  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
-  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
-  .preinit_array     :
-  {
-    PROVIDE_HIDDEN (__preinit_array_start = .);
-    KEEP (*(.preinit_array))
-    PROVIDE_HIDDEN (__preinit_array_end = .);
-  }
-  .init_array     :
-  {
-    PROVIDE_HIDDEN (__init_array_start = .);
-    KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
-    KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
-    PROVIDE_HIDDEN (__init_array_end = .);
-  }
-  .fini_array     :
-  {
-    PROVIDE_HIDDEN (__fini_array_start = .);
-    KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
-    KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
-    PROVIDE_HIDDEN (__fini_array_end = .);
-  }
-  .jcr            : { KEEP (*(.jcr)) }
-  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
-  .dynamic        : { *(.dynamic) }
-  .data           :
-  {
-    *(.data .data.* .gnu.linkonce.d.*)
-    SORT(CONSTRUCTORS)
-  }
-  .data1          : { *(.data1) }
-  .ctors          :
-  {
-    /* gcc uses crtbegin.o to find the start of
-       the constructors, so we make sure it is
-       first.  Because this is a wildcard, it
-       doesn't matter if the user does not
-       actually link against crtbegin.o; the
-       linker won't look for a file to match a
-       wildcard.  The wildcard also means that it
-       doesn't matter which directory crtbegin.o
-       is in.  */
-    KEEP (*crtbegin.o(.ctors))
-    KEEP (*crtbegin?.o(.ctors))
-    /* We don't want to include the .ctor section from
-       the crtend.o file until after the sorted ctors.
-       The .ctor section from the crtend file contains the
-       end of ctors marker and it must be last */
-    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
-    KEEP (*(SORT(.ctors.*)))
-    KEEP (*(.ctors))
-  }
-  .dtors          :
-  {
-    KEEP (*crtbegin.o(.dtors))
-    KEEP (*crtbegin?.o(.dtors))
-    KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
-    KEEP (*(SORT(.dtors.*)))
-    KEEP (*(.dtors))
-  }
-  .got            : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
-  .IA_64.pltoff   : { *(.IA_64.pltoff) }
-  /* We want the small data sections together, so single-instruction offsets
-     can access them all, and initialized data all before uninitialized, so
-     we can shorten the on-disk segment size.  */
-  .sdata          :
-  {
-    *(.sdata .sdata.* .gnu.linkonce.s.*)
-  }
-  _edata = .; PROVIDE (edata = .);
-  . = .;
-  __bss_start = .;
-  .sbss           :
-  {
-    *(.dynsbss)
-    *(.sbss .sbss.* .gnu.linkonce.sb.*)
-    *(.scommon)
-  }
-  .bss            :
-  {
-   *(.dynbss)
-   *(.bss .bss.* .gnu.linkonce.b.*)
-   *(COMMON)
-   /* Align here to ensure that the .bss section occupies space up to
-      _end.  Align after .bss to ensure correct alignment even if the
-      .bss section disappears because there are no input sections.
-      FIXME: Why do we need it? When there is no .bss section, we don't
-      pad the .data section.  */
-   . = ALIGN(. != 0 ? 64 / 8 : 1);
-  }
-  . = ALIGN(64 / 8);
-  . = SEGMENT_START("ldata-segment", .);
-  . = ALIGN(64 / 8);
-  _end = .; PROVIDE (end = .);
-  /* Stabs debugging sections.  */
-  .stab          0 : { *(.stab) }
-  .stabstr       0 : { *(.stabstr) }
-  .stab.excl     0 : { *(.stab.excl) }
-  .stab.exclstr  0 : { *(.stab.exclstr) }
-  .stab.index    0 : { *(.stab.index) }
-  .stab.indexstr 0 : { *(.stab.indexstr) }
-  .comment       0 : { *(.comment) }
-  /* DWARF debug sections.
-     Symbols in the DWARF debugging sections are relative to the beginning
-     of the section so we begin them at 0.  */
-  /* DWARF 1 */
-  .debug          0 : { *(.debug) }
-  .line           0 : { *(.line) }
-  /* GNU DWARF 1 extensions */
-  .debug_srcinfo  0 : { *(.debug_srcinfo) }
-  .debug_sfnames  0 : { *(.debug_sfnames) }
-  /* DWARF 1.1 and DWARF 2 */
-  .debug_aranges  0 : { *(.debug_aranges) }
-  .debug_pubnames 0 : { *(.debug_pubnames) }
-  /* DWARF 2 */
-  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
-  .debug_abbrev   0 : { *(.debug_abbrev) }
-  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end ) }
-  .debug_frame    0 : { *(.debug_frame) }
-  .debug_str      0 : { *(.debug_str) }
-  .debug_loc      0 : { *(.debug_loc) }
-  .debug_macinfo  0 : { *(.debug_macinfo) }
-  /* SGI/MIPS DWARF 2 extensions */
-  .debug_weaknames 0 : { *(.debug_weaknames) }
-  .debug_funcnames 0 : { *(.debug_funcnames) }
-  .debug_typenames 0 : { *(.debug_typenames) }
-  .debug_varnames  0 : { *(.debug_varnames) }
-  /* DWARF 3 */
-  .debug_pubtypes 0 : { *(.debug_pubtypes) }
-  .debug_ranges   0 : { *(.debug_ranges) }
-  /* DWARF Extension.  */
-  .debug_macro    0 : { *(.debug_macro) }
-  .debug_addr     0 : { *(.debug_addr) }
-  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
-  /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
-}
-
