summaryrefslogtreecommitdiff
path: root/arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p
diff options
context:
space:
mode:
Diffstat (limited to 'arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p')
-rw-r--r--arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p394
1 files changed, 394 insertions, 0 deletions
diff --git a/arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p b/arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p
new file mode 100644
index 0000000..afac755
--- /dev/null
+++ b/arm-riscos-gnueabi/recipes/patches/gccsdk/elf2aif-eabi-support.p
@@ -0,0 +1,394 @@
+Index: elf2aif/src/elf2aif.c
+===================================================================
+--- elf2aif/src/elf2aif.c (revision 7698)
++++ elf2aif/src/elf2aif.c (working copy)
+@@ -54,7 +54,7 @@
+ typedef struct
+ {
+ uint8_t decompress[4]; /* BL to decompression code for compressed images */
+- uint8_t selfreloc[4]; /* BL to self-relocation code */
++ uint8_t selfreloc[4]; /* BL to self-relocation code (*) */
+ uint8_t zeroinit[4]; /* BL to zero init code */
+ uint8_t entrypoint[4]; /* BL to image entry point (*) */
+ uint8_t exitinst[4]; /* Exit instruction */
+@@ -72,47 +72,50 @@
+ } aifheader_t;
+
+ static int opt_verbose = 0;
++static int opt_eabi = 0;
+
+ static Elf32_External_Ehdr elf_ehdr;
+ static phdr_list_t *elf_phdrlistP;
+ static const char *elf_filename;
++static uint32_t got_addr = 0;
+
+-static const unsigned int aifcode[] = {
+- 0xE1A00000, /* NOP (BL decompress) */
+- 0xE1A00000, /* NOP (BL self-relocate) */
+- 0xEB00000C, /* BL zero-init */
+- 0xEB000000, /* BL entrypoint (*) */
+- 0xEF000011, /* SWI OS_Exit */
+- 0x00000000, /* Image R/O size (*) */
+- 0x00000000, /* Image R/W size (*) */
+- 0x00000000, /* Image debug size */
+- 0x00000000, /* Image zero-init size (*) */
+- 0x00000000, /* Image debug type */
+- 0x00000000, /* Image base (*) */
+- 0x00000000, /* Workspace size */
+- 0x00000020, /* 32-bit addressing */
+- 0x00000000, /* Data base */
+- 0x00000000, /* Reserved */
+- 0x00000000, /* Reserved */
+- 0xE1A00000, /* MOV R0, R0 */
+- 0xE04EC00F, /* SUB R12, R14, PC */
+- 0xE08FC00C, /* ADD R12, PC, R12 */
+- 0xE99C0017, /* LDMIB R12, {R0-R2, R4} */
+- 0xE24CC010, /* SUB R12, R12, #0x10 */
+- 0xE08CC000, /* ADD R12, R12, R0 */
+- 0xE08CC001, /* ADD R12, R12, R1 */
+- 0xE3A00000, /* MOV R0, #0 */
+- 0xE3A01000, /* MOV R1, #0 */
+- 0xE3A02000, /* MOV R2, #0 */
+- 0xE3A03000, /* MOV R3, #0 */
+- 0xE3540000, /* CMP R4, #0 */
++static const uint32_t aifcode[] = {
++ 0xE1A00000, /* NOP (BL decompress) */
++ 0xE1A00000, /* NOP (BL self-relocate) (*) */
++ 0xEB00000C, /* BL zero-init */
++ 0xEB000000, /* BL entrypoint (*) */
++ 0xEF000011, /* SWI OS_Exit */
++ 0x00000000, /* Image R/O size (*) */
++ 0x00000000, /* Image R/W size (*) */
++ 0x00000000, /* Image debug size */
++ 0x00000000, /* Image zero-init size (*) */
++ 0x00000000, /* Image debug type */
++ 0x00000000, /* Image base (*) */
++ 0x00000000, /* Workspace size */
++ 0x00000020, /* 32-bit addressing */
++ 0x00000000, /* Data base */
++ 0x00000000, /* Reserved */
++ 0x00000000, /* Reserved */
++ 0xE1A00000, /* MOV R0, R0 */
++ 0xE04EC00F, /* SUB R12, R14, PC */
++ 0xE08FC00C, /* ADD R12, PC, R12 */
++ 0xE99C0017, /* LDMIB R12, {R0-R2, R4} */
++ 0xE24CC010, /* SUB R12, R12, #16 */
++ 0xE08CC000, /* ADD R12, R12, R0 */
++ 0xE08CC001, /* ADD R12, R12, R1 */
++ 0xE3A00000, /* MOV R0, #0 */
++ 0xE3A01000, /* MOV R1, #0 */
++ 0xE3A02000, /* MOV R2, #0 */
++ 0xE3A03000, /* MOV R3, #0 */
++ 0xE3540000, /* CMP R4, #0 */
+ /* zeroloop: */
+- 0xD1A0F00E, /* MOVLE PC, R14 */
+- 0xE8AC000F, /* STMIA R12!, {R0-R3} */
+- 0xE2544010, /* SUBS R4, R4, #16 */
+- 0xEAFFFFFB /* B zeroloop */
++ 0xD1A0F00E, /* MOVLE PC, R14 */
++ 0xE8AC000F, /* STMIA R12!, {R0-R3} */
++ 0xE2544010, /* SUBS R4, R4, #16 */
++ 0xEAFFFFFB /* B zeroloop */
+ };
+
++
+ /* Read a little-endian 'short' value. */
+ static uint16_t
+ RdShort (const uint8_t sh[2])
+@@ -143,6 +146,7 @@
+ fprintf (stderr, "Usage: elf2aif [options] <ELF file> [<AIF file>]\n"
+ "Convert static ARM ELF binary to AIF (Acorn Image Format) binary.\n"
+ "Options:\n"
++ " -e, --eabi source binary uses EABI\n"
+ " -v, --verbose prints informational messages during processing\n"
+ " --help display this help and exit\n"
+ " --version output version information and exit\n");
+@@ -201,7 +205,8 @@
+ return EXIT_FAILURE;
+ }
+
+- if (elf_ehdr.e_ident[EI_OSABI] != ELFOSABI_ARM)
++ if ((!opt_eabi && elf_ehdr.e_ident[EI_OSABI] != ELFOSABI_ARM) ||
++ (opt_eabi && elf_ehdr.e_ident[EI_OSABI] != ELFOSABI_NONE))
+ {
+ fprintf (stderr, "ELF file '%s' is not for ARM\n", elf_filename);
+ return EXIT_FAILURE;
+@@ -344,6 +349,97 @@
+ }
+
+ static int
++e2a_readshdr (FILE * elfhandle)
++{
++ Elf32_External_Shdr shstentry;
++ uint32_t shoffset, shentrysize, shentrycount, shstrndx;
++ uint32_t shstoffset, shstsize;
++ char *shst;
++
++ if ((shoffset = RdLong (elf_ehdr.e_shoff)) == 0
++ || (shentrycount = RdShort (elf_ehdr.e_shnum)) == 0)
++ {
++ fprintf (stderr, "ELF file '%s' does not have section headers\n",
++ elf_filename);
++ return EXIT_FAILURE;
++ }
++
++ if ((shentrysize = RdShort (elf_ehdr.e_shentsize)) < sizeof (Elf32_External_Shdr))
++ {
++ fprintf (stderr, "Size section header entry is too small\n");
++ return EXIT_FAILURE;
++ }
++
++ if ((shstrndx = RdShort (elf_ehdr.e_shstrndx)) >= shentrycount) {
++ fprintf (stderr, "String table index out of bounds\n");
++ return EXIT_FAILURE;
++ }
++
++ if (fseek (elfhandle, shoffset + (shstrndx * shentrysize), SEEK_SET) != 0
++ || fread (&shstentry, sizeof (Elf32_External_Shdr), 1, elfhandle) != 1)
++ {
++ fprintf (stderr, "Failed to read section header string table header\n");
++ return EXIT_FAILURE;
++ }
++
++ if ((shstoffset = RdLong (shstentry.sh_offset)) == 0)
++ {
++ fprintf (stderr, "Section header string table data missing\n");
++ return EXIT_FAILURE;
++ }
++
++ if ((shstsize = RdLong (shstentry.sh_size)) == 0)
++ {
++ fprintf (stderr, "Invalid section header string table size\n");
++ return EXIT_FAILURE;
++ }
++
++ if ((shst = malloc (shstsize)) == NULL)
++ {
++ fprintf (stderr, "Out of memory\n");
++ return EXIT_FAILURE;
++ }
++
++ if (fseek (elfhandle, shstoffset, SEEK_SET) != 0
++ || fread (shst, 1, shstsize, elfhandle) != shstsize)
++ {
++ fprintf (stderr, "Failed to read section header string table\n");
++ return EXIT_FAILURE;
++ }
++
++ while (shentrycount)
++ {
++ Elf32_External_Shdr shentry;
++ uint32_t shnameoff;
++
++ if (fseek (elfhandle, shoffset, SEEK_SET) != 0
++ || fread (&shentry, sizeof (Elf32_External_Shdr), 1, elfhandle) != 1)
++ {
++ fprintf (stderr, "Failed to read section header entry\n");
++ return EXIT_FAILURE;
++ }
++
++ if ((shnameoff = RdLong (shentry.sh_name)) >= shstsize)
++ {
++ fprintf (stderr, "Section name out of bounds\n");
++ return EXIT_FAILURE;
++ }
++
++ if (strcmp ((shst + shnameoff), ".got") == 0)
++ {
++ got_addr = RdLong (shentry.sh_addr);
++ }
++
++ shoffset += shentrysize;
++ --shentrycount;
++ }
++
++ free (shst);
++
++ return EXIT_SUCCESS;
++}
++
++static int
+ e2a_copy (FILE * elfhandle, FILE * aifhandle)
+ {
+ const phdr_list_t *phdrP;
+@@ -488,21 +584,156 @@
+ }
+
+ memcpy (&aifhdr, aifcode, sizeof (aifcode));
+- WrLong (aifhdr.entrypoint,
+- RdLong (aifhdr.entrypoint) +
+- ((exec_addr - load_addr -
+- (offsetof (aifheader_t, entrypoint) + 8)) >> 2));
++ if (opt_eabi)
++ {
++ /* BL to relocation code */
++ WrLong (aifhdr.selfreloc,
++ /* Default is a NOP, so reading it is useless */
++ 0xEB000000 +
++ ((aifend - (offsetof (aifheader_t, selfreloc) + 8)) >> 2));
++
++ /* BL to EABI startcode */
++ WrLong (aifhdr.entrypoint,
++ RdLong (aifhdr.entrypoint) +
++ ((sizeof(aifcode) - (offsetof (aifheader_t, entrypoint) + 8)) >> 2));
++ }
++ else
++ {
++ /* BL to program entrypoint */
++ WrLong (aifhdr.entrypoint,
++ RdLong (aifhdr.entrypoint) +
++ ((exec_addr - load_addr -
++ (offsetof (aifheader_t, entrypoint) + 8)) >> 2));
++ }
+ WrLong (aifhdr.rosize, rosize);
+ WrLong (aifhdr.rwsize, rwsize);
+ WrLong (aifhdr.zisize, zisize);
+ WrLong (aifhdr.imagebase, load_addr);
+- if (fwrite (&aifhdr, sizeof (aifhdr), 1, aifhandle) != 1
+- || fseek (aifhandle, aifend, SEEK_SET) != 0)
++ if (fwrite (&aifhdr, sizeof (aifhdr), 1, aifhandle) != 1)
+ {
+ fprintf (stderr, "Failed to write aif header\n");
+ return EXIT_FAILURE;
+ }
+
++ /* In the EABI case we need to inject the code to install
++ * the ARMEABISupport abort handler */
++ if (opt_eabi)
++ {
++ assert (128 == sizeof (aifcode));
++ uint32_t entrycode[] = {
++ /* Space for GOTT_BASE injection (see below) */
++ 0xE1A00000, /* MOV R0, R0 */
++ 0xE1A00000, /* MOV R0, R0 */
++ /* Install the abort handler */
++ 0xE3A00002, /* MOV R0, #2 */
++ 0xEF059D01, /* SWI ARMEABISupport_AbortOp */
++ /* Proceed to the real program start */
++ 0xEA000000, /* B <program_start> (*) */
++ /* Offset of the GOT relative to the load address (or 0 if none) */
++ 0x00000000, /* DCD <got_offset> (*) */
++ };
++
++ const uint32_t reloccode[] = {
++ /* RelocCode: */
++ 0xE1A00000, /* MOV R0, R0 */
++ /* Dynamically compute the program load address */
++ 0xE04EC00F, /* SUB R12, LR, PC */
++ 0xE08FC00C, /* ADD R12, PC, R12 */
++ 0xE24CC00C, /* SUB R12, R12, #12 */
++ /* Prevent reentry by replacing the branch to the relocation code. */
++ 0xE51F0018, /* LDR R0, =RelocCode */
++ 0xE58C0004, /* STR R0, [R12, #4] */
++ /* Relocate the GOT offset (above) to its absolute address */
++ 0xE59C0094, /* LDR R0, [R12, #&94] */
++ 0xE3300000, /* TEQ R0, #0 */
++ 0x1080000C, /* ADDNE R0, R0, R12 */
++ 0x158C0094, /* STRNE R0, [R12, #&94] */
++ /* Fill in GOTT_BASE at load + 0x38, unless running under DDT */
++ 0xE59C0038, /* LDR R0, [R12, #&38] */
++ 0xE3300000, /* TEQ R0, #0 */
++ 0x1A000002, /* BNE ddt_hack */
++ 0xE28C0094, /* ADD R0, R12, #&94 */
++ 0xE58C0038, /* STR R0, [R12, #&38] */
++ 0xE1A0F00E, /* MOV PC, LR */
++ /* Hack for DDT (which uses the reserved field at &8038 to
++ * temporarily store the address of the zero-initialisation code
++ * during program start, which is reinstated after DDT's
++ * replacement is called). In this case, modify the entrycode
++ * (above) to inject it for us.
++ *
++ * This does prevent the RO area being marked non-writeable if
++ * the modified entrycode gets executed, however (in the non-DDT
++ * case, the entrycode does not write to the AIF header, so
++ * there is no reason the RO area can't be non-writeable then).
++ * By definition the RO area must be writeable for relocations to
++ * work, so it is perfectly safe to assume that it is when this
++ * code runs.
++ */
++ /* ddt_hack: */
++ 0xE59F001C, /* LDR R0, =ddt_hack_data */
++ 0xE59F101C, /* LDR R1, =ddt_hack_data+4 */
++ 0xE58C0080, /* STR R0, [R12, #&80] */
++ 0xE58C1084, /* STR R1, [R12, #&84] */
++ /* Invalidate instruction cache */
++ 0xE3A00001, /* MOV R0, #1 */
++ 0xE28C1080, /* ADD R1, R12, #&80 */
++ 0xE28C2088, /* ADD R2, R12, #&88 */
++ 0xEF02006E, /* SWI XOSSynchroniseCodeAreas */
++ 0xE1A0F00E, /* MOV PC, LR */
++ /* Instructions to inject into entrycode. Uses PC-relative
++ * addressing, so must be kept in sync with changes to entrycode
++ * or the location of entrycode within memory. */
++ /* ddt_hack_data: */
++ /* Compute address of GOT field after entrycode */
++ 0xE28F000C, /* ADR R0, got_address */
++ /* Store computed address in GOTT_BASE (load + 0x38) */
++ 0xE50F0054, /* STR R0, [pc, #-&54] */
++ /* Relocation sentinel: just in case anything expects one */
++ 0xFFFFFFFF, /* DCD -1 */
++ };
++
++ /* Ensure there is sufficient space for the EABI entry code */
++ if (opt_eabi && exec_addr - load_addr < sizeof (aifcode) + sizeof (entrycode))
++ {
++ fprintf (stderr, "First program segment is not what we hoped to be "
++ "(not enough place before _start symbol for EABI entrycode)\n");
++ return EXIT_FAILURE;
++ }
++
++ if (opt_verbose)
++ printf ("Writing EABI entry code at offset 0x%x\n", sizeof (aifcode));
++
++ entrycode[4] |= (exec_addr - load_addr - (sizeof (aifcode) + 4*4 + 8)) >> 2;
++ if (got_addr)
++ {
++ if (opt_verbose)
++ printf ("Found GOT at 0x%x\n", got_addr);
++ entrycode[5] = (got_addr - load_addr);
++ }
++ if (fseek (aifhandle, sizeof (aifcode), SEEK_SET) != 0
++ || fwrite (&entrycode, sizeof (entrycode), 1, aifhandle) != 1)
++ {
++ fprintf (stderr, "Failed to write EABI entrycode\n");
++ return EXIT_FAILURE;
++ }
++
++ if (opt_verbose)
++ printf ("Writing relocation code at offset 0x%x\n", aifend);
++
++ if (fseek (aifhandle, aifend, SEEK_SET) != 0
++ || fwrite (&reloccode, sizeof (reloccode), 1, aifhandle) != 1)
++ {
++ fprintf (stderr, "Failed to write relocation code\n");
++ return EXIT_FAILURE;
++ }
++ }
++
++ if (fseek (aifhandle, aifend, SEEK_SET) != 0)
++ {
++ fprintf (stderr, "Failed to seek to end of file\n");
++ return EXIT_FAILURE;
++ }
++
+ return EXIT_SUCCESS;
+ }
+
+@@ -557,6 +788,7 @@
+ elf_filename = elffilename;
+
+ if (e2a_readehdr (elfhandle) == EXIT_SUCCESS
++ && e2a_readshdr (elfhandle) == EXIT_SUCCESS
+ && e2a_readphdr (elfhandle) == EXIT_SUCCESS
+ && e2a_copy (elfhandle, aifhandle) == EXIT_SUCCESS)
+ status = EXIT_SUCCESS;
+@@ -683,6 +915,9 @@
+ fprintf (stderr, "Warning: extra options/arguments ignored\n");
+ return EXIT_SUCCESS;
+ }
++ else if (!strcmp (&argv[i][1], "-eabi")
++ || !strcmp (&argv[i][1], "e"))
++ opt_eabi = 1;
+ else if (!strcmp (&argv[i][1], "-verbose")
+ || !strcmp (&argv[i][1], "v"))
+ ++opt_verbose;