12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697 |
- /* ARC-specific support for 32-bit ELF
- Copyright (C) 1994-2015 Free Software Foundation, Inc.
- Contributed by Cupertino Miranda (cmiranda@synopsys.com).
- This file is part of BFD, the Binary File Descriptor library.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "sysdep.h"
- #include "bfd.h"
- #include "libbfd.h"
- #include "elf-bfd.h"
- #include "elf/arc.h"
- #include "libiberty.h"
- #include "opcode/arc-func.h"
- #define ARC_DEBUG(...)
- #define DEBUG(...) printf (__ARGV__)
- #define DEBUG_ARC_RELOC(A)
- struct arc_local_data
- {
- bfd_vma sdata_begin_symbol_vma;
- asection * sdata_output_section;
- bfd_vma got_symbol_vma;
- };
- struct arc_local_data global_arc_data =
- {
- .sdata_begin_symbol_vma = 0,
- .sdata_output_section = NULL,
- .got_symbol_vma = 0,
- };
- struct dynamic_sections
- {
- bfd_boolean initialized;
- asection * sgot;
- asection * srelgot;
- asection * sgotplt;
- asection * sdyn;
- asection * splt;
- asection * srelplt;
- };
- static struct dynamic_sections
- arc_create_dynamic_sections (bfd * abfd, struct bfd_link_info *info);
- enum dyn_section_types
- {
- got = 0,
- relgot,
- gotplt,
- dyn,
- plt,
- relplt,
- DYN_SECTION_TYPES_END
- };
- const char * dyn_section_names[DYN_SECTION_TYPES_END] =
- {
- ".got",
- ".rela.got",
- ".got.plt",
- ".dynamic",
- ".plt",
- ".rela.plt"
- };
- /* The default symbols representing the init and fini dyn values.
- TODO: Check what is the relation of those strings with arclinux.em
- and DT_INIT. */
- #define INIT_SYM_STRING "_init"
- #define FINI_SYM_STRING "_fini"
- char * init_str = INIT_SYM_STRING;
- char * fini_str = FINI_SYM_STRING;
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- case VALUE: \
- return #TYPE; \
- break;
- static ATTRIBUTE_UNUSED const char *
- reloc_type_to_name (unsigned int type)
- {
- switch (type)
- {
- #include "elf/arc-reloc.def"
- default:
- return "UNKNOWN";
- break;
- }
- }
- #undef ARC_RELOC_HOWTO
- /* Try to minimize the amount of space occupied by relocation tables
- on the ROM (not that the ROM won't be swamped by other ELF overhead). */
- #define USE_REL 1
- static ATTRIBUTE_UNUSED bfd_boolean
- is_reloc_PC_relative (reloc_howto_type *howto)
- {
- return (strstr (howto->name, "PC") != NULL) ? TRUE : FALSE;
- }
- static bfd_boolean
- is_reloc_SDA_relative (reloc_howto_type *howto)
- {
- return (strstr (howto->name, "SDA") != NULL) ? TRUE : FALSE;
- }
- static bfd_boolean
- is_reloc_for_GOT (reloc_howto_type * howto)
- {
- return (strstr (howto->name, "GOT") != NULL) ? TRUE : FALSE;
- }
- static bfd_boolean
- is_reloc_for_PLT (reloc_howto_type * howto)
- {
- return (strstr (howto->name, "PLT") != NULL) ? TRUE : FALSE;
- }
- #define arc_bfd_get_8(A,B,C) bfd_get_8(A,B)
- #define arc_bfd_get_16(A,B,C) bfd_get_16(A,B)
- #define arc_bfd_put_8(A,B,C,D) bfd_put_8(A,B,C)
- #define arc_bfd_put_16(A,B,C,D) bfd_put_16(A,B,C)
- static long
- arc_bfd_get_32 (bfd * abfd, void *loc, asection * input_section)
- {
- long insn = bfd_get_32 (abfd, loc);
- if (!bfd_big_endian (abfd)
- && input_section
- && (input_section->flags & SEC_CODE))
- insn = ((0x0000fffff & insn) << 16) | ((0xffff0000 & insn) >> 16);
- return insn;
- }
- static void
- arc_bfd_put_32 (bfd * abfd, long insn, void *loc, asection * input_section)
- {
- if (!bfd_big_endian (abfd)
- && input_section
- && (input_section->flags & SEC_CODE))
- insn = ((0x0000fffff & insn) << 16) | ((0xffff0000 & insn) >> 16);
- bfd_put_32 (abfd, insn, loc);
- }
- static bfd_reloc_status_type
- arc_elf_reloc (bfd *abfd ATTRIBUTE_UNUSED,
- arelent *reloc_entry,
- asymbol *symbol_in,
- void *data ATTRIBUTE_UNUSED,
- asection *input_section,
- bfd *output_bfd,
- char ** error_message ATTRIBUTE_UNUSED)
- {
- if (output_bfd != NULL)
- {
- reloc_entry->address += input_section->output_offset;
- /* In case of relocateable link and if the reloc is against a
- section symbol, the addend needs to be adjusted according to
- where the section symbol winds up in the output section. */
- if ((symbol_in->flags & BSF_SECTION_SYM) && symbol_in->section)
- reloc_entry->addend += symbol_in->section->output_offset;
- return bfd_reloc_ok;
- }
- return bfd_reloc_continue;
- }
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- TYPE = VALUE,
- enum howto_list
- {
- #include "elf/arc-reloc.def"
- HOWTO_LIST_LAST
- };
- #undef ARC_RELOC_HOWTO
- #define ARC_RELOC_HOWTO(TYPE, VALUE, RSIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- [TYPE] = HOWTO (R_##TYPE, 0, RSIZE, BITSIZE, FALSE, 0, complain_overflow_##OVERFLOW, arc_elf_reloc, #TYPE, FALSE, 0, 0, FALSE),
- static struct reloc_howto_struct elf_arc_howto_table[] =
- {
- #include "elf/arc-reloc.def"
- /* Example of what is generated by the preprocessor. Currently kept as an example.
- HOWTO (R_ARC_NONE, // Type.
- 0, // Rightshift.
- 2, // Size (0 = byte, 1 = short, 2 = long).
- 32, // Bitsize.
- FALSE, // PC_relative.
- 0, // Bitpos.
- complain_overflow_bitfield, // Complain_on_overflow.
- bfd_elf_generic_reloc, // Special_function.
- "R_ARC_NONE", // Name.
- TRUE, // Partial_inplace.
- 0, // Src_mask.
- 0, // Dst_mask.
- FALSE), // PCrel_offset.
- */
- };
- #undef ARC_RELOC_HOWTO
- static void arc_elf_howto_init (void)
- {
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- elf_arc_howto_table[TYPE].pc_relative = (strstr (#FORMULA, " P ") != NULL);
- #include "elf/arc-reloc.def"
- }
- #undef ARC_RELOC_HOWTO
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- [TYPE] = VALUE,
- const int howto_table_lookup[] =
- {
- #include "elf/arc-reloc.def"
- };
- #undef ARC_RELOC_HOWTO
- #define ARC_ELF_HOWTO(r_type) \
- (&elf_arc_howto_table[r_type])
- /* Map BFD reloc types to ARC ELF reloc types. */
- struct arc_reloc_map
- {
- bfd_reloc_code_real_type bfd_reloc_val;
- unsigned char elf_reloc_val;
- };
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- { BFD_RELOC_##TYPE, R_##TYPE },
- static const struct arc_reloc_map arc_reloc_map[] =
- {
- #include "elf/arc-reloc.def"
- {BFD_RELOC_NONE, R_ARC_NONE},
- {BFD_RELOC_8, R_ARC_8},
- {BFD_RELOC_16, R_ARC_16},
- {BFD_RELOC_24, R_ARC_24},
- {BFD_RELOC_32, R_ARC_32},
- };
- #undef ARC_RELOC_HOWTO
- static reloc_howto_type *
- bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
- bfd_reloc_code_real_type code)
- {
- unsigned int i;
- static int fully_initialized = FALSE;
- if (fully_initialized == FALSE)
- {
- arc_elf_howto_init ();
- fully_initialized = TRUE; /* TODO: CHECK THIS IF IT STOPS WORKING. */
- }
- for (i = ARRAY_SIZE (arc_reloc_map); i--;)
- {
- if (arc_reloc_map[i].bfd_reloc_val == code)
- return elf_arc_howto_table + arc_reloc_map[i].elf_reloc_val;
- }
- return NULL;
- }
- static reloc_howto_type *
- bfd_elf32_bfd_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, const char *r_name)
- {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE (elf_arc_howto_table); i++)
- if (elf_arc_howto_table[i].name != NULL
- && strcasecmp (elf_arc_howto_table[i].name, r_name) == 0)
- return elf_arc_howto_table + i;
- return NULL;
- }
- /* Set the howto pointer for an ARC ELF reloc. */
- static void
- arc_info_to_howto_rel (bfd * abfd ATTRIBUTE_UNUSED,
- arelent * cache_ptr,
- Elf_Internal_Rela * dst)
- {
- unsigned int r_type;
- r_type = ELF32_R_TYPE (dst->r_info);
- BFD_ASSERT (r_type < (unsigned int) R_ARC_max);
- cache_ptr->howto = &elf_arc_howto_table[r_type];
- }
- /* Set the right machine number for an ARC ELF file. */
- static bfd_boolean
- arc_elf_object_p (bfd * abfd)
- {
- /* Make sure this is initialised, or you'll have the potential of passing
- garbage---or misleading values---into the call to
- bfd_default_set_arch_mach (). */
- int mach = bfd_mach_arc_arc700;
- unsigned long arch = elf_elfheader (abfd)->e_flags & EF_ARC_MACH_MSK;
- unsigned e_machine = elf_elfheader (abfd)->e_machine;
- if (e_machine == EM_ARC_COMPACT || e_machine == EM_ARC_COMPACT2)
- {
- switch (arch)
- {
- case E_ARC_MACH_ARC600:
- mach = bfd_mach_arc_arc600;
- break;
- case E_ARC_MACH_ARC601:
- mach = bfd_mach_arc_arc601;
- break;
- case E_ARC_MACH_ARC700:
- mach = bfd_mach_arc_arc700;
- break;
- case EF_ARC_CPU_ARCV2HS:
- case EF_ARC_CPU_ARCV2EM:
- mach = bfd_mach_arc_arcv2;
- break;
- default:
- mach = (e_machine == EM_ARC_COMPACT) ?
- bfd_mach_arc_arc700 : bfd_mach_arc_arcv2;
- break;
- }
- }
- else
- {
- if (e_machine == EM_ARC)
- {
- (*_bfd_error_handler)
- (_("Error: The ARC4 architecture is no longer supported.\n"));
- return FALSE;
- }
- else
- {
- (*_bfd_error_handler)
- (_("Warning: unset or old architecture flags. \n"
- " Use default machine.\n"));
- }
- }
- return bfd_default_set_arch_mach (abfd, bfd_arch_arc, mach);
- }
- /* The final processing done just before writing out an ARC ELF object file.
- This gets the ARC architecture right based on the machine number. */
- static void
- arc_elf_final_write_processing (bfd * abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
- {
- unsigned long val;
- unsigned long emf;
- switch (bfd_get_mach (abfd))
- {
- case bfd_mach_arc_arc600:
- val = E_ARC_MACH_ARC600;
- emf = EM_ARC_COMPACT;
- break;
- case bfd_mach_arc_arc601:
- val = E_ARC_MACH_ARC601;
- emf = EM_ARC_COMPACT;
- break;
- case bfd_mach_arc_arc700:
- val = E_ARC_MACH_ARC700;
- emf = EM_ARC_COMPACT;
- break;
- case bfd_mach_arc_arcv2:
- val = EF_ARC_CPU_GENERIC;
- emf = EM_ARC_COMPACT2;
- /* TODO: Check validity of this. It can also be ARCV2EM here.
- Previous version sets the e_machine here. */
- break;
- default:
- abort ();
- }
- elf_elfheader (abfd)->e_flags &= ~EF_ARC_MACH;
- elf_elfheader (abfd)->e_flags |= val;
- elf_elfheader (abfd)->e_machine = emf;
- /* Record whatever is the current syscall ABI version. */
- elf_elfheader (abfd)->e_flags |= E_ARC_OSABI_CURRENT;
- }
- #define BFD_DEBUG_PIC(...)
- struct arc_relocation_data
- {
- bfd_vma reloc_offset;
- bfd_vma reloc_addend;
- bfd_vma got_offset_value;
- bfd_vma sym_value;
- asection * sym_section;
- reloc_howto_type *howto;
- asection * input_section;
- bfd_vma sdata_begin_symbol_vma;
- bfd_boolean sdata_begin_symbol_vma_set;
- bfd_vma got_symbol_vma;
- bfd_boolean should_relocate;
- };
- static void
- debug_arc_reloc (struct arc_relocation_data reloc_data)
- {
- fprintf (stderr, "Reloc type=%s, should_relocate = %s\n",
- reloc_data.howto->name,
- reloc_data.should_relocate ? "true" : "false");
- fprintf (stderr, " offset = 0x%x, addend = 0x%x\n",
- (unsigned int) reloc_data.reloc_offset,
- (unsigned int) reloc_data.reloc_addend);
- fprintf (stderr, " Symbol:\n");
- fprintf (stderr, " value = 0x%08x\n",
- (unsigned int) reloc_data.sym_value);
- if (reloc_data.sym_section != NULL)
- {
- fprintf (stderr, "IN IF\n");
- fprintf (stderr,
- " section name = %s, output_offset 0x%08x, output_section->vma = 0x%08x\n",
- reloc_data.sym_section->name,
- (unsigned int) reloc_data.sym_section->output_offset,
- (unsigned int) reloc_data.sym_section->output_section->vma);
- }
- else
- fprintf (stderr, " symbol section is NULL\n");
- fprintf (stderr, " Input_section:\n");
- if (reloc_data.input_section != NULL)
- {
- fprintf (stderr,
- " section name = %s, output_offset 0x%08x, output_section->vma = 0x%08x\n",
- reloc_data.input_section->name,
- (unsigned int) reloc_data.input_section->output_offset,
- (unsigned int) reloc_data.input_section->output_section->vma);
- fprintf (stderr, " changed_address = 0x%08x\n",
- (unsigned int) (reloc_data.input_section->output_section->vma +
- reloc_data.input_section->output_offset +
- reloc_data.reloc_offset));
- }
- else
- fprintf (stderr, " input section is NULL\n");
- }
- #define S (reloc_data.sym_value \
- + reloc_data.sym_section->output_offset \
- + reloc_data.sym_section->output_section->vma)
- #define A (reloc_data.reloc_addend)
- #define B (0)
- #define G (reloc_data.got_offset_value)
- #define GOT (reloc_data.got_symbol_vma + 12)
- #define L (reloc_data.sym_value \
- + reloc_data.sym_section->output_section->vma \
- + reloc_data.sym_section->output_offset)
- #define MES (0)
- /* P: relative offset to PCL The offset should be to the current location
- aligned to 32 bits. */
- #define P ( \
- (reloc_data.input_section->output_section->vma \
- + reloc_data.input_section->output_offset \
- + (reloc_data.reloc_offset - (bitsize >= 32 ? 4 : 0)) \
- ) & ~0x3)
- #define SECTSTAR (reloc_data.input_section->output_offset)
- #define SECTSTART (reloc_data.input_section->output_offset)
- #define _SDA_BASE_ (reloc_data.sdata_begin_symbol_vma)
- #define none (0)
- #define ARC_RELOC_HOWTO(TYPE, VALUE, SIZE, BITSIZE, RELOC_FUNCTION, OVERFLOW, FORMULA) \
- case R_##TYPE: \
- { \
- bfd_vma bitsize ATTRIBUTE_UNUSED = BITSIZE; \
- relocation = FORMULA ; \
- insn = RELOC_FUNCTION (insn, relocation); \
- } \
- break;
- static bfd_reloc_status_type
- arc_do_relocation (bfd_byte * contents, struct arc_relocation_data reloc_data)
- {
- bfd_vma relocation = 0;
- bfd_vma insn;
- bfd_vma orig_insn ATTRIBUTE_UNUSED;
- if (reloc_data.should_relocate == FALSE)
- return bfd_reloc_notsupported;
- switch (reloc_data.howto->size)
- {
- case 2:
- insn = arc_bfd_get_32 (reloc_data.input_section->owner,
- contents + reloc_data.reloc_offset,
- reloc_data.input_section);
- break;
- case 1:
- case 0:
- insn = arc_bfd_get_16 (reloc_data.input_section->owner,
- contents + reloc_data.reloc_offset,
- reloc_data.input_section);
- break;
- default:
- insn = 0;
- BFD_ASSERT (0);
- break;
- }
- orig_insn = insn;
- switch (reloc_data.howto->type)
- {
- #include "elf/arc-reloc.def"
- default:
- BFD_ASSERT (0);
- break;
- }
- /* Check for relocation overflow. */
- if (reloc_data.howto->complain_on_overflow != complain_overflow_dont)
- {
- bfd_reloc_status_type flag;
- flag = bfd_check_overflow (reloc_data.howto->complain_on_overflow,
- reloc_data.howto->bitsize,
- reloc_data.howto->rightshift,
- bfd_arch_bits_per_address (reloc_data.input_section->owner),
- relocation);
- #undef DEBUG_ARC_RELOC
- #define DEBUG_ARC_RELOC(A) debug_arc_reloc (A)
- if (flag != bfd_reloc_ok)
- {
- fprintf (stderr, "Relocation overflows !!!!\n");
- DEBUG_ARC_RELOC (reloc_data);
- fprintf (stderr,
- "Relocation value = signed -> %d, unsigned -> %u, hex -> (0x%08x)\n",
- (int) relocation,
- (unsigned int) relocation,
- (unsigned int) relocation);
- return flag;
- }
- }
- #undef DEBUG_ARC_RELOC
- #define DEBUG_ARC_RELOC(A)
- switch (reloc_data.howto->size)
- {
- case 2:
- arc_bfd_put_32 (reloc_data.input_section->owner, insn,
- contents + reloc_data.reloc_offset,
- reloc_data.input_section);
- break;
- case 1:
- case 0:
- arc_bfd_put_16 (reloc_data.input_section->owner, insn,
- contents + reloc_data.reloc_offset,
- reloc_data.input_section);
- break;
- default:
- ARC_DEBUG ("size = %d\n", reloc_data.howto->size);
- BFD_ASSERT (0);
- break;
- }
- return bfd_reloc_ok;
- }
- #undef S
- #undef A
- #undef B
- #undef G
- #undef GOT
- #undef L
- #undef MES
- #undef P
- #undef SECTSTAR
- #undef SECTSTART
- #undef _SDA_BASE_
- #undef none
- #undef ARC_RELOC_HOWTO
- static bfd_vma *
- arc_get_local_got_offsets (bfd * abfd)
- {
- static bfd_vma *local_got_offsets = NULL;
- if (local_got_offsets == NULL)
- {
- size_t size;
- unsigned int i;
- Elf_Internal_Shdr *symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
- size = symtab_hdr->sh_info * sizeof (bfd_vma);
- local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size);
- if (local_got_offsets == NULL)
- return FALSE;
- elf_local_got_offsets (abfd) = local_got_offsets;
- for (i = 0; i < symtab_hdr->sh_info; i++)
- local_got_offsets[i] = (bfd_vma) - 1;
- }
- return local_got_offsets;
- }
- /* Relocate an arc ELF section.
- Function : elf_arc_relocate_section
- Brief : Relocate an arc section, by handling all the relocations
- appearing in that section.
- Args : output_bfd : The bfd being written to.
- info : Link information.
- input_bfd : The input bfd.
- input_section : The section being relocated.
- contents : contents of the section being relocated.
- relocs : List of relocations in the section.
- local_syms : is a pointer to the swapped in local symbols.
- local_section : is an array giving the section in the input file
- corresponding to the st_shndx field of each
- local symbol. */
- static bfd_boolean
- elf_arc_relocate_section (bfd * output_bfd,
- struct bfd_link_info * info,
- bfd * input_bfd,
- asection * input_section,
- bfd_byte * contents,
- Elf_Internal_Rela * relocs,
- Elf_Internal_Sym * local_syms,
- asection ** local_sections)
- {
- Elf_Internal_Shdr * symtab_hdr;
- struct elf_link_hash_entry ** sym_hashes;
- bfd_vma * local_got_offsets;
- Elf_Internal_Rela * rel;
- Elf_Internal_Rela * relend;
- symtab_hdr = &((elf_tdata (input_bfd))->symtab_hdr);
- sym_hashes = elf_sym_hashes (input_bfd);
- rel = relocs;
- relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
- {
- enum elf_arc_reloc_type r_type;
- reloc_howto_type * howto;
- unsigned long r_symndx;
- struct elf_link_hash_entry * h;
- Elf_Internal_Sym * sym;
- asection * sec;
- struct arc_relocation_data reloc_data =
- {
- .reloc_offset = 0, /* bfd_vma reloc_offset; */
- .reloc_addend = 0, /* bfd_vma reloc_addend; */
- .got_offset_value = 0, /* bfd_vma got_offset_value; */
- .sym_value = 0, /* bfd_vma sym_value; */
- .sym_section = NULL, /* asection *sym_section; */
- .howto = NULL, /* reloc_howto_type *howto; */
- .input_section = NULL, /* asection *input_section; */
- .sdata_begin_symbol_vma = 0, /* bfd_vma sdata_begin_symbol_vma; */
- .sdata_begin_symbol_vma_set = FALSE, /* bfd_vma sdata_begin_symbol_vma_set; */
- .got_symbol_vma = 0, /* bfd_vma got_symbol_vma; */
- .should_relocate = FALSE /* bfd_boolean should_relocate; */
- };
- struct elf_link_hash_entry *h2;
- h2 = elf_link_hash_lookup (elf_hash_table (info), "__SDATA_BEGIN__",
- FALSE, FALSE, TRUE);
- if (reloc_data.sdata_begin_symbol_vma_set == FALSE
- && h2 != NULL && h2->root.type != bfd_link_hash_undefined)
- {
- reloc_data.sdata_begin_symbol_vma =
- (h2->root.u.def.value +
- h2->root.u.def.section->output_section->vma);
- reloc_data.sdata_begin_symbol_vma_set = TRUE;
- }
- h2 = elf_link_hash_lookup (elf_hash_table (info),
- "_GLOBAL_OFFSET_TABLE_", FALSE, FALSE,
- TRUE);
- if (h2 != NULL && h2->root.type != bfd_link_hash_undefined)
- {
- reloc_data.got_symbol_vma =
- (h2->root.u.def.value +
- h2->root.u.def.section->output_section->vma);
- }
- r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type >= (int) R_ARC_max)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- howto = &elf_arc_howto_table[r_type];
- reloc_data.input_section = input_section;
- reloc_data.howto = howto;
- reloc_data.reloc_offset = rel->r_offset;
- reloc_data.reloc_addend = rel->r_addend;
- r_symndx = ELF32_R_SYM (rel->r_info);
- /* This is a final link. */
- h = NULL;
- sym = NULL;
- sec = NULL;
- if (r_symndx < symtab_hdr->sh_info) /* A local symbol. */
- {
- sym = local_syms + r_symndx;
- sec = local_sections[r_symndx];
- reloc_data.sym_value = sym->st_value;
- reloc_data.sym_section = sec;
- if (is_reloc_for_GOT (reloc_data.howto))
- {
- local_got_offsets = arc_get_local_got_offsets (output_bfd);
- reloc_data.got_offset_value = local_got_offsets[r_symndx];
- }
- reloc_data.should_relocate = TRUE;
- }
- else /* Global symbol. */
- {
- /* Get the symbol's entry in the symtab. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- BFD_ASSERT ((h->dynindx == -1) >= (h->forced_local != 0));
- /* If we have encountered a definition for this symbol. */
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- reloc_data.sym_value = h->root.u.def.value;
- reloc_data.sym_section = h->root.u.def.section;
- reloc_data.should_relocate = TRUE;
- if (is_reloc_for_GOT (howto))
- {
- struct dynamic_sections ds =
- arc_create_dynamic_sections (output_bfd, info);
- /* TODO: Change it to use arc_do_relocation with ARC_32
- reloc. */
- bfd_vma relocation =
- reloc_data.sym_value + reloc_data.reloc_addend
- + reloc_data.sym_section->output_offset
- + reloc_data.sym_section->output_section->vma;
- bfd_put_32 (output_bfd, relocation, ds.sgot->contents + h->got.offset);
- }
- }
- else if (h->root.type == bfd_link_hash_undefweak)
- {
- /* Is weak symbol and has no definition. */
- continue;
- }
- else
- {
- if (is_reloc_for_GOT (howto))
- {
- struct dynamic_sections ds =
- arc_create_dynamic_sections (output_bfd, info);
- reloc_data.sym_value = h->root.u.def.value;
- reloc_data.sym_section = ds.sgot;
- reloc_data.should_relocate = TRUE;
- }
- else if (is_reloc_for_PLT (howto))
- {
- struct dynamic_sections ds =
- arc_create_dynamic_sections (output_bfd, info);
- reloc_data.sym_value = h->plt.offset;
- reloc_data.sym_section = ds.splt;
- reloc_data.should_relocate = TRUE;
- }
- else if (!(*info->callbacks->undefined_symbol)
- (info, h->root.root.string, input_bfd, input_section,
- rel->r_offset,!bfd_link_pic (info)))
- {
- return FALSE;
- }
- }
- reloc_data.got_offset_value = h->got.offset;
- }
- if (is_reloc_SDA_relative (howto) && reloc_data.sdata_begin_symbol_vma_set == FALSE)
- {
- (*_bfd_error_handler)
- ("Error: Linker symbol __SDATA_BEGIN__ not found");
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- DEBUG_ARC_RELOC (reloc_data);
- if (arc_do_relocation (contents, reloc_data) != bfd_reloc_ok)
- return FALSE;
- }
- return TRUE;
- }
- static struct dynamic_sections
- arc_create_dynamic_sections (bfd * abfd, struct bfd_link_info *info)
- {
- static bfd * dynobj = NULL;
- struct dynamic_sections ds =
- {
- .initialized = FALSE,
- .sgot = NULL,
- .srelgot = NULL,
- .sgotplt = NULL,
- .sdyn = NULL,
- .splt = NULL,
- .srelplt = NULL
- };
- if (dynobj == NULL)
- {
- elf_hash_table (info)->dynobj = dynobj = abfd;
- if (!_bfd_elf_create_got_section (dynobj, info))
- return ds;
- }
- else
- dynobj = (elf_hash_table (info))->dynobj;
- ds.sgot = bfd_get_section_by_name (dynobj, ".got");
- ds.srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
- if (ds.srelgot == NULL)
- {
- ds.srelgot = bfd_make_section_with_flags (dynobj, ".rela.got",
- SEC_ALLOC
- | SEC_LOAD
- | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY
- | SEC_LINKER_CREATED
- | SEC_READONLY);
- if (ds.srelgot == NULL
- || !bfd_set_section_alignment (dynobj, ds.srelgot, 2))
- return ds;
- }
- ds.sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
- ds.sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
- ds.splt = bfd_get_section_by_name (dynobj, ".plt");
- ds.srelplt = bfd_get_section_by_name (dynobj, ".rela.plt");
- ds.initialized = TRUE;
- return ds;
- }
- #define ADD_SYMBOL_REF_SEC_AND_RELOC(SECNAME, COND_FOR_RELOC, H) \
- ds.s##SECNAME->size; \
- { \
- if (COND_FOR_RELOC) ds.srel##SECNAME->size += sizeof (Elf32_External_Rela); \
- if (H) \
- if (h->dynindx == -1 && !h->forced_local) \
- if (! bfd_elf_link_record_dynamic_symbol (info, H)) \
- return FALSE; \
- ds.s##SECNAME->size += 4; \
- }
- static bfd_boolean
- elf_arc_check_relocs (bfd * abfd,
- struct bfd_link_info * info,
- asection * sec,
- const Elf_Internal_Rela * relocs)
- {
- Elf_Internal_Shdr * symtab_hdr;
- struct elf_link_hash_entry ** sym_hashes;
- bfd_vma * local_got_offsets;
- const Elf_Internal_Rela * rel;
- const Elf_Internal_Rela * rel_end;
- bfd * dynobj ATTRIBUTE_UNUSED;
- dynobj = (elf_hash_table (info))->dynobj;
- symtab_hdr = &((elf_tdata (abfd))->symtab_hdr);
- sym_hashes = elf_sym_hashes (abfd);
- local_got_offsets = arc_get_local_got_offsets (abfd);
- struct dynamic_sections ds = arc_create_dynamic_sections (abfd, info);
- rel_end = relocs + sec->reloc_count;
- for (rel = relocs; rel < rel_end; rel++)
- {
- enum elf_arc_reloc_type r_type;
- reloc_howto_type *howto;
- unsigned long r_symndx;
- struct elf_link_hash_entry *h;
- r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type >= (int) R_ARC_max)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- howto = &elf_arc_howto_table[r_type];
- /* Load symbol information. */
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (r_symndx < symtab_hdr->sh_info) /* Is a local symbol. */
- h = NULL;
- else /* Global one. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- if (is_reloc_for_PLT (howto) == TRUE)
- {
- if (h == NULL)
- continue;
- else
- h->needs_plt = 1;
- }
- if (is_reloc_for_GOT (howto) == TRUE)
- {
- if (h == NULL)
- {
- /* Local symbol. */
- local_got_offsets[r_symndx] =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got, bfd_link_pic (info), NULL);
- }
- else
- {
- /* Global symbol. */
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- h->got.offset =
- ADD_SYMBOL_REF_SEC_AND_RELOC (got, TRUE, h);
- }
- }
- }
- return TRUE;
- }
- #define ELF_DYNAMIC_INTERPRETER "/sbin/ld-uClibc.so"
- /* Size of one plt entry in bytes. */
- #define PLT_ENTRY_SIZE 12
- #define PLT_ENTRY_SIZE_V2 16
- /* Instructions appear in memory as a sequence of half-words (16 bit);
- individual half-words are represented on the target in target byte order.
- We use 'unsigned short' on the host to represent the PLT templates,
- and translate to target byte order as we copy to the target. */
- typedef unsigned short insn_hword;
- /* TODO: Make this PLT entry code be in a separate object file. */
- /* TODO: This is a linker BTW, we should be able to link. :) */
- /* The zeroth entry in the absolute plt entry. */
- static const insn_hword elf_arc_abs_plt0_entry[2 * PLT_ENTRY_SIZE / 2] =
- {
- 0x1600, /* ld %r11, [0] */
- 0x700b,
- 0x0000,
- 0x0000,
- 0x1600, /* ld %r10, [0] */
- 0x700a, /* */
- 0,
- 0,
- 0x2020, /* j [%r10] */
- 0x0280, /* ---"---- */
- 0x0000, /* pad */
- 0x0000 /* pad */
- };
- /* Contents of the subsequent entries in the absolute plt. */
- static const insn_hword elf_arc_abs_pltn_entry[PLT_ENTRY_SIZE / 2] =
- {
- 0x2730, /* ld %r12, [%pc,func@gotpc] */
- 0x7f8c, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x7c20, /* j_s.d [%r12] */
- 0x74ef /* mov_s %r12, %pcl */
- };
- /* The zeroth entry in the absolute plt entry for ARCv2. */
- static const insn_hword elf_arcV2_abs_plt0_entry[2 * PLT_ENTRY_SIZE_V2 / 2] =
- {
- 0x1600, 0x700b, 0, 0, /* ld %r11, [0] */
- 0x1600, 0x700a, 0, 0, /* ld %r10, [0] */
- 0x2020, 0x0280, /* j [%r10] */
- 0x0000, 0x0000, /* -> RELOCATED TO ABS ADDRESS OF GOT <- */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000 /* pad */
- };
- /* Contents of the subsequent entries in the absolute plt for ARCv2. */
- static const insn_hword elf_arcV2_abs_pltn_entry[PLT_ENTRY_SIZE_V2 / 2] =
- {
- 0x2730, /* ld %r12, [%pcl,func@gotpc] */
- 0x7f8c, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x2021, /* j.d [%r12] */
- 0x0300, /* ------ " " -------------- */
- 0x240a, /* mov %r12, %pcl */
- 0x1fc0 /* ------ " " -------------- */
- };
- /* The zeroth entry in the pic plt entry. */
- static const insn_hword elf_arc_pic_plt0_entry[2 * PLT_ENTRY_SIZE / 2] =
- {
- 0x2730, /* ld %r11, [pcl,0] : 0 to be replaced by
- _DYNAMIC@GOTPC+4 */
- 0x7f8b,
- 0x0000,
- 0x0000,
- 0x2730, /* ld %r10, [pcl,0] : 0 to be replaced by
- -DYNAMIC@GOTPC+8 */
- 0x7f8a, /* */
- 0,
- 0,
- 0x2020, /* j [%r10] */
- 0x0280, /* ---"---- */
- 0x0000, /* pad */
- 0x0000 /* pad */
- };
- /* Contents of the subsequent entries in the pic plt. */
- static const insn_hword elf_arc_pic_pltn_entry[PLT_ENTRY_SIZE / 2] =
- {
- 0x2730, /* ld %r12, [%pc,func@got] */
- 0x7f8c, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x7c20, /* j_s.d [%r12] */
- 0x74ef, /* mov_s %r12, %pcl */
- };
- /* The zeroth entry in the pic plt entry for ARCv2. */
- static const insn_hword elf_arcV2_pic_plt0_entry[2 * PLT_ENTRY_SIZE_V2 / 2] =
- {
- 0x2730, /* ld %r11, [pcl,0] : 0 to be replaced by
- _DYNAMIC@GOTPC+4 */
- 0x7f8b,
- 0x0000,
- 0x0000,
- 0x2730, /* ld %r10, [pcl,0] : 0 to be replaced by
- -DYNAMIC@GOTPC+8 */
- 0x7f8a, /* */
- 0,
- 0,
- 0x2020, /* j [%r10] */
- 0x0280, /* ---"---- */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000, /* pad */
- 0x0000 /* pad */
- };
- #define elf_arcV2_pic_PLT0_ENTRY_SIZE (2 * PLT_ENTRY_SIZE_V2/2)
- /* Contents of the subsequent entries in the pic plt for ARCv2. */
- static const insn_hword elf_arcV2_pic_pltn_entry[PLT_ENTRY_SIZE_V2 / 2] =
- {
- 0x2730, /* ld %r12, [%pc,func@got] */
- 0x7f8c, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x0000, /* ------ " " -------------- */
- 0x2021, /* j.d [%r12] */
- 0x0300, /* ------ " " -------------- */
- 0x240a, /* mov %r12, %pcl */
- 0x1fc0 /* ------ " " -------------- */
- };
- #define elf_arcV2_pic_PLTN_ENTRY_SIZE (PLT_ENTRY_SIZE_V2/2)
- enum plt_reloc_symbol
- {
- LAST_RELOC = 0,
- SGOT = 1,
- RELATIVE = (1 << 8),
- MIDDLE_ENDIAN = (1 << 9)
- };
- #define IS_RELATIVE(S) ((S & RELATIVE) != 0)
- #define IS_MIDDLE_ENDIAN(S) ((S & MIDDLE_ENDIAN) != 0)
- #define SYM_ONLY(S) (S & 0xFF)
- struct plt_reloc
- {
- bfd_vma offset;
- bfd_vma size;
- bfd_vma mask;
- enum plt_reloc_symbol symbol;
- bfd_vma addend;
- };
- struct plt_version_t
- {
- const insn_hword * entry;
- const bfd_vma entry_size;
- const insn_hword * elem;
- const bfd_vma elem_size;
- struct plt_reloc entry_relocs[5];
- struct plt_reloc elem_relocs[5];
- };
- #define PLT_DATA(NAME, ...) \
- .entry = NAME##_plt0_entry, \
- .entry_size = NAME##_PLT0_ENTRY_SIZE, \
- .elem = NAME##_pltn_entry, \
- .elem_size = NAME##_PLTN_ENTRY_SIZE
- struct plt_version_t plt_versions[] =
- {
- {
- PLT_DATA (elf_arcV2_pic),
- .entry_relocs =
- {
- {4, 32, 0xFFFFFFFF, SGOT | RELATIVE | MIDDLE_ENDIAN, 4},
- {12, 32, 0xFFFFFFFF, SGOT | RELATIVE | MIDDLE_ENDIAN, 8},
- {20, 32, 0xFFFFFFFF, SGOT, 0},
- {0, 0, 0, LAST_RELOC, 0}
- },
- .elem_relocs =
- {
- {4, 32, 0xFFFFFFFF, SGOT, 0},
- {0, 0, 0, LAST_RELOC, 0}
- }
- }
- };
- #undef PLT_DATA
- static struct plt_version_t *
- arc_get_plt_version (void)
- {
- return &(plt_versions[0]);
- }
- static bfd_vma
- add_symbol_to_plt (struct bfd_link_info *info)
- {
- bfd *dynobj = (elf_hash_table (info))->dynobj;
- struct dynamic_sections ds = arc_create_dynamic_sections (dynobj, info);
- bfd_vma ret;
- /* If this is the first .plt entry, make room for the special first entry. */
- if (ds.splt->size == 0)
- ds.splt->size += 2 *
- (bfd_get_mach (dynobj) == bfd_mach_arc_arcv2
- ? PLT_ENTRY_SIZE_V2 : PLT_ENTRY_SIZE);
- ret = ds.splt->size;
- ds.splt->size += (bfd_get_mach (dynobj) == bfd_mach_arc_arcv2
- ? PLT_ENTRY_SIZE_V2
- : PLT_ENTRY_SIZE
- );
- ds.sgotplt->size += 4;
- ds.srelplt->size += sizeof (Elf32_External_Rela);
- return ret;
- }
- #define PLT_DO_RELOCS_FOR_ENTRY(DS, RELOCS) \
- plt_do_relocs_for_symbol (DS, RELOCS, 0, 0)
- static void
- plt_do_relocs_for_symbol (struct dynamic_sections *ds,
- struct plt_reloc *reloc,
- bfd_vma plt_offset,
- bfd_vma symbol_got_offset)
- {
- while (SYM_ONLY (reloc->symbol) != LAST_RELOC)
- {
- bfd_vma relocation = 0;
- switch (SYM_ONLY (reloc->symbol))
- {
- case SGOT:
- relocation =
- ds->sgotplt->output_section->vma +
- ds->sgotplt->output_offset + symbol_got_offset;
- break;
- }
- relocation += reloc->addend;
- relocation -= (IS_RELATIVE (reloc->symbol))
- ? ds->splt->output_section->vma + ds->splt->output_offset +
- plt_offset + reloc->offset : 0;
- if (IS_MIDDLE_ENDIAN (reloc->symbol))
- {
- relocation =
- ((relocation & 0xffff0000) >> 16) |
- ((relocation & 0xffff) << 16);
- }
- switch (reloc->size)
- {
- case 32:
- bfd_put_32 (ds->splt->output_section->owner,
- relocation,
- ds->splt->contents + plt_offset + reloc->offset);
- break;
- }
- reloc = &(reloc[1]); /* Jump to next relocation. */
- }
- }
- static void
- relocate_plt_for_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *h)
- {
- bfd * dynobj = elf_hash_table (info)->dynobj;
- struct plt_version_t *plt_data = arc_get_plt_version ();
- struct dynamic_sections ds = arc_create_dynamic_sections (dynobj, info);
- bfd_vma plt_index = h->plt.offset / plt_data->elem_size;
- bfd_vma got_offset = (plt_index + 3) * 4;
- memcpy (ds.splt->contents + h->plt.offset, plt_data->elem,
- plt_data->elem_size * sizeof (insn_hword));
- plt_do_relocs_for_symbol (&ds, plt_data->elem_relocs, h->plt.offset,
- got_offset);
- }
- static void
- relocate_plt_for_entry (struct bfd_link_info *info)
- {
- bfd * dynobj = (elf_hash_table (info))->dynobj;
- struct plt_version_t *plt_data = arc_get_plt_version ();
- struct dynamic_sections ds = arc_create_dynamic_sections (dynobj, info);
- memcpy (ds.splt->contents, plt_data->entry,
- plt_data->entry_size * sizeof (insn_hword));
- PLT_DO_RELOCS_FOR_ENTRY (&ds, plt_data->entry_relocs);
- }
- /* Desc : Adjust a symbol defined by a dynamic object and referenced by a
- regular object. The current definition is in some section of the
- dynamic object, but we're not including those sections. We have to
- change the definition to something the rest of the link can
- understand. */
- static bfd_boolean
- elf_arc_adjust_dynamic_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *h)
- {
- bfd *dynobj = (elf_hash_table (info))->dynobj;
- struct dynamic_sections ds = arc_create_dynamic_sections (dynobj, info);
- if (h->needs_plt == 1)
- {
- if (!bfd_link_pic (info) && !h->def_dynamic && !h->ref_dynamic)
- {
- /* This case can occur if we saw a PLT32 reloc in an input
- file, but the symbol was never referred to by a dynamic
- object. In such a case, we don't actually need to build
- a procedure linkage table, and we can just do a PC32
- reloc instead. */
- BFD_ASSERT (h->needs_plt);
- return TRUE;
- }
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1 && !h->forced_local
- && !bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- if (bfd_link_pic (info) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
- {
- bfd_vma loc = add_symbol_to_plt (info);
- if (!bfd_link_pic (info) && !h->def_regular)
- {
- h->root.u.def.section = ds.splt;
- h->root.u.def.value = loc;
- }
- h->plt.offset = loc;
- }
- }
- else
- {
- h->plt.offset = (bfd_vma) - 1;
- h->needs_plt = 0;
- }
- return TRUE;
- }
- #define ADD_RELA(BFD, SECTION, OFFSET, SYM_IDX, TYPE, ADDEND) \
- {\
- struct dynamic_sections ds = arc_create_dynamic_sections (output_bfd, info); \
- bfd_byte * rloc = ds.srel##SECTION->contents + \
- ((ds.srel##SECTION->reloc_count++) * sizeof (Elf32_External_Rela)); \
- Elf_Internal_Rela rel; \
- bfd_put_32 (output_bfd, (bfd_vma) 0, ds.s##SECTION->contents + OFFSET); \
- rel.r_addend = ADDEND; \
- rel.r_offset = (ds.s##SECTION)->output_section->vma + (ds.s##SECTION)->output_offset + OFFSET; \
- rel.r_info = ELF32_R_INFO (SYM_IDX, TYPE); \
- bfd_elf32_swap_reloca_out (BFD, &rel, rloc); \
- }
- /* Function : elf_arc_finish_dynamic_symbol
- Brief : Finish up dynamic symbol handling. We set the
- contents of various dynamic sections here.
- Args : output_bfd :
- info :
- h :
- sym :
- Returns : True/False as the return status. */
- static bfd_boolean
- elf_arc_finish_dynamic_symbol (bfd * output_bfd,
- struct bfd_link_info *info,
- struct elf_link_hash_entry *h,
- Elf_Internal_Sym * sym)
- {
- if (h->plt.offset != (bfd_vma) - 1)
- relocate_plt_for_symbol (info, h);
- if (h->got.offset != (bfd_vma) - 1)
- {
- if (bfd_link_pic (info) && (info->symbolic || h->dynindx == -1)
- && h->def_regular)
- {
- ADD_RELA (output_bfd, got, h->got.offset, 0, R_ARC_RELATIVE, 0);
- }
- else
- {
- ADD_RELA (output_bfd, got, h->got.offset, h->dynindx,
- R_ARC_GLOB_DAT, 0);
- }
- }
- /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "__DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
- sym->st_shndx = SHN_ABS;
- return TRUE;
- }
- #define GET_SYMBOL_OR_SECTION(TAG, SYMBOL, SECTION) \
- case TAG: \
- if (SYMBOL != NULL) \
- { \
- h = elf_link_hash_lookup (elf_hash_table (info), SYMBOL, FALSE, FALSE, TRUE); \
- } \
- else if (SECTION != NULL) \
- { \
- s = bfd_get_section_by_name (output_bfd, SECTION); \
- BFD_ASSERT (s != NULL); \
- do_it = TRUE; \
- } \
- break;
- /* Function : elf_arc_finish_dynamic_sections
- Brief : Finish up the dynamic sections handling.
- Args : output_bfd :
- info :
- h :
- sym :
- Returns : True/False as the return status. */
- static bfd_boolean
- elf_arc_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info *info)
- {
- struct dynamic_sections ds = arc_create_dynamic_sections (output_bfd, info);
- bfd *dynobj = (elf_hash_table (info))->dynobj;
- if (ds.sdyn)
- {
- Elf32_External_Dyn *dyncon, *dynconend;
- dyncon = (Elf32_External_Dyn *) ds.sdyn->contents;
- dynconend =
- (Elf32_External_Dyn *) (ds.sdyn->contents + ds.sdyn->size);
- for (; dyncon < dynconend; dyncon++)
- {
- Elf_Internal_Dyn internal_dyn;
- bfd_boolean do_it = FALSE;
- struct elf_link_hash_entry *h = NULL;
- asection *s = NULL;
- bfd_elf32_swap_dyn_in (dynobj, dyncon, &internal_dyn);
- switch (internal_dyn.d_tag)
- {
- GET_SYMBOL_OR_SECTION (DT_INIT, "_init", NULL)
- GET_SYMBOL_OR_SECTION (DT_FINI, "_fini", NULL)
- GET_SYMBOL_OR_SECTION (DT_PLTGOT, NULL, ".plt")
- GET_SYMBOL_OR_SECTION (DT_JMPREL, NULL, ".rela.plt")
- GET_SYMBOL_OR_SECTION (DT_PLTRELSZ, NULL, ".rela.plt")
- GET_SYMBOL_OR_SECTION (DT_RELASZ, NULL, ".rela.plt")
- default:
- break;
- }
- /* In case the dynamic symbols should be updated with a
- symbol. */
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- )
- {
- asection *asec_ptr;
- internal_dyn.d_un.d_val = h->root.u.def.value;
- asec_ptr = h->root.u.def.section;
- if (asec_ptr->output_section != NULL)
- {
- internal_dyn.d_un.d_val +=
- (asec_ptr->output_section->vma +
- asec_ptr->output_offset);
- }
- else
- {
- /* The symbol is imported from another
- shared library and does not apply to this
- one. */
- internal_dyn.d_un.d_val = 0;
- }
- do_it = TRUE;
- }
- else if (s != NULL) /* With a section information. */
- {
- switch (internal_dyn.d_tag)
- {
- case DT_PLTGOT:
- case DT_JMPREL:
- internal_dyn.d_un.d_ptr = s->vma;
- do_it = TRUE;
- break;
- case DT_PLTRELSZ:
- internal_dyn.d_un.d_val = s->size;
- do_it = TRUE;
- break;
- case DT_RELASZ:
- internal_dyn.d_un.d_val -= s->size;
- do_it = TRUE;
- break;
- default:
- break;
- }
- }
- if (do_it == TRUE)
- bfd_elf32_swap_dyn_out (output_bfd, &internal_dyn, dyncon);
- }
- if (ds.splt->size > 0)
- {
- relocate_plt_for_entry (info);
- }
- elf_section_data (ds.srelplt->output_section)->this_hdr.sh_entsize = 0xc;
- }
- /* Fill in the first three entries in the global offset table. */
- if (ds.sgot)
- {
- if (ds.sgot->size > 0)
- {
- if (ds.sdyn == NULL)
- bfd_put_32 (output_bfd, (bfd_vma) 0,
- ds.sgotplt->contents);
- else
- bfd_put_32 (output_bfd,
- ds.sdyn->output_section->vma + ds.sdyn->output_offset,
- ds.sgotplt->contents);
- bfd_put_32 (output_bfd, (bfd_vma) 0, ds.sgotplt->contents + 4);
- bfd_put_32 (output_bfd, (bfd_vma) 0, ds.sgotplt->contents + 8);
- elf_section_data (ds.sgot->output_section)->this_hdr.sh_entsize = 4;
- }
- }
- if (ds.srelgot
- /* Check that the linker script has not dumped the .srelgot section. */
- && ds.srelgot->output_section
- && elf_section_data (ds.srelgot->output_section))
- {
- /* TODO: Make it work even if I remove this. */
- elf_section_data (ds.srelgot->output_section)->this_hdr.sh_entsize = 0xc;
- }
- return TRUE;
- }
- #define ADD_DYNAMIC_SYMBOL(NAME, TAG) \
- h = elf_link_hash_lookup (elf_hash_table (info), NAME, FALSE, FALSE, FALSE); \
- if ((h != NULL && (h->ref_regular || h->def_regular))) \
- if (! _bfd_elf_add_dynamic_entry (info, TAG, 0)) \
- return FALSE;
- /* Set the sizes of the dynamic sections. */
- static bfd_boolean
- elf_arc_size_dynamic_sections (bfd * output_bfd, struct bfd_link_info *info)
- {
- bfd * dynobj;
- asection * s;
- bfd_boolean relocs_exist;
- bfd_boolean reltext_exist;
- struct dynamic_sections ds = arc_create_dynamic_sections (output_bfd, info);
- dynobj = (elf_hash_table (info))->dynobj;
- BFD_ASSERT (dynobj != NULL);
- if ((elf_hash_table (info))->dynamic_sections_created)
- {
- struct elf_link_hash_entry *h;
- /* Set the contents of the .interp section to the interpreter. */
- if (!bfd_link_pic (info))
- {
- s = bfd_get_section_by_name (dynobj, ".interp");
- BFD_ASSERT (s != NULL);
- s->size = sizeof ELF_DYNAMIC_INTERPRETER;
- s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
- }
- /* Add some entries to the .dynamic section. We fill in some of the
- values later, in elf_bfd_final_link, but we must add the entries
- now so that we know the final size of the .dynamic section.
- Checking if the .init section is present. We also create DT_INIT
- and DT_FINI entries if the init_str has been changed by the user. */
- ADD_DYNAMIC_SYMBOL ("init", DT_INIT);
- ADD_DYNAMIC_SYMBOL ("fini", DT_FINI);
- }
- else
- {
- /* We may have created entries in the .rela.got section. However, if
- we are not creating the dynamic sections, we will not actually
- use these entries. Reset the size of .rela.got, which will cause
- it to get stripped from the output file below. */
- ds.srelgot->size = 0;
- }
- for (s = dynobj->sections; s != NULL; s = s->next)
- {
- bfd_boolean is_dynamic_section = FALSE;
- /* Skip any non dynamic section. */
- if (strstr (s->name, ".plt") != NULL
- || strstr (s->name, ".got") != NULL
- || strstr (s->name, ".rel") != NULL)
- is_dynamic_section = TRUE;
- /* Allocate memory for the section contents. */
- if (!is_dynamic_section)
- continue;
- s->contents = (bfd_byte *) bfd_alloc (dynobj, s->size);
- if (s->contents == NULL && s->size != 0)
- return FALSE;
- if (s->size == 0)
- {
- s->flags |= SEC_EXCLUDE;
- continue;
- }
- if (strcmp (s->name, ".rela.plt") != 0)
- {
- const char *outname = bfd_get_section_name (output_bfd,
- s->output_section);
- asection *target = bfd_get_section_by_name (output_bfd,
- outname + 4);
- relocs_exist = TRUE;
- if (target != NULL && target->size != 0
- && (target->flags & SEC_READONLY) != 0
- && (target->flags & SEC_ALLOC) != 0)
- reltext_exist = TRUE;
- }
- }
- if (ds.sdyn)
- {
- if (ds.splt && ds.splt->size != 0)
- if (!_bfd_elf_add_dynamic_entry (info, DT_PLTGOT, 0)
- || !_bfd_elf_add_dynamic_entry (info, DT_PLTRELSZ, 0)
- || !_bfd_elf_add_dynamic_entry (info, DT_PLTREL, DT_RELA)
- || !_bfd_elf_add_dynamic_entry (info, DT_JMPREL, 0)
- )
- return FALSE;
- if (relocs_exist == TRUE)
- if (!_bfd_elf_add_dynamic_entry (info, DT_RELA, 0)
- || !_bfd_elf_add_dynamic_entry (info, DT_RELASZ, 0)
- || !_bfd_elf_add_dynamic_entry (info, DT_RELENT,
- sizeof (Elf32_External_Rela))
- )
- return FALSE;
- if (reltext_exist == TRUE)
- if (!_bfd_elf_add_dynamic_entry (info, DT_TEXTREL, 0))
- return FALSE;
- }
- return TRUE;
- }
- #define TARGET_LITTLE_SYM arc_elf32_le_vec
- #define TARGET_LITTLE_NAME "elf32-littlearc"
- #define TARGET_BIG_SYM arc_elf32_be_vec
- #define TARGET_BIG_NAME "elf32-bigarc"
- #define ELF_ARCH bfd_arch_arc
- #define ELF_MACHINE_CODE EM_ARC_COMPACT
- #define ELF_MACHINE_ALT1 EM_ARC_COMPACT2
- #define ELF_MAXPAGESIZE 0x2000
- #define elf_info_to_howto_rel arc_info_to_howto_rel
- #define elf_backend_object_p arc_elf_object_p
- #define elf_backend_final_write_processing arc_elf_final_write_processing
- #define elf_backend_relocate_section elf_arc_relocate_section
- #define elf_backend_check_relocs elf_arc_check_relocs
- #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections
- #define elf_backend_adjust_dynamic_symbol elf_arc_adjust_dynamic_symbol
- #define elf_backend_finish_dynamic_symbol elf_arc_finish_dynamic_symbol
- #define elf_backend_finish_dynamic_sections elf_arc_finish_dynamic_sections
- #define elf_backend_size_dynamic_sections elf_arc_size_dynamic_sections
- #define elf_backend_can_gc_sections 1
- #define elf_backend_want_got_plt 1
- #define elf_backend_plt_readonly 1
- #define elf_backend_want_plt_sym 0
- #define elf_backend_got_header_size 12
- #define elf_backend_may_use_rel_p 0
- #define elf_backend_may_use_rela_p 1
- #define elf_backend_default_use_rela_p 1
- #include "elf32-target.h"
|