From b10f8e5e5c3740b78e625251ff9795cf297a0262 Mon Sep 17 00:00:00 2001 From: Kim Knuttila Date: Fri, 1 Dec 1995 02:08:19 +0000 Subject: [PATCH] PowerPC changes --- binutils/ChangeLog | 10 ++ binutils/dlltool.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 306 insertions(+), 29 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index b645afb..56aacb3 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +Thu Nov 30 20:26:02 1995 Kim Knuttila + + * dlltool.c (ppc_jtab): The binary glue for PowerPC dll linkage, + including the return instruction. + sinfo: added a preferred alignment field. + (secdata): section data for the PowerPC version. + (make_one_lib_file): More symbols, More sections (pdata, rdata) + (make_tail): Use idata$6 instead of idata$7 for ppc. Also added a + NULL idata$3 descriptor (temporary). + Tue Nov 28 17:23:44 1995 Doug Evans * dlltool.c (fill_ordinals): Don't reference d_export_vec if diff --git a/binutils/dlltool.c b/binutils/dlltool.c index 156dde9..eef12ac 100644 --- a/binutils/dlltool.c +++ b/binutils/dlltool.c @@ -237,10 +237,27 @@ unsigned char i386_jtab[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x90, 0x90}; 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 @@ -282,7 +299,7 @@ mtable[] { #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} @@ -1112,6 +1129,7 @@ typedef struct int id; const char *name; int flags; + int align; asection *sec; asymbol *sym; asymbol **sympp; @@ -1120,6 +1138,8 @@ typedef struct } sinfo; +#ifndef DLLTOOL_PPC + #define TEXT 0 #define DATA 1 #define BSS 2 @@ -1127,20 +1147,54 @@ typedef struct #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 @@ -1164,11 +1218,25 @@ __imp_GetFileVersionInfoSizeW@8: 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 ); @@ -1177,10 +1245,11 @@ const char *name; 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) { @@ -1235,7 +1304,22 @@ int i; 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; @@ -1243,7 +1327,8 @@ int i; 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); } @@ -1251,6 +1336,7 @@ int i; 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; @@ -1260,8 +1346,10 @@ int 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; @@ -1274,16 +1362,23 @@ int i; 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; @@ -1297,9 +1392,34 @@ int i; 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++) @@ -1323,8 +1443,18 @@ int 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; @@ -1333,7 +1463,6 @@ int i; /* An idata$4 or idata$5 is one word long, and has an rva to idata$6 */ - si->data = xmalloc (4); si->size = 4; @@ -1386,6 +1515,115 @@ int i; 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; } } @@ -1395,8 +1633,10 @@ int i; 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;*/ } } @@ -1404,6 +1644,7 @@ int i; for (i = 0; i < NSECS; i++) { sinfo *si = secdata + i; + if (i == IDATA5 && no_idata5) continue; @@ -1424,8 +1665,7 @@ int i; } -static -bfd * +static bfd * make_head() { FILE * f = fopen ("dh.s", FOPEN_WT); @@ -1477,11 +1717,19 @@ make_head() 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); @@ -1496,6 +1744,25 @@ bfd * make_tail() 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"); -- 2.7.4