Index: kernel/arch/amd64/_link.ld.in
===================================================================
--- kernel/arch/amd64/_link.ld.in	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/_link.ld.in	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -14,8 +14,25 @@
 ENTRY(multiboot_image_start)
 
+PHDRS {
+	ap_boot PT_LOAD ;
+	unmapped PT_LOAD ;
+	mapped PT_LOAD ;
+}
+
 SECTIONS {
 	kernel_load_address = PA2KA(BOOT_OFFSET);
 
-	.unmapped (BOOT_OFFSET + SIZEOF_HEADERS): AT (BOOT_OFFSET + SIZEOF_HEADERS) {
+	.ap_bootstrap (AP_BOOT_OFFSET): AT (AP_BOOT_OFFSET) {
+		ap_bootstrap_start = .;
+
+		/* Must be first. */
+		*(.multiboot);
+
+		*(K_AP_TEXT_START);
+		*(K_AP_DATA_START);
+		ap_bootstrap_end = .;
+	} :ap_boot
+
+	.unmapped (BOOT_OFFSET): AT (BOOT_OFFSET) {
 		unmapped_start = .;
 		*(K_TEXT_START);
@@ -23,7 +40,7 @@
 		*(K_INI_PTLS);
 		unmapped_end = .;
-	}
+	} :unmapped
 
-	.mapped (PA2KA(BOOT_OFFSET) + SIZEOF_HEADERS + SIZEOF(.unmapped)) : AT (BOOT_OFFSET + SIZEOF_HEADERS + SIZEOF(.unmapped)) {
+	.mapped (PA2KA(BOOT_OFFSET) + SIZEOF(.unmapped)) : AT (BOOT_OFFSET + SIZEOF(.unmapped)) {
 		ktext_start = .;
 		*(.text .text.*);
@@ -43,5 +60,5 @@
 
 		kdata_end = .;
-	}
+	} :mapped
 
 #ifdef CONFIG_LINE_DEBUG
@@ -63,6 +80,4 @@
 
 #ifdef CONFIG_SMP
-	ap_boot = unmapped_ap_boot - BOOT_OFFSET + AP_BOOT_OFFSET;
-	ap_gdtr = unmapped_ap_gdtr - BOOT_OFFSET + AP_BOOT_OFFSET;
 	protected_ap_gdtr = PA2KA(ap_gdtr);
 #endif /* CONFIG_SMP */
Index: kernel/arch/amd64/include/arch/boot/boot.h
===================================================================
--- kernel/arch/amd64/include/arch/boot/boot.h	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/include/arch/boot/boot.h	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -42,5 +42,6 @@
 #ifndef __ASSEMBLER__
 
-extern uint8_t unmapped_end[];
+extern uint8_t ap_bootstrap_start[];
+extern uint8_t ap_bootstrap_end[];
 
 #endif /* __ASSEMBLER__ */
Index: kernel/arch/amd64/src/amd64.c
===================================================================
--- kernel/arch/amd64/src/amd64.c	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/src/amd64.c	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -92,10 +92,4 @@
 	multiboot_info_parse(signature, (multiboot_info_t *) info);
 	multiboot2_info_parse(signature, (multiboot2_info_t *) info);
-
-#ifdef CONFIG_SMP
-	size_t unmapped_size = (uintptr_t) unmapped_end - BOOT_OFFSET;
-	/* Copy AP bootstrap routines below 1 MB. */
-	memcpy((void *) AP_BOOT_OFFSET, (void *) BOOT_OFFSET, unmapped_size);
-#endif
 }
 
Index: kernel/arch/amd64/src/boot/multiboot.S
===================================================================
--- kernel/arch/amd64/src/boot/multiboot.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/src/boot/multiboot.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -46,27 +46,5 @@
 #define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
 
-.section K_TEXT_START, "ax"
-
-.code32
-
-.macro pm_error msg
-	movl \msg, %esi
-	jmp pm_error_halt
-.endm
-
-.macro pm_status msg
-#if defined(CONFIG_EGA) && !defined(CONFIG_FB)
-	pushl %esi
-	movl \msg, %esi
-	call pm_early_puts
-	popl %esi
-#endif
-.endm
-
-.macro pm2_status msg
-#ifndef CONFIG_FB
-	pm_status \msg
-#endif
-.endm
+.section .multiboot, "a"
 
 .align 4
@@ -91,4 +69,28 @@
 	.long CONFIG_BFB_BPP
 #endif
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.macro pm_error msg
+	movl \msg, %esi
+	jmp pm_error_halt
+.endm
+
+.macro pm_status msg
+#if defined(CONFIG_EGA) && !defined(CONFIG_FB)
+	pushl %esi
+	movl \msg, %esi
+	call pm_early_puts
+	popl %esi
+#endif
+.endm
+
+.macro pm2_status msg
+#ifndef CONFIG_FB
+	pm_status \msg
+#endif
+.endm
 
 SYMBOL(multiboot_image_start)
