summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeng Fan <van.freenix@gmail.com>2013-07-18 11:33:55 +0800
committerPeng Fan <van.freenix@gmail.com>2013-07-22 10:51:40 +0800
commit19b3b6033adfe740038a5cd483f05b7c9273a148 (patch)
treefb9b4115a78e1a06ddfa1bc88ce7ffb2fe71877f
parente4b6108400c8df19184fee30beeaa4edde9bca10 (diff)
ARM Support
Signed-off-by: Peng Fan <van.freenix@gmail.com>
-rw-r--r--libbsd/include/arch/arm/machine/elf_machdep.h20
-rw-r--r--rtl-mdreloc-arm.c291
-rw-r--r--testcase/1.c106
-rw-r--r--testcase/2.c14
-rw-r--r--testcase/Readme11
-rw-r--r--testcase/wscript32
-rw-r--r--wscript8
7 files changed, 408 insertions, 74 deletions
diff --git a/libbsd/include/arch/arm/machine/elf_machdep.h b/libbsd/include/arch/arm/machine/elf_machdep.h
index 963ff64..78c88b5 100644
--- a/libbsd/include/arch/arm/machine/elf_machdep.h
+++ b/libbsd/include/arch/arm/machine/elf_machdep.h
@@ -46,7 +46,7 @@
#define R_ARM_THM_ABS5 7
#define R_ARM_ABS8 8
#define R_ARM_SBREL32 9
-#define R_ARM_THM_PC22 10
+#define R_ARM_THM_CALL 10
#define R_ARM_THM_PC8 11
#define R_ARM_AMP_VCALL9 12
#define R_ARM_SWI24 13
@@ -68,6 +68,10 @@
#define R_ARM_GOTPC 25
#define R_ARM_GOT32 26
#define R_ARM_PLT32 27
+#define R_ARM_CALL 28
+#define R_ARM_JUMP24 29
+#define R_ARM_THM_JUMP24 30
+#define R_ARM_BASE_ABS 31
#define R_ARM_ALU_PCREL_7_0 32
#define R_ARM_ALU_PCREL_15_8 33
@@ -75,12 +79,22 @@
#define R_ARM_ALU_SBREL_11_0 35
#define R_ARM_ALU_SBREL_19_12 36
#define R_ARM_ALU_SBREL_27_20 37
+#define R_ARM_V4BX 40
+#define R_ARM_PREL31 41
+
+#define R_ARM_MOVW_ABS_NC 43
+#define R_ARM_MOVT_ABS 44
+
+#define R_ARM_THM_MOVW_ABS_NC 47
+#define R_ARM_THM_MOVT_ABS 48
+
+#define R_ARM_THM_JUMP19 51
/* 96-111 are reserved to G++. */
#define R_ARM_GNU_VTENTRY 100
#define R_ARM_GNU_VTINHERIT 101
-#define R_ARM_THM_PC11 102
-#define R_ARM_THM_PC9 103
+#define R_ARM_THM_JUMP11 102
+#define R_ARM_THM_JUMP8 103
/* More TLS relocations */
#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic */
diff --git a/rtl-mdreloc-arm.c b/rtl-mdreloc-arm.c
index e55da1f..d1bfd5a 100644
--- a/rtl-mdreloc-arm.c
+++ b/rtl-mdreloc-arm.c
@@ -40,6 +40,18 @@ store_ptr(void *where, Elf_Addr val)
memcpy(where, &val, sizeof(val));
}
+/*
+ * The address of Thumb function symbols is it's real address plus one.
+ * This is done by compiler, thus do not consider symtype here.
+ */
+static inline int
+isThumb(Elf_Word symvalue)
+{
+ if ((symvalue & 0x1) == 0x1)
+ return true;
+ else return false;
+}
+
bool
rtems_rtl_elf_rel_resolve_sym (Elf_Word type)
{
@@ -67,7 +79,10 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
const Elf_Word symvalue)
{
Elf_Addr *where;
- Elf_Addr tmp;
+ Elf_Addr tmp;
+ Elf_Word insn, addend;
+ Elf_Word sign, i1, i2;
+ uint16_t lower_insn, upper_insn;
where = (Elf_Addr *)(sect->base + rel->r_offset);
@@ -75,81 +90,221 @@ rtems_rtl_elf_relocate_rel (const rtems_rtl_obj_t* obj,
case R_TYPE(NONE):
break;
-#if 1 /* XXX should not occur */
- case R_TYPE(PC24): { /* word32 S - P + A */
- Elf32_Sword addend;
-
- /*
- * Extract addend and sign-extend if needed.
- */
- addend = *where;
- if (addend & 0x00800000)
- addend |= 0xff000000;
-
- tmp = (Elf_Addr)sect->base + symvalue
- - (Elf_Addr)where + (addend << 2);
-
- if ((tmp & 0xfe000000) != 0xfe000000 &&
- (tmp & 0xfe000000) != 0) {
- rtems_rtl_set_error (EINVAL,
- "R_ARM_PC24 in %s relocation @ %p failed " \
- "(displacement %ld (%#lx) out of range)",
- rtems_rtl_obj_oname (obj), where, (long) tmp, (long) tmp);
- return false;
- }
-
- tmp >>= 2;
- *where = (*where & 0xff000000) | (tmp & 0x00ffffff);
+ case R_TYPE(CALL): /* BL/BLX */
+ case R_TYPE(JUMP24): /* B/BL<cond> */
+ insn = *where;
+
+ if (insn & 0x00800000)
+ addend = insn | 0xff000000;
+ else addend = insn & 0x00ffffff;
+
+ if (isThumb(symvalue)) {
+ if ((insn & 0xfe000000) == 0xfa000000); /* Already blx */
+ else {
+ if ((insn & 0xff000000) == 0xeb000000) { /* BL <label> */
+ *where = (insn & 0x00ffffff) | 0xfa000000; /* BL-->BLX */
+ } else {
+ printf("JUMP24 is not suppored from arm to thumb\n");
+ return false;
+ }
+ }
+ }
+
+ tmp = symvalue + (addend << 2) - (Elf_Addr)where;
+ tmp = (Elf_Sword)tmp >> 2;
+
+ if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
+ printf("CALL/JUMP24 Overflow\n");
+ return false;
+ }
+
+ *where = (*where & 0xff000000) | (tmp & 0xffffff);
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: PC24 %p @ %p in %s",
+ printf ("rtl: JUMP24/PC24/CALL %p @ %p in %s\n",
(void *)*where, where, rtems_rtl_obj_oname (obj));
- break;
- }
-#endif
-
- case R_TYPE(ABS32): /* word32 B + S + A */
- case R_TYPE(GLOB_DAT): /* word32 B + S */
- if (__predict_true(RELOC_ALIGNED_P(where))) {
- tmp = *where + (Elf_Addr)sect->base + symvalue;
- /* Set the Thumb bit, if needed. */
- if (ELF_ST_TYPE(syminfo) == STT_ARM_TFUNC)
+
+ break;
+
+ case R_TYPE(V4BX):
+ /* Miscellaneous, ignore */
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
+ printf ("rtl: V4BX %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ }
+ break;
+
+ case R_TYPE(MOVT_ABS):
+ case R_TYPE(MOVW_ABS_NC):
+ insn = *where;
+
+ addend = ((insn >> 4) & 0xf000) | (insn & 0x0fff);
+ if (addend & 0x8000)
+ addend |= 0xffff0000;
+
+ tmp = symvalue + addend;
+
+ if (ELF_R_TYPE(rel->r_info) == R_TYPE(MOVW_ABS_NC))
+ tmp &= 0xffff;
+ else {
+ tmp = (Elf_Sword)tmp >> 16;
+ if (((Elf_Sword)tmp > 0x7fff) || ((Elf_Sword)tmp < -0x8000)) {
+ printf("MOVT_ABS Overflow\n");
+ return false;
+ }
+ }
+
+ *where = (insn & 0xfff0f000) | ((tmp & 0xf000) << 4) | (tmp & 0xfff);
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
+ printf ("rtl: MOVT_ABS/MOVW_ABS_NC %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
+
+
+ case R_TYPE(REL32): /* word32 (S + A) | T - P */
+ case R_TYPE(ABS32): /* word32 (S + A) | T */
+ case R_TYPE(GLOB_DAT): /* word32 (S + A) | T */
+ if (__predict_true(RELOC_ALIGNED_P(where))) {
+ tmp = *where + symvalue;
+ if (isThumb(symvalue))
+ tmp |= 1;
+ if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
+ tmp -= (Elf_Addr)where;
+ *where = tmp;
+ } else {
+ tmp = load_ptr(where) + symvalue;
+ if (isThumb(symvalue))
tmp |= 1;
- *where = tmp;
- } else {
- tmp = load_ptr(where) + symvalue;
- /* Set the Thumb bit, if needed. */
- if (ELF_ST_TYPE(syminfo) == STT_ARM_TFUNC)
- tmp |= 1;
- store_ptr(where, tmp);
- }
+ if (ELF_R_TYPE(rel->r_info) == R_TYPE(REL32))
+ tmp -= (Elf_Addr)where;
+ store_ptr(where, tmp);
+ }
+
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: ABS32/GLOB_DAT %p @ %p in %s",
+ printf ("rtl: REL32/ABS32/GLOB_DAT %p @ %p in %s",
(void *)tmp, where, rtems_rtl_obj_oname (obj));
- break;
+ break;
- case R_TYPE(RELATIVE): /* word32 B + A */
- if (__predict_true(RELOC_ALIGNED_P(where))) {
- tmp = *where + (Elf_Addr)sect->base;
- *where = tmp;
- } else {
- tmp = load_ptr(where) + (Elf_Addr)sect->base;
- store_ptr(where, tmp);
- }
- if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: RELATIVE in %s --> %p",
- rtems_rtl_obj_oname (obj), (void *)tmp);
- break;
+ case R_TYPE(THM_MOVT_ABS):
+ case R_TYPE(THM_MOVW_ABS_NC):
+ upper_insn = *(uint16_t *)where;
+ lower_insn = *((uint16_t *)where + 1);
+
+ addend = ((upper_insn & 0x000f) << 12) | ((upper_insn & 0x0400) << 1) |
+ ((lower_insn & 0x7000) >> 4) | (lower_insn & 0x00ff);
+ addend = (addend ^ 0x8000) - 0x8000;
+
+ tmp = addend + symvalue;
+ if (ELF32_R_TYPE(rel->r_info) == R_ARM_THM_MOVT_ABS)
+ tmp >>= 16;
+
+ *(uint16_t *)where = (uint16_t)((upper_insn & 0xfbf0) |
+ ((tmp & 0xf000) >> 12) |
+ ((tmp & 0x0800) >> 1));
+ *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0x8f00) |
+ ((tmp & 0x0700) << 4) |
+ (tmp & 0x00ff));
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)) {
+ printf ("rtl: THM_MOVT_ABS/THM_MOVW_ABS_NC %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ }
+
+ break;
+
+ case R_TYPE(THM_JUMP24):
+ /* same to THM_CALL; insn b.w */
+ case R_TYPE(THM_CALL):
+ upper_insn = *(uint16_t *)where;
+ lower_insn = *((uint16_t *)where + 1);
+ sign = (upper_insn & (1 << 10)) >> 10;
+ i1 = ((lower_insn >> 13) & 1) ^ sign ? 0 : 1;
+ i2 = ((lower_insn >> 11) & 1) ^ sign ? 0 : 1;
+ tmp = (i1 << 23) | (i2 << 22) | ((upper_insn & 0x3ff) << 12) | ((lower_insn & 0x7ff) << 1);
+ addend = (tmp | ((sign ? 0 : 1) << 24)) - (1 << 24);
+
+ if (isThumb(symvalue)) ;/*Thumb to Thumb call, nothing to care */
+ else {
+ if (ELF_R_TYPE(rel->r_info) == R_TYPE(THM_JUMP24)) {
+ tmp = (tmp + 2) & ~3; /* aligned to 4 bytes only for JUMP24 */
+ printf("THM_JUMP24 to arm not supported\n");
+ return false;
+ }
+ else {
+ /* THM_CALL bl-->blx */
+ lower_insn &=~(1<<12);
+ }
+ }
+
+ tmp = symvalue + addend;
+ tmp = tmp - (Elf_Addr)where;
+
+ if (((Elf_Sword)tmp > 0x7fffff) || ((Elf_Sword)tmp < -0x800000)) {
+ printf("THM_CALL/JUMP24 overflow\n");
+ return false;
+ }
+
+ sign = (tmp >> 24) & 1;
+ *(uint16_t *)where = (uint16_t)((upper_insn & 0xf800) | (sign << 10) |
+ ((tmp >> 12) & 0x3ff));
+
+ *((uint16_t *)where + 1) = (uint16_t)((lower_insn & 0xd000)|
+ ((sign ^ (~(tmp >> 23) & 1)) << 13) |
+ ((sign ^ (~(tmp >> 22) & 1)) << 11) |
+ ((tmp >> 1) & 0x7ff));
+
+ if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC)){
+ printf ("rtl: THM_CALL/JUMP24 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ }
+
+ break;
+
+ case R_TYPE(THM_JUMP19):
+
+ if (!isThumb(symvalue)) {
+ printf("THM_JUMP19 to arm not supported\n");
+ return false;
+ }
+
+ upper_insn = *(uint16_t *)where;
+ lower_insn = *((uint16_t *)where + 1);
+ sign = (upper_insn >> 10) & 0x1;
+
+ if ((((upper_insn & 0x3f) >> 7) & 0x7) == 0x7) {
+ printf("THM_JUMP19 failed\n");
+ return false; /*if cond <3:1> == '111', see Related codings in armv7a manual */
+ }
+
+ i1 = (lower_insn >> 13) & 0x1;
+ i2 = (lower_insn >> 11) & 0x1;
+
+ tmp = ((i2 << 19) | (i1 << 18) | ((upper_insn & 0x3f) << 12) | ((lower_insn & 0x7ff) << 1));
+ addend = (tmp | ((sign ? 0 : 1) << 20)) - (1 << 20);
+ tmp = symvalue + addend;
+
+ tmp = tmp - (Elf_Addr)where;
+
+ if (((Elf_Sword)tmp > 0x7ffffe) || ((Elf_Sword)tmp < -0x800000)) {
+ rtems_rtl_set_error (EINVAL, "%s: Overflow %ld "
+ "THM_JUMP19 relocations",
+ sect->name, (uint32_t) ELF_R_TYPE(rel->r_info));
+ return false;
+ }
+
+ sign = (tmp >> 20) & 0x1;
+ i2 = (tmp >> 19) & 0x1;
+ i1 = (tmp >> 18) & 0x1;
+
+ *(uint16_t*)where = (upper_insn & 0xfbc0) | (sign << 10) | ((tmp >> 12) & 0x3f);
+ *((uint16_t*)where + 1) = (lower_insn & 0xd000) | (i1 << 13) |
+ (i2 << 11) | ((tmp >> 1) & 0x7ff);
- case R_TYPE(COPY):
- /*
- * These are deferred until all other relocations have
- * been done. All we do here is make sure that the
- * COPY relocation is not in a shared library. They
- * are allowed only in executable files.
- */
if (rtems_rtl_trace (RTEMS_RTL_TRACE_RELOC))
- printf ("rtl: COPY (avoid in main)");
- break;
+ printf ("rtl: THM_JUMP19 %p @ %p in %s\n",
+ (void *)*where, where, rtems_rtl_obj_oname (obj));
+ break;
default:
printf ("rtl: reloc unknown: sym = %lu, type = %lu, offset = %p, "
diff --git a/testcase/1.c b/testcase/1.c
new file mode 100644
index 0000000..e8a1241
--- /dev/null
+++ b/testcase/1.c
@@ -0,0 +1,106 @@
+int global;
+static char local;
+
+void hello(int arg)
+{
+ switch (arg) {
+ case 1:
+ printf("Inner-module call hello()\n");
+ break;
+ case 2:
+ printf("Inter-module call hello()\n");
+ break;
+ default:
+ return;
+ }
+}
+
+#if defined (__arm__)
+int rtems_arm(int arg)
+{
+ switch (arg) {
+ case 24:
+ printf("R_ARM_JUMP24: arg = 24\n");
+ break;
+ }
+ return 0;
+}
+
+int rtems_thumb(int arg)
+{
+ switch (arg) {
+ case 19:
+ printf("R_ARM_THM_JUMP19: arg = 19\n");
+ break;
+ case 24:
+ printf("R_ARM_THM_JUMP24: arg = 24\n");
+ break;
+ }
+ return 0;
+}
+#endif
+
+/* This is the init entry, Because init() use "blx", it is not needed
+ * to handle arm/thumb switch here
+ */
+int rtems(int argc, char **argv)
+{
+ local = 1;
+ printf("In rtems() local = %d\n", local); //inner-module data access
+ hello(1); //inner-module call
+ test(argc, argv);
+
+#if defined (__arm__)
+#ifdef THUMB_TEST
+ __asm__ volatile (
+ "push {r0}\r\n"
+ "push {lr}\r\n"
+ "mov r0, #19\r\n"
+ "cmp r0, #19\r\n"
+ "mov lr, pc\r\n"
+ "add lr, #7\r\n"
+ "beq rtems_thumb\r\n" /*THM_JUMP19*/
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "pop {lr}\r\n"
+ "pop {r0}\r\n"
+ );
+ __asm__ volatile (
+ "push {r0}\r\n"
+ "push {lr}\r\n"
+ "mov r0, #24\r\n"
+ "mov lr, pc\r\n"
+ "add lr, #7\r\n"
+ "b.w rtems_thumb\r\n" /*THM_JUMP24*/
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "pop {lr}\r\n"
+ "pop {r0}\r\n"
+ );
+#elif defined ARM_TEST
+ /*arm instruction test*/
+ __asm__ volatile (
+ "push {r0}\r\n"
+ "push {lr}\r\n"
+ "mov r0, #24\r\n"
+ "mov lr, pc\r\n"
+ "add lr, #4\r\n"
+ "b rtems_arm\r\n" /*JUMP24*/
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "nop\r\n"
+ "pop {lr}\r\n"
+ "pop {r0}\r\n"
+ );
+#endif
+
+#else
+ /* other archs */
+#endif
+ return 0;
+}
diff --git a/testcase/2.c b/testcase/2.c
new file mode 100644
index 0000000..a63c1c7
--- /dev/null
+++ b/testcase/2.c
@@ -0,0 +1,14 @@
+extern int global;
+extern void hello(int);
+
+int test(int argc, char **argv)
+{
+ global = 1; //inter-module data access
+ printf("In test() global = %d\n", global);
+ hello(2); //inter-module call
+}
+
+int my_main(int argc, char **argv)
+{
+ exit(0);
+}
diff --git a/testcase/Readme b/testcase/Readme
new file mode 100644
index 0000000..1312f60
--- /dev/null
+++ b/testcase/Readme
@@ -0,0 +1,11 @@
+====================
+arm:
+ Simulator:
+ qemu-system-arm -no-reboot -net none -nographic -M realview-pbx-a9 -m 256M -kernel build/arm-rtems4.11-realview_pbx_a9_qemu/rtld
+ add "-S -s" option and you can use gdbserver to debug rtld
+ use "halt" to exit qemu.
+
+ Configuration:
+ waf configure --rtems=/opt/rtems-4.11 --rtems-tools=/opt/rtems-4.11 --rtems-archs=arm --rtems-bsps=arm/realview_pbx_a9_qemu
+
+ In the wscript, you can use different cflags to test.
diff --git a/testcase/wscript b/testcase/wscript
new file mode 100644
index 0000000..a518cb6
--- /dev/null
+++ b/testcase/wscript
@@ -0,0 +1,32 @@
+import re
+import rtems
+
+def build(bld):
+ arch = bld.get_env()['RTEMS_ARCH']
+
+ bld(target = 'x',
+ features = 'c cstlib',
+ includes = bld.includes,
+ defines = bld.defines,
+ source = ['1.c', '2.c'])
+
+# Note: the bsp is compiled in thumb mode
+# The follow cflags is to test arm/thumb reloc code.
+# cflags = '-marm -fno-common -DARM_TEST',
+# cflags = '-mthumb -fno-common -DTHUMB_TEST',
+# cflags = '-marm -mcpu=arm1176jzf-s -fno-common -DARM_TEST',
+
+ if arch == 'arm':
+ bld(target = 'test.rap',
+ features = 'c rap',
+ xxxx = 'hello',
+
+ cflags = '-mthumb -fno-common -DTHUMB_TEST',
+
+ rtems_linkflags = ['--base', 'rtld.prelink',
+ '--entry', 'my_main'],
+ source = ['1.c', '2.c'])
+
+ bld(target = '../test.rap',
+ source = ['test.rap'],
+ rule = 'cp ${SRC} ${TGT}')
diff --git a/wscript b/wscript
index 9f9417a..3d3a1b4 100644
--- a/wscript
+++ b/wscript
@@ -145,7 +145,7 @@ def build(bld):
#
bld(target = 'fs-root.tar',
source = ['shell-init', 'libx.a'],
- rule = 'tar cf - ${SRC} > ${TGT}')
+ rule = 'tar --format=ustar -cf ${TGT} ${SRC}')
bld.objects(name = 'rootfs.prelink',
target = 'fs-root-tarfile.o',
source = 'fs-root.tar',
@@ -181,6 +181,8 @@ def build(bld):
source = ['xa.c',
'x-long-name-to-create-gnu-extension-in-archive.c'])
+ bld.recurse('testcase');
+
if re.match('pc[3456]86', bsp) is not None:
raps = ['bsdport.rap']
else:
@@ -188,8 +190,8 @@ def build(bld):
bld(target = 'fs-root.tar',
name = 'fs',
- source = ['shell-init', 'libx.a', 'x.rap'] + raps,
- rule = 'tar cf - ${SRC} > ${TGT}')
+ source = ['shell-init', 'libx.a', 'x.rap', 'test.rap'] + raps,
+ rule = 'tar --format=ustar -cf ${TGT} ${SRC}')
bld.objects(name = 'rootfs',
target = 'fs-root-tarfile.o',
source = 'fs-root.tar',