diff --git a/Makefile b/Makefile
index b09bfcc..5dd28a9 100644
--- a/Makefile
+++ b/Makefile
@@ -392,6 +392,17 @@ else
 BOARD_SIZE_CHECK =
 endif
 
+# Statically apply RELA-style relocations (currently arm64 only)
+ifneq ($(CONFIG_STATIC_RELA),)
+# $(1) is u-boot ELF, $(2) is u-boot bin, $(3) is text base
+DO_STATIC_RELA = \
+	start=$$($(NM) $(1) | grep __rel_dyn_start | cut -f 1 -d ' '); \
+	end=$$($(NM) $(1) | grep __rel_dyn_end | cut -f 1 -d ' '); \
+	$(obj)tools/relocate-rela $(2) $(3) $$start $$end
+else
+DO_STATIC_RELA =
+endif
+
 # Always append ALL so that arch config.mk's can add custom ones
 ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map
 
@@ -431,6 +442,7 @@ $(obj)u-boot.srec:	$(obj)u-boot
 
 $(obj)u-boot.bin:	$(obj)u-boot
 		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
+		$(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
 		$(BOARD_SIZE_CHECK)
 
 $(obj)u-boot.ldr:	$(obj)u-boot
diff --git a/tools/Makefile b/tools/Makefile
index c36cde2..a5eb85e 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -59,6 +59,7 @@ BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
 BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
 BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX)
 BIN_FILES-y += proftool(SFX)
+BIN_FILES-$(CONFIG_STATIC_RELA) += relocate-rela$(SFX)
 
 # Source files which exist outside the tools directory
 EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
@@ -84,6 +85,7 @@ NOPED_OBJ_FILES-y += os_support.o
 NOPED_OBJ_FILES-y += pblimage.o
 NOPED_OBJ_FILES-y += proftool.o
 NOPED_OBJ_FILES-y += ublimage.o
+NOPED_OBJ_FILES-y += relocate-rela.o
 OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o
 OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o
 OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o
@@ -250,6 +252,10 @@ $(obj)kwboot$(SFX): $(obj)kwboot.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
 
