From 9a4c7f16697de0aea00870e4b6b183b149596ceb Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sat, 22 Dec 2001 17:18:34 +0000 Subject: [PATCH] -binitfini emulation, put __rtinit symbol generation into linker. --- bfd/ChangeLog | 13 +++ bfd/bfd-in.h | 2 + bfd/bfd-in2.h | 2 + bfd/coff-rs6000.c | 256 ++++++++++++++++++++++++++++++++++++++++++++ bfd/coff64-rs6000.c | 250 ++++++++++++++++++++++++++++++++++++++++++ bfd/libxcoff.h | 9 ++ bfd/xcofflink.c | 35 ++++++ ld/ChangeLog | 7 ++ ld/emultempl/aix.em | 102 +++++++++--------- 9 files changed, 625 insertions(+), 51 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f0c7fe71163..27bab56be62 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,16 @@ +2001-12-21 Tom Rix + + * xcofflink.c (bfd_xcoff_link_generate_rtinit): New function. + Interface to linker for generation of __rtinit. + * libxcoff.h (struct xcoff_backend_data_rec): Add new ops to xcoff + backend to generate special linker symbol __rtinit. + * coff-rs6000.c (bfd_xcoff_backend_data, bfd_pmac_xcoff_backend_data) + : Add new rtinit ops + * coff64-rs6000.c (bfd_xcoff_aix5_backend_data, + bfd_xcoff_backend_data): Same. + * bfd-in.h: Add bfd_xcoff_link_generate_rtinit. + * bfd-in2.h : Regenerate. + 2001-12-21 Jakub Jelinek * elf32-sparc.c (_bfd_sparc_elf_howto_table): Fix dst_mask for diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index c578614201b..c6f2b4162d4 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -724,6 +724,8 @@ extern boolean bfd_xcoff_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, unsigned long, unsigned long, unsigned long, boolean, int, boolean, boolean, struct sec **)); +extern boolean bfd_xcoff_link_generate_rtinit + PARAMS ((bfd *, const char *, const char *)); /* Externally visible COFF routines. */ diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 920df8de488..29831386496 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -730,6 +730,8 @@ extern boolean bfd_xcoff_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, unsigned long, unsigned long, unsigned long, boolean, int, boolean, boolean, struct sec **)); +extern boolean bfd_xcoff_link_generate_rtinit + PARAMS ((bfd *, const char *, const char *)); /* Externally visible COFF routines. */ diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index d97cb030ae9..932e437626d 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -2918,6 +2918,254 @@ xcoff_loader_reloc_offset (abfd, ldhdr) (ldhdr->l_nsyms * bfd_xcoff_ldsymsz(abfd)); } +static boolean +xcoff_generate_rtinit (abfd, init, fini) + bfd *abfd; + const char *init; + const char *fini; +{ + bfd_byte filehdr_ext[FILHSZ]; + bfd_byte scnhdr_ext[SCNHSZ]; + bfd_byte syment_ext[SYMESZ * 8]; + bfd_byte reloc_ext[RELSZ * 2]; + bfd_byte *data_buffer; + bfd_size_type data_buffer_size; + bfd_byte *string_table, *st_tmp; + bfd_size_type string_table_size; + bfd_vma val; + size_t initsz, finisz; + struct internal_filehdr filehdr; + struct internal_scnhdr scnhdr; + struct internal_syment syment; + union internal_auxent auxent; + struct internal_reloc reloc; + + char *data_name = ".data"; + char *rtinit_name = "__rtinit"; + + if (! bfd_xcoff_rtinit_size (abfd) + || (init == NULL && fini == NULL)) + return false; + + initsz = (init == NULL ? 0 : 1 + strlen (init)); + finisz = (fini == NULL ? 0 : 1 + strlen (fini)); + + /* file header */ + memset (filehdr_ext, 0, FILHSZ); + memset (&filehdr, 0, sizeof (struct internal_filehdr)); + filehdr.f_magic = bfd_xcoff_magic_number (abfd); + filehdr.f_nscns = 1; + filehdr.f_timdat = 0; + filehdr.f_nsyms = 0; /* at least 6, no more than 8 */ + filehdr.f_symptr = 0; /* set below */ + filehdr.f_opthdr = 0; + filehdr.f_flags = 0; + + /* section header */ + memset (scnhdr_ext, 0, SCNHSZ); + memset (&scnhdr, 0, sizeof (struct internal_scnhdr)); + memcpy (scnhdr.s_name, data_name, strlen (data_name)); + scnhdr.s_paddr = 0; + scnhdr.s_vaddr = 0; + scnhdr.s_size = 0; /* set below */ + scnhdr.s_scnptr = FILHSZ + SCNHSZ; + scnhdr.s_relptr = 0; /* set below */ + scnhdr.s_lnnoptr = 0; + scnhdr.s_nreloc = 0; /* either 1 or 2 */ + scnhdr.s_nlnno = 0; + scnhdr.s_flags = STYP_DATA; + + /* .data + 0x0000 0x00000000 : rtl + 0x0004 0x00000010 : offset to init, or 0 + 0x0008 0x00000028 : offset to fini, or 0 + 0x000C 0x0000000C : size of descriptor + 0x0010 0x00000000 : init, needs a reloc + 0x0014 0x00000040 : offset to init name + 0x0018 0x00000000 : flags, padded to a word + 0x001C 0x00000000 : empty init + 0x0020 0x00000000 : + 0x0024 0x00000000 : + 0x0028 0x00000000 : fini, needs a reloc + 0x002C 0x00000??? : offset to fini name + 0x0030 0x00000000 : flags, padded to a word + 0x0034 0x00000000 : empty fini + 0x0038 0x00000000 : + 0x003C 0x00000000 : + 0x0040 init name + 0x0040 + initsz fini name */ + + data_buffer_size = 0x0040 + initsz + finisz; + data_buffer_size += (data_buffer_size & 7) ? 8 - (data_buffer_size & 7) : 0; + data_buffer = (bfd_byte *)bfd_malloc (data_buffer_size); + memset (data_buffer, 0, data_buffer_size); + + if (initsz) + { + val = 0x10; + bfd_h_put_32 (abfd, val, &data_buffer[0x04]); + val = 0x40; + bfd_h_put_32 (abfd, val, &data_buffer[0x14]); + memcpy (&data_buffer[val], init, initsz); + } + + if (finisz) + { + val = 0x28; + bfd_h_put_32 (abfd, val, &data_buffer[0x08]); + val = 0x40 + initsz; + bfd_h_put_32 (abfd, val, &data_buffer[0x2C]); + memcpy (&data_buffer[val], fini, finisz); + } + + val = 0x0C; + bfd_h_put_32 (abfd, val, &data_buffer[0x0C]); + + scnhdr.s_size = data_buffer_size; + + /* string table */ + string_table_size = 0; + if (initsz > 9) + string_table_size += initsz; + if (finisz > 9) + string_table_size += finisz; + if (string_table_size) + { + string_table_size += 4; + string_table = (bfd_byte *)bfd_malloc (string_table_size); + memset (string_table, 0, string_table_size); + val = string_table_size; + bfd_h_put_32 (abfd, val, &string_table[0]); + st_tmp = string_table + 4; + } + + /* symbols + 0. .data csect + 2. __rtinit + 4. init function + 6. fini function */ + memset (syment_ext, 0, 8 * SYMESZ); + memset (reloc_ext, 0, 2 * RELSZ); + + /* .data csect */ + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + memcpy (syment._n._n_name, data_name, strlen (data_name)); + syment.n_scnum = 1; + syment.n_sclass = C_HIDEXT; + syment.n_numaux = 1; + auxent.x_csect.x_scnlen.l = data_buffer_size; + auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD; + auxent.x_csect.x_smclas = XMC_RW; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + filehdr.f_nsyms += 2; + + /* __rtinit */ + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + memcpy (syment._n._n_name, rtinit_name, strlen (rtinit_name)); + syment.n_scnum = 1; + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + auxent.x_csect.x_smtyp = XTY_LD; + auxent.x_csect.x_smclas = XMC_RW; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + filehdr.f_nsyms += 2; + + /* init */ + if (initsz) + { + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + + if (initsz > 9) + { + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, init, initsz); + st_tmp += initsz; + } + else + memcpy (syment._n._n_name, init, initsz - 1); + + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + + /* reloc */ + memset (&reloc, 0, sizeof (struct internal_reloc)); + reloc.r_vaddr = 0x0010; + reloc.r_symndx = filehdr.f_nsyms; + reloc.r_type = R_POS; + reloc.r_size = 31; + bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]); + + filehdr.f_nsyms += 2; + scnhdr.s_nreloc += 1; + } + + /* fini */ + if (finisz) + { + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + + if (finisz > 9) + { + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, fini, finisz); + st_tmp += finisz; + } + else + memcpy (syment._n._n_name, fini, finisz - 1); + + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + + /* reloc */ + memset (&reloc, 0, sizeof (struct internal_reloc)); + reloc.r_vaddr = 0x0028; + reloc.r_symndx = filehdr.f_nsyms; + reloc.r_type = R_POS; + reloc.r_size = 31; + bfd_coff_swap_reloc_out (abfd, &reloc, + &reloc_ext[scnhdr.s_nreloc * RELSZ]); + + filehdr.f_nsyms += 2; + scnhdr.s_nreloc += 1; + } + + scnhdr.s_relptr = scnhdr.s_scnptr + data_buffer_size; + filehdr.f_symptr = scnhdr.s_relptr + scnhdr.s_nreloc * RELSZ; + + bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext); + bfd_bwrite (filehdr_ext, FILHSZ, abfd); + bfd_coff_swap_scnhdr_out (abfd, &scnhdr, scnhdr_ext); + bfd_bwrite (scnhdr_ext, SCNHSZ, abfd); + bfd_bwrite (data_buffer, data_buffer_size, abfd); + bfd_bwrite (reloc_ext, scnhdr.s_nreloc * RELSZ, abfd); + bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd); + bfd_bwrite (string_table, string_table_size, abfd); + + return true; +} + static reloc_howto_type xcoff_dynamic_reloc = HOWTO (0, /* type */ @@ -3045,6 +3293,10 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = /* glink. */ & xcoff_glink_code[0], (36), /* _xcoff_glink_size */ + + /* rtinit */ + 64, /* _xcoff_rtinit_size */ + xcoff_generate_rtinit, /* _xcoff_generate_rtinit */ }; /* The transfer vector that leads the outside world to all of the above. */ @@ -3302,6 +3554,10 @@ static const struct xcoff_backend_data_rec bfd_pmac_xcoff_backend_data = &xcoff_glink_code[0], (36), /* _xcoff_glink_size */ + /* rtinit */ + 0, /* _xcoff_rtinit_size */ + xcoff_generate_rtinit, /* _xcoff_generate_rtinit */ + }; /* The transfer vector that leads the outside world to all of the above. */ diff --git a/bfd/coff64-rs6000.c b/bfd/coff64-rs6000.c index bc972418db9..52d7a226a7a 100644 --- a/bfd/coff64-rs6000.c +++ b/bfd/coff64-rs6000.c @@ -2094,6 +2094,252 @@ xcoff64_loader_reloc_offset (abfd, ldhdr) return (ldhdr->l_rldoff); } +static boolean +xcoff64_generate_rtinit (abfd, init, fini) + bfd *abfd; + const char *init; + const char *fini; +{ + bfd_byte filehdr_ext[FILHSZ]; + bfd_byte scnhdr_ext[SCNHSZ]; + bfd_byte syment_ext[SYMESZ * 8]; + bfd_byte reloc_ext[RELSZ * 2]; + bfd_byte *data_buffer; + bfd_size_type data_buffer_size; + bfd_byte *string_table, *st_tmp; + bfd_size_type string_table_size; + bfd_vma val; + size_t initsz, finisz; + struct internal_filehdr filehdr; + struct internal_scnhdr scnhdr; + struct internal_syment syment; + union internal_auxent auxent; + struct internal_reloc reloc; + + char *data_name = ".data"; + char *rtinit_name = "__rtinit"; + + if (! bfd_xcoff_rtinit_size (abfd) + || (init == NULL && fini == NULL)) + return false; + + initsz = (init == NULL ? 0 : 1 + strlen (init)); + finisz = (fini == NULL ? 0 : 1 + strlen (fini)); + + /* file header */ + memset (filehdr_ext, 0, FILHSZ); + memset (&filehdr, 0, sizeof (struct internal_filehdr)); + filehdr.f_magic = bfd_xcoff_magic_number (abfd); + filehdr.f_nscns = 1; + filehdr.f_timdat = 0; + filehdr.f_nsyms = 0; /* at least 6, no more than 8 */ + filehdr.f_symptr = 0; /* set below */ + filehdr.f_opthdr = 0; + filehdr.f_flags = 0; + + /* section header */ + memset (scnhdr_ext, 0, SCNHSZ); + memset (&scnhdr, 0, sizeof (struct internal_scnhdr)); + memcpy (scnhdr.s_name, data_name, strlen (data_name)); + scnhdr.s_paddr = 0; + scnhdr.s_vaddr = 0; + scnhdr.s_size = 0; /* set below */ + scnhdr.s_scnptr = FILHSZ + SCNHSZ; + scnhdr.s_relptr = 0; /* set below */ + scnhdr.s_lnnoptr = 0; + scnhdr.s_nreloc = 0; /* either 1 or 2 */ + scnhdr.s_nlnno = 0; + scnhdr.s_flags = STYP_DATA; + + /* .data + 0x0000 0x00000000 : rtl + 0x0004 0x00000000 : + 0x0008 0x00000018 : offset to init, or 0 + 0x000C 0x00000038 : offset to fini, or 0 + 0x0010 0x00000010 : size of descriptor + 0x0014 0x00000000 : pad + 0x0018 0x00000000 : init, needs a reloc + 0x001C 0x00000000 : + 0x0020 0x00000058 : offset to init name + 0x0024 0x00000000 : flags, padded to a word + 0x0028 0x00000000 : empty init + 0x002C 0x00000000 : + 0x0030 0x00000000 : + 0x0034 0x00000000 : + 0x0038 0x00000000 : fini, needs a reloc + 0x003C 0x00000000 : + 0x0040 0x00000??? : offset to fini name + 0x0044 0x00000000 : flags, padded to a word + 0x0048 0x00000000 : empty fini + 0x004C 0x00000000 : + 0x0050 0x00000000 : + 0x0054 0x00000000 : + 0x0058 init name + 0x0058 + initsz fini name */ + + data_buffer_size = 0x0058 + initsz + finisz; + data_buffer_size += (data_buffer_size & 7) ? 8 - (data_buffer_size & 7) : 0; + data_buffer = (bfd_byte *)bfd_malloc (data_buffer_size); + memset (data_buffer, 0, data_buffer_size); + + if (initsz) + { + val = 0x18; + bfd_put_32 (abfd, val, &data_buffer[0x08]); + val = 0x58; + bfd_put_32 (abfd, val, &data_buffer[0x20]); + memcpy (&data_buffer[val], init, initsz); + } + + if (finisz) + { + val = 0x38; + bfd_put_32 (abfd, val, &data_buffer[0x0C]); + val = 0x58 + initsz; + bfd_put_32 (abfd, val, &data_buffer[0x40]); + memcpy (&data_buffer[val], fini, finisz); + } + + val = 0x10; + bfd_put_32 (abfd, val, &data_buffer[0x10]); + scnhdr.s_size = data_buffer_size; + + /* string table */ + string_table_size = 4; + string_table_size += strlen (data_name) + 1; + string_table_size += strlen (rtinit_name) + 1; + string_table_size += initsz; + string_table_size += finisz; + + string_table = (bfd_byte *)bfd_malloc (string_table_size); + memset (string_table, 0, string_table_size); + val = string_table_size; + bfd_put_32 (abfd, val, &string_table[0]); + st_tmp = string_table + 4; + + /* symbols + 0. .data csect + 2. __rtinit + 4. init function + 6. fini function */ + memset (syment_ext, 0, 8 * SYMESZ); + memset (reloc_ext, 0, 2 * RELSZ); + + /* .data csect */ + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, data_name, strlen (data_name)); + st_tmp += strlen (data_name) + 1; + + syment.n_scnum = 1; + syment.n_sclass = C_HIDEXT; + syment.n_numaux = 1; + auxent.x_csect.x_scnlen.l = data_buffer_size; + auxent.x_csect.x_smtyp = 3 << 3 | XTY_SD; + auxent.x_csect.x_smclas = XMC_RW; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + filehdr.f_nsyms += 2; + + /* __rtinit */ + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, rtinit_name, strlen (rtinit_name)); + st_tmp += strlen (rtinit_name) + 1; + + syment.n_scnum = 1; + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + auxent.x_csect.x_smtyp = XTY_LD; + auxent.x_csect.x_smclas = XMC_RW; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + filehdr.f_nsyms += 2; + + /* init */ + if (initsz) + { + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, init, initsz); + st_tmp += initsz; + + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + /* reloc */ + memset (&reloc, 0, sizeof (struct internal_reloc)); + reloc.r_vaddr = 0x0018; + reloc.r_symndx = filehdr.f_nsyms; + reloc.r_type = R_POS; + reloc.r_size = 63; + bfd_coff_swap_reloc_out (abfd, &reloc, &reloc_ext[0]); + + filehdr.f_nsyms += 2; + scnhdr.s_nreloc += 1; + } + + /* finit */ + if (finisz) + { + memset (&syment, 0, sizeof (struct internal_syment)); + memset (&auxent, 0, sizeof (union internal_auxent)); + + syment._n._n_n._n_offset = st_tmp - string_table; + memcpy (st_tmp, fini, finisz); + st_tmp += finisz; + + syment.n_sclass = C_EXT; + syment.n_numaux = 1; + bfd_coff_swap_sym_out (abfd, &syment, + &syment_ext[filehdr.f_nsyms * SYMESZ]); + bfd_coff_swap_aux_out (abfd, &auxent, syment.n_type, syment.n_sclass, 0, + syment.n_numaux, + &syment_ext[(filehdr.f_nsyms + 1) * SYMESZ]); + + /* reloc */ + memset (&reloc, 0, sizeof (struct internal_reloc)); + reloc.r_vaddr = 0x0038; + reloc.r_symndx = filehdr.f_nsyms; + reloc.r_type = R_POS; + reloc.r_size = 63; + bfd_coff_swap_reloc_out (abfd, &reloc, + &reloc_ext[scnhdr.s_nreloc * RELSZ]); + + filehdr.f_nsyms += 2; + scnhdr.s_nreloc += 1; + } + + scnhdr.s_relptr = scnhdr.s_scnptr + data_buffer_size; + filehdr.f_symptr = scnhdr.s_relptr + scnhdr.s_nreloc * RELSZ; + + bfd_coff_swap_filehdr_out (abfd, &filehdr, filehdr_ext); + bfd_bwrite (filehdr_ext, FILHSZ, abfd); + bfd_coff_swap_scnhdr_out (abfd, &scnhdr, scnhdr_ext); + bfd_bwrite (scnhdr_ext, SCNHSZ, abfd); + bfd_bwrite (data_buffer, data_buffer_size, abfd); + bfd_bwrite (reloc_ext, scnhdr.s_nreloc * RELSZ, abfd); + bfd_bwrite (syment_ext, filehdr.f_nsyms * SYMESZ, abfd); + bfd_bwrite (string_table, string_table_size, abfd); + + return true; +} + /* The typical dynamic reloc. */ static reloc_howto_type xcoff64_dynamic_reloc = @@ -2219,6 +2465,10 @@ static const struct xcoff_backend_data_rec bfd_xcoff_backend_data = &xcoff64_glink_code[0], 40, /* _xcoff_glink_size */ + /* rtinit */ + 88, /* _xcoff_rtinit_size */ + xcoff64_generate_rtinit, /* _xcoff_generate_rtinit */ + }; /* The transfer vector that leads the outside world to all of the above. */ diff --git a/bfd/libxcoff.h b/bfd/libxcoff.h index b0ac0501f58..257e9e40309 100644 --- a/bfd/libxcoff.h +++ b/bfd/libxcoff.h @@ -112,6 +112,9 @@ struct xcoff_backend_data_rec */ unsigned long _xcoff_glink_size; + /* rtinit */ + unsigned int _xcoff_rtinit_size; + boolean (*_xcoff_generate_rtinit)(bfd *, const char *, const char *); }; /* Look up an entry in an XCOFF link hash table. */ @@ -201,9 +204,15 @@ struct xcoff_backend_data_rec #define bfd_xcoff_glink_code(a, b) ((xcoff_backend(a)->_xcoff_glink_code[(b)])) #define bfd_xcoff_glink_code_size(a) ((xcoff_backend(a)->_xcoff_glink_size)) +/* Check for the magic number U803XTOCMAGIC for 64 bit targets. */ #define bfd_xcoff_is_xcoff64(a) (0x01EF == (bfd_xcoff_magic_number(a))) + +/* Check for the magic number U802TOMAGIC for 32 bit targets. */ #define bfd_xcoff_is_xcoff32(a) (0x01DF == (bfd_xcoff_magic_number(a))) +#define bfd_xcoff_rtinit_size(a) ((xcoff_backend(a)->_xcoff_rtinit_size)) +#define bfd_xcoff_generate_rtinit(a, b, c) ((xcoff_backend(a)->_xcoff_generate_rtinit ((a), (b), (c)))) + /* Functions in xcofflink.c. */ extern long _bfd_xcoff_get_dynamic_symtab_upper_bound PARAMS ((bfd *)); diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index af6ebb1818e..e27f648d048 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -3219,6 +3219,41 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry, return false; } +boolean +bfd_xcoff_link_generate_rtinit (abfd, init, fini) + bfd *abfd; + const char *init; + const char *fini; +{ + struct bfd_in_memory *bim; + + bim = ((struct bfd_in_memory *) + bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory))); + if (bim == NULL) + return false; + + bim->size = 0; + bim->buffer = 0; + + abfd->link_next = 0; + abfd->format = bfd_object; + abfd->iostream = (PTR) bim; + abfd->flags = BFD_IN_MEMORY; + abfd->direction = write_direction; + abfd->where = 0; + + if (false == bfd_xcoff_generate_rtinit (abfd, init, fini)) + return false; + + /* need to reset to unknown or it will not be read back in correctly */ + abfd->format = bfd_unknown; + abfd->direction = read_direction; + abfd->where = 0; + + return true; +} + + /* Add a symbol to the .loader symbols, if necessary. */ static boolean diff --git a/ld/ChangeLog b/ld/ChangeLog index 4f01c884b70..3f6c7fef136 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,10 @@ +2001-12-21 Tom Rix + + (gld*_create_output_section_statements): New function. + For -binitfini support. + * emultempl/aix.em (gld*_before_parse): Fix comment. + * emultempl/aix.em (gld*_parse_args): Fix comment. + 2001-12-20 Jason Thorpe * configure.tgt (mips*-dec-netbsd*): Delete alias for diff --git a/ld/emultempl/aix.em b/ld/emultempl/aix.em index 1bc643b548b..e5db1b9c36b 100644 --- a/ld/emultempl/aix.em +++ b/ld/emultempl/aix.em @@ -67,6 +67,8 @@ static void gld${EMULATION_NAME}_find_exp_assignment PARAMS ((etree_type *)); static char *gld${EMULATION_NAME}_get_script PARAMS ((int *isfile)); static boolean gld${EMULATION_NAME}_unrecognized_file PARAMS ((lang_input_statement_type *)); +static void gld${EMULATION_NAME}_create_output_section_statements + PARAMS((void)); static int is_syscall PARAMS ((char *, unsigned int *)); static int change_symbol_mode PARAMS ((char *)); @@ -126,6 +128,9 @@ static int is_64bit = 0; /* Which syscalls from import file are valid */ static unsigned int syscall_mask = 0x77; +/* fake file for -binitfini support */ +static lang_input_statement_type *initfini_file; + /* This routine is called before anything else is done. */ static void @@ -144,11 +149,10 @@ gld${EMULATION_NAME}_before_parse () #endif /* not TARGET_ */ config.has_shared = true; - /* - * The link_info.[init|fini]_functions are initialized in ld/lexsup.c. - * Override them here so we can use the link_info.init_function as a - * state flag that lets the backend know that -binitfini has been done. - */ + /* The link_info.[init|fini]_functions are initialized in ld/lexsup.c. + Override them here so we can use the link_info.init_function as a + state flag that lets the backend know that -binitfini has been done. */ + link_info.init_function = NULL; link_info.fini_function = NULL; @@ -192,51 +196,14 @@ gld${EMULATION_NAME}_parse_args (argc, argv) OPTION_64, }; - /* - binitfini has special handling in the linker backend. The native linker - uses the arguemnts to generate a table of init and fini functions for - the executable. The important use for this option is to support aix 4.2+ - c++ constructors and destructors. This is tied into gcc via collect2.c. - The function table is accessed by the runtime linker/loader by checking if - the first symbol in the loader symbol table is "__rtinit". The native - linker generates this table and the loader symbol. The gnu linker looks - for the symbol "__rtinit" and makes it the first loader symbol. It is the - responsiblity of the user to define the __rtinit symbol. The format for - __rtinit is given by the aix system file /usr/include/rtinit.h. You can - look at collect2.c to see an example of how this is done for 32 and 64 bit. - Below is an exmaple of a 32 bit assembly file that defines __rtinit. - - .file "my_rtinit.s" - - .csect .data[RW],3 - .globl __rtinit - .extern init_function - .extern fini_function - - __rtinit: - .long 0 - .long f1i - __rtinit - .long f1f - __rtinit - .long f2i - f1i - .align 3 - f1i: .long init_function - .long s1i - __rtinit - .long 0 - f2i: .long 0 - .long 0 - .long 0 - f1f: .long fini_function - .long s1f - __rtinit - .long 0 - f2f: .long 0 - .long 0 - .long 0 - .align 3 - s1i: .string "init_function" - .align 3 - s1f: .string "fini_function" - - */ + /* -binitfini has special handling in the linker backend. The native linker + uses the arguemnts to generate a table of init and fini functions for + the executable. The important use for this option is to support aix 4.2+ + c++ constructors and destructors. This is tied into gcc via collect2.c. + + The function table is accessed by the runtime linker/loader by checking if + the first symbol in the loader symbol table is __rtinit. The gnu linker + generates this symbol and makes it the first loader symbol. */ static const struct option longopts[] = { {"basis", no_argument, NULL, OPTION_IGNORE}, @@ -1319,6 +1286,39 @@ fi cat >>e${EMULATION_NAME}.c <the_bfd = bfd_create ("initfini", output_bfd); + if (initfini_file->the_bfd == NULL + || ! bfd_set_arch_mach (initfini_file->the_bfd, + bfd_get_arch (output_bfd), + bfd_get_mach (output_bfd))) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + + /* Call backend to fill in the rest */ + if (false == bfd_xcoff_link_generate_rtinit (initfini_file->the_bfd, + link_info.init_function, + link_info.fini_function)) + { + einfo ("%X%P: can not create BFD %E\n"); + return; + } + } +} + struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { gld${EMULATION_NAME}_before_parse, syslib_default, @@ -1333,7 +1333,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = { "${EMULATION_NAME}", "${OUTPUT_FORMAT}", 0, /* finish */ - 0, /* create_output_section_statements */ + gld${EMULATION_NAME}_create_output_section_statements, 0, /* open_dynamic_archive */ 0, /* place_orphan */ 0, /* set_symbols */ -- 2.30.2