Forum Discussion
Altera_Forum
Honored Contributor
12 years agoA quick patch to let 'small data' be accessed from r0:
--- bfd.altera/elf32-nios2.c 2009-10-21 09:00:21.000000000 +0100
+++ bfd/elf32-nios2.c 2013-09-06 09:46:07.000000000 +0100
@@ -1816,7 +1816,7 @@
if (!nios2_elf_assign_gp (output_bfd, &gp, info))
{
format = _("global pointer relative relocation at address 0x%08x when _gp not defined\n");
- sprintf(msgbuf, format, reloc_address);
+ sprintf(msgbuf, format, (unsigned int)reloc_address);
msg = msgbuf;
r = bfd_reloc_dangerous;
}
@@ -1828,9 +1828,33 @@
if ((signed) relocation < -32768
|| (signed) relocation > 32767)
{
+#if 1 /* Allow small data be accessed from r0 as well as gp */
+ /* Before erroring, see if we can change the instruction to use an offset
+ * from r0 (always zero) instead.
+ * Verify source register is r26 and the opcode is addi, ldxxx or stxxx.
+ * (We really shouldn't see GPREL for any other instructions.) */
+ unsigned int instruction, opcode;
+ if ((signed)symbol_address < -32768 || (signed)symbol_address > 32767)
+ goto gprel_fail;
+ instruction = bfd_get_32(input_bfd, contents + rel->r_offset);
+ if ((instruction >> 27) != 26)
+ /* Source register is not gp */
+ goto gprel_fail;
+ opcode = instruction & 0x3f;
+ /* 4 is 'addi', 0x20 collapses the 'io' variants, 0x15/0x17 are 'ldw'/'stw',
+ * 0x8 collapses 'xxh' onto 'xxb', 5 is 'stb', 3 and 7 are 'ldbu' and 'ldb'. */
+ if (opcode == 4 || (opcode &= ~0x20) == 0x15 || opcode == 0x17
+ || (opcode &= ~8) == 5 || (opcode & ~4) == 3) {
+ /* Change source register to r0 and drop in offset */
+ instruction = (instruction & 0x07c0003f) | (symbol_address & 0xffff) << 6;
+ bfd_put_32(input_bfd, instruction, contents + rel->r_offset);
+ break;
+ }
+ gprel_fail:
+#endif
format = _("Unable to reach %s (at 0x%08x) from the global pointer (at 0x%08x) "
"because the offset (%d) is out of the allowed range, -32678 to 32767.\n" );
- sprintf(msgbuf, format, name, symbol_address, gp, (signed)relocation);
+ sprintf(msgbuf, format, name, (unsigned int)symbol_address, (unsigned int)gp, (signed)relocation);
msg = msgbuf;
r = bfd_reloc_outofrange;
}
There is a second check for the gp offset, but the above is the one that usually detects errors. I've also fixed a couple of format fubars. They would cause grief if 'long' is 64 bits and the arguments aren't all passed in registers (linux amd64 and sparc64 will use registers for the arguments).