+$(obj)relocate-rela$(SFX): $(obj)relocate-rela.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
 # Some of the tool objects need to be accessed from outside the tools directory
 $(obj)%.o: $(SRCTREE)/common/%.c
 	$(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
diff --git a/tools/relocate-rela.c b/tools/relocate-rela.c
new file mode 100644
index 0000000..47afe0b
--- /dev/null
+++ b/tools/relocate-rela.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+ BSD-2-Clause
+ *
+ * 64-bit and little-endian target only until we need to support a different
+ * arch that needs this.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const bool debug_en;
+
+static void debug(const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	if (debug_en)
+		vprintf(fmt, args);
+}
+
+static bool supported_rela(Elf64_Rela *rela)
+{
+	uint64_t mask = 0xffffffffULL; /* would be different on 32-bit */
+	uint32_t type = rela->r_info & mask;
+
+	switch (type) {
+#ifdef R_AARCH64_RELATIVE
+	case R_AARCH64_RELATIVE:
+		return true;
+#endif
+	default:
+		fprintf(stderr, "warning: unsupported relocation type %"
+				PRIu32 " at %" PRIx64 "\n",
+			type, rela->r_offset);
+
+		return false;
+	}
+}
+
+static inline uint64_t swap64(uint64_t val)
+{
+	return ((val >> 56) & 0x00000000000000ffULL) |
+	       ((val >> 40) & 0x000000000000ff00ULL) |
+	       ((val >> 24) & 0x0000000000ff0000ULL) |
+	       ((val >>  8) & 0x00000000ff000000ULL) |
+	       ((val <<  8) & 0x000000ff00000000ULL) |
+	       ((val << 24) & 0x0000ff0000000000ULL) |
+	       ((val << 40) & 0x00ff000000000000ULL) |
+	       ((val << 56) & 0xff00000000000000ULL);
+}
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+static inline uint64_t be64(uint64_t val)
+{
+	return swap64(val);
+}
+
+static inline uint64_t le64(uint64_t val)
+{
+	return val;
+}
+#else
+static inline uint64_t le64(uint64_t val)
+{
+	return swap64(val);
+}
+
+static inline uint64_t be64(uint64_t val)
+{
+	return val;
+}
+#endif
+
+static bool read_num(const char *str, uint64_t *num)
+{
+	char *endptr;
+	*num = strtoull(str, &endptr, 16);
+	return str[0] && !endptr[0];
+}
+
+int main(int argc, char **argv)
+{
+	FILE *f;
+	int i, num;
+	uint64_t rela_start, rela_end, text_base;
+
+	if (argc != 5) {
+		fprintf(stderr, "Statically apply ELF rela relocations\n");
+		fprintf(stderr, "Usage: %s <bin file> <text base> <rela start> <rela end>\n",
+			argv[0]);
+		fprintf(stderr, "All numbers in hex.\n");
+		return 1;
+	}
+
+	f = fopen(argv[1], "r+b");
+	if (!f) {
+		fprintf(stderr, "%s: Cannot open %s: %s\n",
+			argv[0], argv[1], strerror(errno));
+		return 2;
+	}
+
+	if (!read_num(argv[2], &text_base) ||
+	    !read_num(argv[3], &rela_start) ||
+	    !read_num(argv[4], &rela_end)) {
+		fprintf(stderr, "%s: bad number\n", argv[0]);
+		return 3;
+	}
+
+	if (rela_start > rela_end || rela_start < text_base ||
+	    (rela_end - rela_start) % 24) {
+		fprintf(stderr, "%s: bad rela bounds\n", argv[0]);
+		return 3;
+	}
+
+	rela_start -= text_base;
+	rela_end -= text_base;
+
+	num = (rela_end - rela_start) / sizeof(Elf64_Rela);
+
+	for (i = 0; i < num; i++) {
+		Elf64_Rela rela, swrela;
+		uint64_t pos = rela_start + sizeof(Elf64_Rela) * i;
+		uint64_t addr;
+
+		if (fseek(f, pos, SEEK_SET) < 0) {
+			fprintf(stderr, "%s: %s: seek to %" PRIx64
+					" failed: %s\n",
+				argv[0], argv[1], pos, strerror(errno));
+		}
+
+		if (fread(&rela, sizeof(rela), 1, f) != 1) {
+			fprintf(stderr, "%s: %s: read rela failed at %"
+					PRIx64 "\n",
+				argv[0], argv[1], pos);
+			return 4;
+		}
+
+		swrela.r_offset = le64(rela.r_offset);
+		swrela.r_info = le64(rela.r_info);
+		swrela.r_addend = le64(rela.r_addend);
+
+		if (!supported_rela(&swrela))
+			continue;
+
+		debug("Rela %" PRIx64 " %" PRIu64 " %" PRIx64 "\n",
+		      swrela.r_offset, swrela.r_info, swrela.r_addend);
+
+		if (swrela.r_offset < text_base) {
+			fprintf(stderr, "%s: %s: bad rela at %" PRIx64 "\n",
+				argv[0], argv[1], pos);
+			return 4;
+		}
+
+		addr = swrela.r_offset - text_base;
+
+		if (fseek(f, addr, SEEK_SET) < 0) {
+			fprintf(stderr, "%s: %s: seek to %"
+					PRIx64 " failed: %s\n",
+				argv[0], argv[1], addr, strerror(errno));
+		}
+
+		if (fwrite(&rela.r_addend, sizeof(rela.r_addend), 1, f) != 1) {
+			fprintf(stderr, "%s: %s: write failed at %" PRIx64 "\n",
+				argv[0], argv[1], addr);
+			return 4;
+		}
+	}
+
+	if (fclose(f) < 0) {
+		fprintf(stderr, "%s: %s: close failed: %s\n",
+			argv[0], argv[1], strerror(errno));
+		return 4;
+	}
+
+	return 0;
+}