Index: kernel/arch/amd64/src/boot/multiboot2.S
===================================================================
--- kernel/arch/amd64/src/boot/multiboot2.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/src/boot/multiboot2.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -35,7 +35,5 @@
 #include <genarch/multiboot/multiboot2.h>
 
-.section K_TEXT_START, "ax"
-
-.code32
+.section .multiboot, "a"
 
 .align 8
Index: kernel/arch/amd64/src/smp/ap.S
===================================================================
--- kernel/arch/amd64/src/smp/ap.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/amd64/src/smp/ap.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -41,5 +41,5 @@
 #include <arch/context_struct.h>
 
-.section K_TEXT_START, "ax"
+.section K_AP_TEXT_START, "ax"
 
 #ifdef CONFIG_SMP
@@ -50,5 +50,6 @@
 
 .align 4096
-SYMBOL(unmapped_ap_boot)
+
+SYMBOL(ap_boot)
 .code16
 	cli
@@ -61,5 +62,5 @@
 	orl $CR0_PE, %eax
 	movl %eax, %cr0     # switch to protected mode
-	jmpl $GDT_SELECTOR(KTEXT32_DES), $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT32_DES), $jump_to_kernel
 
 jump_to_kernel:
@@ -94,5 +95,5 @@
 
 	# At this point we are in compatibility mode
-	jmpl $GDT_SELECTOR(KTEXT_DES), $start64 - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $GDT_SELECTOR(KTEXT_DES), $start64
 
 .code64
@@ -109,9 +110,9 @@
 #endif /* CONFIG_SMP */
 
-.section K_DATA_START, "aw", @progbits
+.section K_AP_DATA_START, "aw", @progbits
 
 #ifdef CONFIG_SMP
 
-SYMBOL(unmapped_ap_gdtr)
+SYMBOL(ap_gdtr)
 	.word 0
 	.long 0
Index: kernel/arch/ia32/_link.ld.in
===================================================================
--- kernel/arch/ia32/_link.ld.in	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/_link.ld.in	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -14,15 +14,32 @@
 ENTRY(multiboot_image_start)
 
+PHDRS {
+	ap_boot PT_LOAD ;
+	unmapped PT_LOAD ;
+	mapped PT_LOAD ;
+}
+
 SECTIONS {
 	kernel_load_address = PA2KA(BOOT_OFFSET);
 
-	.unmapped (BOOT_OFFSET + SIZEOF_HEADERS): AT (BOOT_OFFSET + SIZEOF_HEADERS) {
+	.ap_bootstrap (AP_BOOT_OFFSET): AT (AP_BOOT_OFFSET) {
+		ap_bootstrap_start = .;
+
+		/* Must be first. */
+		*(.multiboot);
+
+		*(K_AP_TEXT_START);
+		*(K_AP_DATA_START);
+		ap_bootstrap_end = .;
+	} :ap_boot
+
+	.unmapped (BOOT_OFFSET): AT (BOOT_OFFSET) {
 		unmapped_start = .;
 		*(K_TEXT_START);
 		*(K_DATA_START);
 		unmapped_end = .;
-	}
+	} :unmapped
 
-	.mapped (PA2KA(BOOT_OFFSET) + SIZEOF_HEADERS + SIZEOF(.unmapped)): AT (BOOT_OFFSET + SIZEOF_HEADERS + SIZEOF(.unmapped)) {
+	.mapped (PA2KA(BOOT_OFFSET) + SIZEOF(.unmapped)): AT (BOOT_OFFSET + SIZEOF(.unmapped)) {
 		ktext_start = .;
 		*(.text .text.*);
@@ -41,5 +58,5 @@
 		*(symtab.*);            /* Symbol table, must be LAST symbol! */
 		kdata_end = .;
-	}
+	} :mapped
 
 #ifdef CONFIG_LINE_DEBUG
@@ -61,9 +78,5 @@
 
 #ifdef CONFIG_SMP
-
-	ap_boot = unmapped_ap_boot - BOOT_OFFSET + AP_BOOT_OFFSET;
-	ap_gdtr = unmapped_ap_gdtr - BOOT_OFFSET + AP_BOOT_OFFSET;
 	protected_ap_gdtr = PA2KA(ap_gdtr);
-
 #endif /* CONFIG_SMP */
 
Index: kernel/arch/ia32/include/arch/boot/boot.h
===================================================================
--- kernel/arch/ia32/include/arch/boot/boot.h	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/include/arch/boot/boot.h	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -44,5 +44,6 @@
 #ifdef CONFIG_SMP
 
-extern uint8_t unmapped_end[];
+extern uint8_t ap_bootstrap_start[];
+extern uint8_t ap_bootstrap_end[];
 
 #endif /* CONFIG_SMP */
Index: kernel/arch/ia32/src/boot/multiboot.S
===================================================================
--- kernel/arch/ia32/src/boot/multiboot.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/src/boot/multiboot.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -46,21 +46,5 @@
 #define START_STACK  (BOOT_OFFSET - BOOT_STACK_SIZE)
 
-.section K_TEXT_START, "ax"
-
-.code32
-
-.macro pm_status msg
-#if defined(CONFIG_EGA) && !defined(CONFIG_FB)
-	pushl %esi
-	movl \msg, %esi
-	call pm_early_puts
-	popl %esi
-#endif
-.endm
-
-.macro pm2_status msg
-	pushl \msg
-	call early_puts
-.endm
+.section .multiboot, "a"
 
 .align 4
@@ -85,4 +69,22 @@
 	.long CONFIG_BFB_BPP
 #endif
+
+.section K_TEXT_START, "ax"
+
+.code32
+
+.macro pm_status msg
+#if defined(CONFIG_EGA) && !defined(CONFIG_FB)
+	pushl %esi
+	movl \msg, %esi
+	call pm_early_puts
+	popl %esi
+#endif
+.endm
+
+.macro pm2_status msg
+	pushl \msg
+	call early_puts
+.endm
 
 SYMBOL(multiboot_image_start)
Index: kernel/arch/ia32/src/boot/multiboot2.S
===================================================================
--- kernel/arch/ia32/src/boot/multiboot2.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/src/boot/multiboot2.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -33,7 +33,5 @@
 #include <genarch/multiboot/multiboot2.h>
 
-.section K_TEXT_START, "ax"
-
-.code32
+.section .multiboot, "a"
 
 .align 8
Index: kernel/arch/ia32/src/ia32.c
===================================================================
--- kernel/arch/ia32/src/ia32.c	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/src/ia32.c	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -92,10 +92,4 @@
 	multiboot_info_parse(signature, (multiboot_info_t *) info);
 	multiboot2_info_parse(signature, (multiboot2_info_t *) info);
-
-#ifdef CONFIG_SMP
-	size_t unmapped_size = (uintptr_t) unmapped_end - BOOT_OFFSET;
-	/* Copy AP bootstrap routines below 1 MB. */
-	memcpy((void *) AP_BOOT_OFFSET, (void *) BOOT_OFFSET, unmapped_size);
-#endif
 }
 
