summaryrefslogtreecommitdiff
path: root/pie
diff options
context:
space:
mode:
authorRuss Dill <Russ.Dill@ti.com>2013-09-17 01:10:23 -0700
committer黄涛 <huangtao@rock-chips.com>2013-11-21 13:39:21 +0800
commit2ecab0b339252a6427b52d03719c96f97f19e272 (patch)
tree0b325933675512e6cd238861c949ca1bc7979561 /pie
parent49d083bd72f8fe93b1d76078be1da897f5e41e98 (diff)
PIE: Support embedding position independent executables
This commit adds support for embedding PIEs into the kernel, loading them into genalloc sections, performing necessary relocations, and running code from them. This allows platforms that need to run code from SRAM, such an during suspend/resume, to develop that code in C instead of assembly. Functions and data for each PIE should be grouped into sections with the __pie(<group>) and __pie_data(<group>) macros respectively. Any symbols or functions that are to be accessed from outside the PIE should be marked with EXPORT_PIE_SYMBOL(<sym>). For example: static struct ddr_timings xyz_timings __pie_data(platformxyz) = { [...] }; void __pie(platformxyz) xyz_ddr_on(void *addr) { [...] } EXPORT_PIE_SYMBOL(xyz_ddr_on); While the kernel can access exported symbols from the PIE, the PIE cannot access symbols from the kernel, but can access data from the kernel and call functions in the kernel so long as addresses are passed into the PIE. PIEs are loaded from the kernel into a genalloc pool with pie_load_sections. pie_load_sections allocates space within the pool, copies the neccesary code/data, and performs any necessary relocations. A chunk identifier is returned for removing the PIE from the pool, and for translating symbols. Because the PIEs are dynamically relocated, special accessors must be used to access PIE symbols from kernel code: - kern_to_pie(chunk, ptr): Translate a PIE symbol to the virtual address it is loaded into within the pool. - fn_to_pie(chunk, ptr): Same as above, but for function pointers. - sram_to_phys(chunk, addr): Translate a virtual address within a loaded PIE to a physical address. Loading a PIE involves three main steps. First a set of common functions to cover built-ins emitted by gcc (memcpy, memmove, etc) is copied into the pool. Then the actual PIE code and data is copied into the pool. Because the PIE code is contained within an overlay with other PIEs, offsets to the common functions are maintained. Finally, relocations are performed as necessary. Signed-off-by: Russ Dill <Russ.Dill@ti.com>
Diffstat (limited to 'pie')
-rw-r--r--pie/.gitignore3
-rw-r--r--pie/Makefile85
2 files changed, 88 insertions, 0 deletions
diff --git a/pie/.gitignore b/pie/.gitignore
new file mode 100644
index 000000000000..4f298035927b
--- /dev/null
+++ b/pie/.gitignore
@@ -0,0 +1,3 @@
+*.syms
+pie.lds
+pie.lds.S
diff --git a/pie/Makefile b/pie/Makefile
new file mode 100644
index 000000000000..9afed70fa0c5
--- /dev/null
+++ b/pie/Makefile
@@ -0,0 +1,85 @@
+#
+# linux/pie/Makefile
+#
+# Copyright 2013 Texas Instruments, Inc.
+# Russ Dill <russ.dill@ti.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+
+obj-y := pie.bin.o
+
+# Report unresolved symbol references
+ldflags-y += --no-undefined
+# Delete all temporary local symbols
+ldflags-y += -X
+
+# Reset objcopy flags, ARM puts "-O binary" here
+OBJCOPYFLAGS =
+
+# Reference gcc builtins for use in PIE with __pie_
+$(obj)/pie_rename.syms: $(KBUILD_LIBPIE)
+ @$(NM) $^ | awk '{if ($$3) print $$3,"__pie_"$$3}' > $@
+
+# For weakening the links to the original gcc builtins
+$(obj)/pie_weaken.syms: $(KBUILD_LIBPIE)
+ @$(NM) $^ | awk '{if ($$3) print "__pie_"$$3}' > $@
+
+# For embedding address of the symbols copied from the PIE into the kernel
+$(obj)/pie.syms: $(obj)/pie.elf
+ @$(NM) $^ | awk '{if ($$3 && $$2 == toupper($$2)) print $$3,"=","0x"$$1" + _binary_pie_pie_bin_start;"}' > $@
+
+# Collect together the libpie objects
+LDFLAGS_libpie_stage1.o += -r
+
+$(obj)/libpie_stage1.o: $(KBUILD_LIBPIE)
+ $(call if_changed,ld)
+
+# Rename the libpie gcc builtins with a __pie_ prefix
+OBJCOPYFLAGS_libpie_stage2.o += --redefine-syms=$(obj)/pie_rename.syms
+OBJCOPYFLAGS_libpie_stage2.o += --rename-section .text=.pie.text
+
+$(obj)/libpie_stage2.o: $(obj)/libpie_stage1.o
+ $(call if_changed,objcopy)
+
+# Generate a version of vmlinux.o with weakened and rename references to gcc
+# builtins.
+OBJCOPYFLAGS_pie_stage1.o += --weaken-symbols=$(obj)/pie_weaken.syms
+OBJCOPYFLAGS_pie_stage1.o += --redefine-syms=$(obj)/pie_rename.syms
+
+$(obj)/pie_stage1.o: $(obj)/../vmlinux.o $(obj)/pie_rename.syms $(obj)/pie_weaken.syms
+ $(call if_changed,objcopy)
+
+# Drop in the PIE versions instead
+LDFLAGS_pie_stage2.o += -r
+# Allow the _GLOBAL_OFFSET_TABLE to redefine
+LDFLAGS_pie_stage2.o += --defsym=_GLOBAL_OFFSET_TABLE_=_GLOBAL_OFFSET_TABLE_
+
+$(obj)/pie_stage2.o: $(obj)/pie_stage1.o $(obj)/libpie_stage2.o
+ $(call if_changed,ld)
+
+# Drop everything but the pie sections
+OBJCOPYFLAGS_pie_stage3.o += -j ".pie.*"
+
+$(obj)/pie_stage3.o: $(obj)/pie_stage2.o
+ $(call if_changed,objcopy)
+
+# Create the position independant executable
+LDFLAGS_pie.elf += -T $(KBUILD_PIE_LDS) --pie --gc-sections
+
+$(obj)/pie.elf: $(obj)/pie_stage3.o $(KBUILD_PIE_LDS)
+ $(call if_changed,ld)
+
+# Create binary data for the kernel
+OBJCOPYFLAGS_pie.bin += -O binary
+
+$(obj)/pie.bin: $(obj)/pie.elf $(obj)/pie.syms
+ $(call if_changed,objcopy)
+
+# Import the data into the kernel
+OBJCOPYFLAGS_pie.bin.o += -B $(ARCH) -I binary -O $(OBJCOPY_OUTPUT_FORMAT)
+
+$(obj)/pie.bin.o: $(obj)/pie.bin
+ $(call if_changed,objcopy)