diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index 1d83966f5ef6..8397af058650 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -28,7 +28,7 @@ p_etext:	.8byte	_etext
 p_bss_start:	.8byte	__bss_start
 p_end:		.8byte	_end
 
-p_toc:		.8byte	__toc_start + 0x8000 - p_base
+p_toc:		.8byte	__toc_ptr - p_base
 p_dyn:		.8byte	__dynamic_start - p_base
 p_rela:		.8byte	__rela_dyn_start - p_base
 p_prom:		.8byte	0
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index d6f072865627..35654cbcd294 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -36,13 +36,11 @@ SECTIONS
   }
 
 #ifdef CONFIG_PPC64_BOOT_WRAPPER
-  . = ALIGN(256);
-  .got :
+  .got : ALIGN(256)
   {
-    __toc_start = .;
-    *(.got)
-    *(.toc)
+    *(.got .toc)
   }
+  __toc_ptr = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
 #endif
 
   .hash : { *(.hash) }
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 324d7b298ec3..4c3e84a2a073 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -49,13 +49,13 @@ static inline int in_kernel_text(unsigned long addr)
 static inline unsigned long kernel_toc_addr(void)
 {
 	/* Defined by the linker, see vmlinux.lds.S */
-	extern unsigned long __toc_start;
+	extern unsigned long __toc_ptr;
 
 	/*
 	 * The TOC register (r2) points 32kB into the TOC, so that 64kB of
 	 * the TOC can be addressed using a single machine instruction.
 	 */
-	return (unsigned long)(&__toc_start) + 0x8000UL;
+	return (unsigned long)&__toc_ptr;
 }
 
 static inline int overlaps_interrupt_vector_text(unsigned long start,
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index ece7f97bafff..1cae5b0943be 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -899,7 +899,7 @@ _GLOBAL(relative_toc)
 	blr
 
 .balign 8
-p_toc:	.8byte	__toc_start + 0x8000 - 0b
+p_toc:	.8byte	__toc_ptr - 0b
 
 /*
  * This is where the main kernel code starts.
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index ccf77b985c8f..d309a7787652 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -3220,27 +3220,26 @@ static void unreloc_toc(void)
 {
 }
 #else
-static void __reloc_toc(unsigned long offset, unsigned long nr_entries)
+static void __reloc_toc(unsigned long offset)
 {
-	unsigned long i;
 	unsigned long *toc_entry;
+	unsigned long *toc_start, *toc_end;
 
-	/* Get the start of the TOC by using r2 directly. */
-	asm volatile("addi %0,2,-0x8000" : "=b" (toc_entry));
+	asm("addis %0,2,__prom_init_toc_start@toc@ha\n\t"
+	    "addi %0,%0,__prom_init_toc_start@toc@l" : "=b" (toc_start));
+	asm("addis %0,2,__prom_init_toc_end@toc@ha\n\t"
+	    "addi %0,%0,__prom_init_toc_end@toc@l" : "=b" (toc_end));
 
-	for (i = 0; i < nr_entries; i++) {
-		*toc_entry = *toc_entry + offset;
-		toc_entry++;
+	for (toc_entry = toc_start; toc_entry != toc_end; toc_entry++) {
+		*toc_entry += offset;
 	}
 }
 
 static void reloc_toc(void)
 {
 	unsigned long offset = reloc_offset();
-	unsigned long nr_entries =
-		(__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
 
-	__reloc_toc(offset, nr_entries);
+	__reloc_toc(offset);
 
 	mb();
 }
@@ -3248,12 +3247,10 @@ static void reloc_toc(void)
 static void unreloc_toc(void)
 {
 	unsigned long offset = reloc_offset();
-	unsigned long nr_entries =
-		(__prom_init_toc_end - __prom_init_toc_start) / sizeof(long);
 
 	mb();
 
-	__reloc_toc(-offset, nr_entries);
+	__reloc_toc(-offset);
 }
 #endif
 #endif
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 72fa3c00229a..343579080dd5 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -326,17 +326,16 @@ SECTIONS
 		__end_opd = .;
 	}
 
-	. = ALIGN(256);
-	.got : AT(ADDR(.got) - LOAD_OFFSET) {
-		__toc_start = .;
+	.got : AT(ADDR(.got) - LOAD_OFFSET) ALIGN(256) {
+		*(.got)
 #ifndef CONFIG_RELOCATABLE
 		__prom_init_toc_start = .;
-		arch/powerpc/kernel/prom_init.o*(.toc .got)
+		arch/powerpc/kernel/prom_init.o*(.toc)
 		__prom_init_toc_end = .;
 #endif
-		*(.got)
 		*(.toc)
 	}
+	__toc_ptr = DEFINED (.TOC.) ? .TOC. : ADDR (.got) + 0x8000;
 #endif
 
 	/* The initial task and kernel stack */