Index: kernel/arch/ia32/src/mm/frame.c
===================================================================
--- kernel/arch/ia32/src/mm/frame.c	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/src/mm/frame.c	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -152,9 +152,7 @@
 
 #ifdef CONFIG_SMP
-		size_t unmapped_size =
-		    (uintptr_t) unmapped_end - BOOT_OFFSET;
-
-		minconf = max(minconf,
-		    ADDR2PFN(AP_BOOT_OFFSET + unmapped_size));
+		// FIXME: What is the purpose of minconf? Can we remove it?
+		uintptr_t ap_end = ALIGN_UP((uintptr_t) ap_bootstrap_end, FRAME_SIZE);
+		minconf = max(minconf, ADDR2PFN(ap_end));
 #endif
 
@@ -165,7 +163,11 @@
 
 #ifdef CONFIG_SMP
+		// TODO: should go away implicitly with section table
+
 		/* Reserve AP real mode bootstrap memory */
+		size_t ap_size =
+		    ALIGN_UP(ap_bootstrap_end - ap_bootstrap_start, FRAME_SIZE);
 		frame_mark_unavailable(AP_BOOT_OFFSET >> FRAME_WIDTH,
-		    unmapped_size >> FRAME_WIDTH);
+		    ap_size >> FRAME_WIDTH);
 #endif
 	}
Index: kernel/arch/ia32/src/smp/ap.S
===================================================================
--- kernel/arch/ia32/src/smp/ap.S	(revision 2214382eafe65c13cf80c543f085426b751add11)
+++ kernel/arch/ia32/src/smp/ap.S	(revision 6e5252a21fc011ffd91ddded1ae5f8647705f169)
@@ -40,5 +40,5 @@
 #include <arch/context_struct.h>
 
-.section K_TEXT_START, "ax"
+.section K_AP_TEXT_START, "ax"
 
 #ifdef CONFIG_SMP
@@ -54,5 +54,5 @@
 
 .align 4096
-SYMBOL(unmapped_ap_boot)
+SYMBOL(ap_boot)
 .code16
 	cli
@@ -67,5 +67,5 @@
 	orl $CR0_PE, %eax
 	movl %eax, %cr0
-	jmpl $KTEXT, $jump_to_kernel - BOOT_OFFSET + AP_BOOT_OFFSET
+	jmpl $KTEXT, $jump_to_kernel
 
 jump_to_kernel:
@@ -96,9 +96,9 @@
 
 
-.section K_DATA_START, "aw", @progbits
+.section K_AP_DATA_START, "aw", @progbits
 
 #ifdef CONFIG_SMP
 
-SYMBOL(unmapped_ap_gdtr)
+SYMBOL(ap_gdtr)
 	.word 0
 	.long 0
