unsigned char arm_jtab[] = { 0x00, 0xc0, 0x9f, 0xe5,
0x00, 0xf0, 0x9c, 0xe5,
0, 0, 0, 0};
-/* If I understand what is going on here, this will need more for ppc
- support, but this lets the program start. Kim Knuttila (krk@cygnus.com) */
-unsigned char ppc_jtab[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90};
+/* This is the glue sequence for PowerPC PE. There is a */
+/* tocrel16-tocdefn reloc against the first instruction. */
+/* We also need a IMGLUE reloc against the glue function */
+/* to restore the toc saved by the third instruction in */
+/* the glue. */
+unsigned char ppc_jtab[] =
+{
+ 0x00, 0x00, 0x62, 0x81, /* lwz r11,0(r2) */
+ /* Reloc TOCREL16 __imp_xxx */
+ 0x00, 0x00, 0x8B, 0x81, /* lwz r12,0(r11) */
+ 0x04, 0x00, 0x41, 0x90, /* stw r2,4(r1) */
+ 0xA6, 0x03, 0x89, 0x7D, /* mtctr r12 */
+ 0x04, 0x00, 0x4B, 0x80, /* lwz r2,4(r11) */
+ 0x20, 0x04, 0x80, 0x4E /* bctr */
+};
+
+/* the glue instruction, picks up the toc from the stw in */
+/* the above code: "lwz r2,4(r1)" */
+bfd_vma ppc_glue_insn = 0x80410004;
+
char outfile[PATHMAX];
struct mac
{
#define MPPC 2
"ppc", ".byte", ".short", ".long", ".asciz", "#", "jmp *", ".global", ".space", ".align\t2",".align\t4","pe-powerpcle",bfd_arch_powerpc,
- ppc_jtab,sizeof(ppc_jtab),2,
+ ppc_jtab,sizeof(ppc_jtab),0,
}
,
{ 0}
int id;
const char *name;
int flags;
+ int align;
asection *sec;
asymbol *sym;
asymbol **sympp;
} sinfo;
+#ifndef DLLTOOL_PPC
+
#define TEXT 0
#define DATA 1
#define BSS 2
#define IDATA5 4
#define IDATA4 5
#define IDATA6 6
+#define PDATA 7
+#define RDATA 8
+
#define NSECS 7
+
static sinfo secdata[NSECS] =
{
- { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS},
- { DATA, ".data", SEC_DATA},
- { BSS,".bss" },
- { IDATA7, ".idata$7",SEC_HAS_CONTENTS},
- { IDATA5, ".idata$5", SEC_HAS_CONTENTS},
- { IDATA4, ".idata$4", SEC_HAS_CONTENTS},
- { IDATA6,".idata$6", SEC_HAS_CONTENTS}
+ { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 3},
+ { DATA, ".data", SEC_DATA, 2},
+ { BSS, ".bss", 0, 2},
+ { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2},
+ { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2},
+ { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2},
+ { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1}
+};
+
+#else
+/* Sections numbered to make the order the same as other PowerPC NT */
+/* compilers. This also keeps funny alignment thingies from happening. */
+#define TEXT 0
+#define PDATA 1
+#define RDATA 2
+#define IDATA5 3
+#define IDATA4 4
+#define IDATA6 5
+#define IDATA7 6
+#define DATA 7
+#define BSS 8
+#define NSECS 9
+
+static sinfo secdata[NSECS] =
+{
+ { TEXT, ".text", SEC_CODE | SEC_HAS_CONTENTS, 3},
+ { PDATA, ".pdata", SEC_HAS_CONTENTS, 2},
+ { RDATA, ".rdata", SEC_HAS_CONTENTS, 2},
+ { IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2},
+ { IDATA4, ".idata$4", SEC_HAS_CONTENTS, 2},
+ { IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1},
+ { IDATA7, ".idata$7", SEC_HAS_CONTENTS, 2},
+ { DATA, ".data", SEC_DATA, 2},
+ { BSS, ".bss", 0, 2}
};
+
+#endif
+
/*
This is what we're trying to make
ID2: .short 2
.asciz "GetFileVersionInfoSizeW"
+
+For the PowerPC, here's the variation on the above scheme:
+
+# Rather than a simple "jmp *", the code to get to the dll function
+# looks like:
+ .text
+ lwz r11,[tocv]__imp_function_name(r2)
+# RELOC: 00000000 TOCREL16,TOCDEFN __imp_function_name
+ lwz r12,0(r11)
+ stw r2,4(r1)
+ mtctr r12
+ lwz r2,4(r11)
+ bctr
*/
-static char *make_label (prefix, name)
-const char *prefix;
-const char *name;
+static char *
+make_label (prefix, name)
+ const char *prefix;
+ const char *name;
{
int len = strlen (ASM_PREFIX) + strlen (prefix) + strlen (name);
char *copy = xmalloc (len +1 );
strcat (copy, name);
return copy;
}
+
static bfd *
make_one_lib_file (exp, i)
-export_type *exp;
-int i;
+ export_type *exp;
+ int i;
{
if (0)
{
asymbol *iname;
asymbol *iname_lab;
asymbol **iname_lab_pp;
- asymbol *ptrs[NSECS+3+1]; /* one symbol for each section, 2 extra + a null */
+ asymbol **iname_pp;
+
+ /* Extra Symbols for PPC */
+#ifdef DLLTOOL_PPC
+#define EXTRA 2
+#else
+#define EXTRA 0
+#endif
+
+ asymbol *function_name; /* ".." functionName */
+ asymbol **fn_pp;
+ asymbol *toc_symbol; /* The .toc symbol */
+ asymbol **toc_pp;
+
+ /* one symbol for each section, 2 extra + a null */
+ asymbol *ptrs[NSECS+3+EXTRA+1];
char *outname = xmalloc (10);
int oidx = 0;
abfd = bfd_openw (outname, HOW_BFD_TARGET);
if (!abfd)
{
- fprintf (stderr, "%s: bfd_open failed open output file %s\n", program_name, outname);
+ fprintf (stderr, "%s: bfd_open failed open output file %s\n",
+ program_name, outname);
exit (1);
}
bfd_set_arch_mach (abfd, HOW_BFD_ARCH, 0);
+ /* First make symbols for the sections */
for (i = 0; i < NSECS; i++)
{
sinfo *si = secdata + i;
bfd_set_section_flags (abfd,
si->sec,
si->flags);
+
+ bfd_set_section_alignment(abfd, si->sec, si->align);
si->sec->output_section = si->sec;
- si->sym = bfd_make_empty_symbol(abfd);
+ si->sym = bfd_make_empty_symbol(abfd);
si->sym->name = si->sec->name;
si->sym->section = si->sec;
si->sym->flags = BSF_LOCAL;
exp_label = bfd_make_empty_symbol(abfd);
exp_label->name = make_label ("",exp->name);
- exp_label->section = secdata[TEXT].sec;
+
+ /* On PowerPC, the function name points to a descriptor in the
+ rdata section, the first element of which is a pointer to the
+ code (..function_name), and the second points to the .toc
+ */
+ if (machine == MPPC)
+ exp_label->section = secdata[RDATA].sec;
+ else
+ exp_label->section = secdata[TEXT].sec;
+
exp_label->flags = BSF_GLOBAL;
exp_label->value = 0;
ptrs[oidx++] = exp_label;
iname = bfd_make_empty_symbol(abfd);
-
iname->name = make_label ("__imp_", exp->name);
-
iname->section = secdata[IDATA5].sec;
iname->flags = BSF_GLOBAL;
iname->value = 0;
iname_lab->value = 0;
+ iname_pp = ptrs + oidx;
ptrs[oidx++] = iname;
+
iname_lab_pp = ptrs + oidx;
ptrs[oidx++] = iname_lab;
+
+#ifdef DLLTOOL_PPC
+ /* The symbol refering to the code (.text) */
+ function_name = bfd_make_empty_symbol(abfd);
+ function_name->name = make_label ("..", exp->name);
+ function_name->section = secdata[TEXT].sec;
+ function_name->flags = BSF_GLOBAL;
+ function_name->value = 0;
+
+ fn_pp = ptrs + oidx;
+ ptrs[oidx++] = function_name;
+
+ /* The .toc symbol */
+ toc_symbol = bfd_make_empty_symbol(abfd);
+ toc_symbol->name = make_label (".", "toc");
+ toc_symbol->section = (asection *)&bfd_und_section;
+ toc_symbol->flags = BSF_GLOBAL;
+ toc_symbol->value = 0;
+
+ toc_pp = ptrs + oidx;
+ ptrs[oidx++] = toc_symbol;
+#endif
+
ptrs[oidx] = 0;
for (i = 0; i < NSECS; i++)
rpp[1] = 0;
rel->address = HOW_JTAB_ROFF;
rel->addend = 0;
- rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
- rel->sym_ptr_ptr = secdata[IDATA5].sympp;
+
+ if (machine == MPPC)
+ {
+ rel->howto = bfd_reloc_type_lookup (abfd,
+ BFD_RELOC_16_GOTOFF);
+ rel->sym_ptr_ptr = iname_pp;
+ }
+ else
+ {
+ rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ rel->sym_ptr_ptr = secdata[IDATA5].sympp;
+ }
sec->orelocation = rpp;
sec->reloc_count = 1;
break;
/* An idata$4 or idata$5 is one word long, and has an
rva to idata$6 */
-
si->data = xmalloc (4);
si->size = 4;
sec->orelocation = rpp;
sec->reloc_count = 1;
break;
+
+ case PDATA:
+ {
+ /* The .pdata section is 5 words long. */
+ /* Think of it as: */
+ /* struct */
+ /* { */
+ /* bfd_vma BeginAddress, [0x00] */
+ /* EndAddress, [0x04] */
+ /* ExceptionHandler, [0x08] */
+ /* HandlerData, [0x0c] */
+ /* PrologEndAddress; [0x10] */
+ /* }; */
+
+ /* So this pdata section setups up this as a glue linkage to
+ a dll routine. There are a number of house keeping things
+ we need to do:
+
+ 1. In the name of glue trickery, the ADDR32 relocs for 0,
+ 4, and 0x10 are set to point to the same place:
+ "..function_name".
+ 2. There is one more reloc needed in the pdata section.
+ The actual glue instruction to restore the toc on
+ return is saved as the offset in an IMGLUE reloc.
+ So we need a total of four relocs for this section.
+
+ 3. Lastly, the HandlerData field is set to 0x03, to indicate
+ that this is a glue routine.
+ */
+ arelent *imglue, *ba_rel, *ea_rel, *pea_rel;
+
+ /* alignment must be set to 2**2 or you get extra stuff */
+ bfd_set_section_alignment(abfd, sec, 2);
+
+ si->size = 4 * 5;
+ si->data =xmalloc(4 * 5);
+ memset (si->data, 0, si->size);
+ rpp = xmalloc (sizeof (arelent *) * 5);
+ rpp[0] = imglue = xmalloc (sizeof (arelent));
+ rpp[1] = ba_rel = xmalloc (sizeof (arelent));
+ rpp[2] = ea_rel = xmalloc (sizeof (arelent));
+ rpp[3] = pea_rel = xmalloc (sizeof (arelent));
+ rpp[4] = 0;
+
+ /* stick the toc reload instruction in the glue reloc */
+ bfd_put_32(abfd, ppc_glue_insn, (char *) &imglue->address);
+
+ imglue->addend = 0;
+ imglue->howto = bfd_reloc_type_lookup (abfd,
+ BFD_RELOC_32_GOTOFF);
+ imglue->sym_ptr_ptr = fn_pp;
+
+ ba_rel->address = 0;
+ ba_rel->addend = 0;
+ ba_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ ba_rel->sym_ptr_ptr = fn_pp;
+
+ bfd_put_32(abfd, 0x18, si->data + 0x04);
+ ea_rel->address = 4;
+ ea_rel->addend = 0;
+ ea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ ea_rel->sym_ptr_ptr = fn_pp;
+
+ /* mark it as glue */
+ bfd_put_32(abfd, 0x03, si->data + 0x0c);
+
+ /* mark the prolog end address */
+ bfd_put_32(abfd, 0x0D, si->data + 0x10);
+ pea_rel->address = 0x10;
+ pea_rel->addend = 0;
+ pea_rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ pea_rel->sym_ptr_ptr = fn_pp;
+
+ sec->orelocation = rpp;
+ sec->reloc_count = 4;
+ break;
+ }
+ case RDATA:
+ /* Each external function in a PowerPC PE file has a two word
+ descriptor consisting of:
+ 1. The address of the code.
+ 2. The address of the appropriate .toc
+ We use relocs to build this.
+ */
+
+ si->size = 8;
+ si->data =xmalloc(8);
+ memset (si->data, 0, si->size);
+
+ rpp = xmalloc (sizeof (arelent *) * 3);
+ rpp[0] = rel = xmalloc (sizeof (arelent));
+ rpp[1] = xmalloc (sizeof (arelent));
+ rpp[2] = 0;
+
+ rel->address = 0;
+ rel->addend = 0;
+ rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ rel->sym_ptr_ptr = fn_pp;
+
+ rel = rpp[1];
+
+ rel->address = 4;
+ rel->addend = 0;
+ rel->howto = bfd_reloc_type_lookup (abfd, BFD_RELOC_32);
+ rel->sym_ptr_ptr = toc_pp;
+
+ sec->orelocation = rpp;
+ sec->reloc_count = 2;
+ break;
}
}
for (i = 0; i < NSECS; i++)
{
sinfo *si = secdata + i;
+
bfd_set_section_size (abfd, si->sec, si->size);
bfd_set_section_vma (abfd, si->sec, vma);
+
/* vma += si->size;*/
}
}
for (i = 0; i < NSECS; i++)
{
sinfo *si = secdata + i;
+
if (i == IDATA5 && no_idata5)
continue;
}
-static
-bfd *
+static bfd *
make_head()
{
FILE * f = fopen ("dh.s", FOPEN_WT);
return bfd_openr ("dh.o", HOW_BFD_TARGET);
}
-static
-bfd * make_tail()
+static bfd *
+make_tail()
{
FILE * f = fopen ("dt.s", FOPEN_WT);
+
+#ifdef DLLTOOL_PPC
+ /* Other PowerPC NT compilers use idata$6 for the dllname, so I
+ do too. Original, huh? */
+ fprintf (f, "\t.section .idata$6\n");
+#else
fprintf (f, "\t.section .idata$7\n");
+#endif
+
fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab);
fprintf (f, "__%s_iname:\t%s\t\"%s\"\n",
imp_name_lab, ASM_TEXT, dll_name);
fprintf (f, "\t.section .idata$5\n");
fprintf (f, "\t%s\t0\n", ASM_LONG);
}
+
+
+#ifdef DLLTOOL_PPC
+ /* Normally, we need to see a null descriptor built in idata$3 to
+ act as the terminator for the list. The ideal way, I suppose,
+ would be to mark this section as a comdat type 2 section, so
+ only one would appear in the final .exe (if our linker supported
+ comdat, that is) or cause it to be inserted by something else (say
+ crt0)
+ */
+
+ fprintf (f, "\t.section .idata$3\n");
+ fprintf (f, "\t%s\t0\n", ASM_LONG);
+ fprintf (f, "\t%s\t0\n", ASM_LONG);
+ fprintf (f, "\t%s\t0\n", ASM_LONG);
+ fprintf (f, "\t%s\t0\n", ASM_LONG);
+ fprintf (f, "\t%s\t0\n", ASM_LONG);
+#endif
+
fclose (f);
sprintf (outfile, "-o dt.o dt.s");