123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483 |
- /* Xilinx MicroBlaze-specific support for 32-bit ELF
- Copyright (C) 2009-2022 Free Software Foundation, Inc.
- 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 "bfdlink.h"
- #include "libbfd.h"
- #include "elf-bfd.h"
- #include "elf/microblaze.h"
- #include <assert.h>
- #define USE_RELA /* Only USE_REL is actually significant, but this is
- here are a reminder... */
- #define INST_WORD_SIZE 4
- static int ro_small_data_pointer = 0;
- static int rw_small_data_pointer = 0;
- static reloc_howto_type * microblaze_elf_howto_table [(int) R_MICROBLAZE_max];
- static reloc_howto_type microblaze_elf_howto_raw[] =
- {
- /* This reloc does nothing. */
- HOWTO (R_MICROBLAZE_NONE, /* Type. */
- 0, /* Rightshift. */
- 3, /* Size (0 = byte, 1 = short, 2 = long). */
- 0, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- NULL, /* Special Function. */
- "R_MICROBLAZE_NONE", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A standard 32 bit relocation. */
- HOWTO (R_MICROBLAZE_32, /* 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_MICROBLAZE_32", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0xffffffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A standard PCREL 32 bit relocation. */
- HOWTO (R_MICROBLAZE_32_PCREL,/* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 32, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_bitfield, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_32_PCREL", /* Name. */
- true, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0xffffffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* A 64 bit PCREL relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_64_PCREL,/* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_64_PCREL", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* The low half of a PCREL 32 bit relocation. */
- HOWTO (R_MICROBLAZE_32_PCREL_LO, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_signed, /* Complain on overflow. */
- bfd_elf_generic_reloc, /* Special Function. */
- "R_MICROBLAZE_32_PCREL_LO", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* A 64 bit relocation. Table entry not really used. */
- HOWTO (R_MICROBLAZE_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_64", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* The low half of a 32 bit relocation. */
- HOWTO (R_MICROBLAZE_32_LO, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_signed, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_32_LO", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* Read-only small data section relocation. */
- HOWTO (R_MICROBLAZE_SRO32, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_bitfield, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_SRO32", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* Read-write small data area relocation. */
- HOWTO (R_MICROBLAZE_SRW32, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_bitfield, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_SRW32", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* This reloc does nothing. Used for relaxation. */
- HOWTO (R_MICROBLAZE_64_NONE, /* Type. */
- 0, /* Rightshift. */
- 3, /* Size (0 = byte, 1 = short, 2 = long). */
- 0, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- NULL, /* Special Function. */
- "R_MICROBLAZE_64_NONE",/* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0, /* Dest Mask. */
- false), /* PC relative offset? */
- /* Symbol Op Symbol relocation. */
- HOWTO (R_MICROBLAZE_32_SYM_OP_SYM, /* 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_MICROBLAZE_32_SYM_OP_SYM", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0xffffffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* GNU extension to record C++ vtable hierarchy. */
- HOWTO (R_MICROBLAZE_GNU_VTINHERIT, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 0, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont,/* Complain on overflow. */
- NULL, /* Special Function. */
- "R_MICROBLAZE_GNU_VTINHERIT", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0, /* Dest Mask. */
- false), /* PC relative offset? */
- /* GNU extension to record C++ vtable member usage. */
- HOWTO (R_MICROBLAZE_GNU_VTENTRY, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 0, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont,/* Complain on overflow. */
- _bfd_elf_rel_vtable_reloc_fn, /* Special Function. */
- "R_MICROBLAZE_GNU_VTENTRY", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A 64 bit GOTPC relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_GOTPC_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc, /* Special Function. */
- "R_MICROBLAZE_GOTPC_64", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* A 64 bit TEXTPCREL relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_TEXTPCREL_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc, /* Special Function. */
- "R_MICROBLAZE_TEXTPCREL_64", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* A 64 bit GOT relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_GOT_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_GOT_64",/* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A 64 bit TEXTREL relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_TEXTREL_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_TEXTREL_64",/* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A 64 bit PLT relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_PLT_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_PLT_64",/* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* Table-entry not really used. */
- HOWTO (R_MICROBLAZE_REL, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_REL", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* Table-entry not really used. */
- HOWTO (R_MICROBLAZE_JUMP_SLOT,/* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_JUMP_SLOT", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* Table-entry not really used. */
- HOWTO (R_MICROBLAZE_GLOB_DAT,/* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- true, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_GLOB_DAT", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- true), /* PC relative offset? */
- /* A 64 bit GOT relative relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_GOTOFF_64, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_GOTOFF_64", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* A 32 bit GOT relative relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_GOTOFF_32, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc, /* Special Function. */
- "R_MICROBLAZE_GOTOFF_32", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* COPY relocation. Table-entry not really used. */
- HOWTO (R_MICROBLAZE_COPY, /* Type. */
- 0, /* Rightshift. */
- 2, /* Size (0 = byte, 1 = short, 2 = long). */
- 16, /* Bitsize. */
- false, /* PC_relative. */
- 0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
- bfd_elf_generic_reloc,/* Special Function. */
- "R_MICROBLAZE_COPY", /* Name. */
- false, /* Partial Inplace. */
- 0, /* Source Mask. */
- 0x0000ffff, /* Dest Mask. */
- false), /* PC relative offset? */
- /* Marker relocs for TLS. */
- HOWTO (R_MICROBLAZE_TLS,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLS", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_MICROBLAZE_TLSGD,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSGD", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_MICROBLAZE_TLSLD,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSLD", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Computes the load module index of the load module that contains the
- definition of its TLS sym. */
- HOWTO (R_MICROBLAZE_TLSDTPMOD32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSDTPMOD32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Computes a dtv-relative displacement, the difference between the value
- of sym+add and the base address of the thread-local storage block that
- contains the definition of sym, minus 0x8000. Used for initializing GOT */
- HOWTO (R_MICROBLAZE_TLSDTPREL32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSDTPREL32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Computes a dtv-relative displacement, the difference between the value
- of sym+add and the base address of the thread-local storage block that
- contains the definition of sym, minus 0x8000. */
- HOWTO (R_MICROBLAZE_TLSDTPREL64,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSDTPREL64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Computes a tp-relative displacement, the difference between the value of
- sym+add and the value of the thread pointer (r13). */
- HOWTO (R_MICROBLAZE_TLSGOTTPREL32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSGOTTPREL32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Computes a tp-relative displacement, the difference between the value of
- sym+add and the value of the thread pointer (r13). */
- HOWTO (R_MICROBLAZE_TLSTPREL32,
- 0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_MICROBLAZE_TLSTPREL32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x0000ffff, /* dst_mask */
- false), /* pcrel_offset */
- };
- #ifndef NUM_ELEM
- #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
- #endif
- /* Initialize the microblaze_elf_howto_table, so that linear accesses can be done. */
- static void
- microblaze_elf_howto_init (void)
- {
- unsigned int i;
- for (i = NUM_ELEM (microblaze_elf_howto_raw); i--;)
- {
- unsigned int type;
- type = microblaze_elf_howto_raw[i].type;
- BFD_ASSERT (type < NUM_ELEM (microblaze_elf_howto_table));
- microblaze_elf_howto_table [type] = & microblaze_elf_howto_raw [i];
- }
- }
- static reloc_howto_type *
- microblaze_elf_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
- bfd_reloc_code_real_type code)
- {
- enum elf_microblaze_reloc_type microblaze_reloc = R_MICROBLAZE_NONE;
- switch (code)
- {
- case BFD_RELOC_NONE:
- microblaze_reloc = R_MICROBLAZE_NONE;
- break;
- case BFD_RELOC_MICROBLAZE_64_NONE:
- microblaze_reloc = R_MICROBLAZE_64_NONE;
- break;
- case BFD_RELOC_32:
- microblaze_reloc = R_MICROBLAZE_32;
- break;
- /* RVA is treated the same as 32 */
- case BFD_RELOC_RVA:
- microblaze_reloc = R_MICROBLAZE_32;
- break;
- case BFD_RELOC_32_PCREL:
- microblaze_reloc = R_MICROBLAZE_32_PCREL;
- break;
- case BFD_RELOC_64_PCREL:
- microblaze_reloc = R_MICROBLAZE_64_PCREL;
- break;
- case BFD_RELOC_MICROBLAZE_32_LO_PCREL:
- microblaze_reloc = R_MICROBLAZE_32_PCREL_LO;
- break;
- case BFD_RELOC_64:
- microblaze_reloc = R_MICROBLAZE_64;
- break;
- case BFD_RELOC_MICROBLAZE_32_LO:
- microblaze_reloc = R_MICROBLAZE_32_LO;
- break;
- case BFD_RELOC_MICROBLAZE_32_ROSDA:
- microblaze_reloc = R_MICROBLAZE_SRO32;
- break;
- case BFD_RELOC_MICROBLAZE_32_RWSDA:
- microblaze_reloc = R_MICROBLAZE_SRW32;
- break;
- case BFD_RELOC_MICROBLAZE_32_SYM_OP_SYM:
- microblaze_reloc = R_MICROBLAZE_32_SYM_OP_SYM;
- break;
- case BFD_RELOC_VTABLE_INHERIT:
- microblaze_reloc = R_MICROBLAZE_GNU_VTINHERIT;
- break;
- case BFD_RELOC_VTABLE_ENTRY:
- microblaze_reloc = R_MICROBLAZE_GNU_VTENTRY;
- break;
- case BFD_RELOC_MICROBLAZE_64_GOTPC:
- microblaze_reloc = R_MICROBLAZE_GOTPC_64;
- break;
- case BFD_RELOC_MICROBLAZE_64_GOT:
- microblaze_reloc = R_MICROBLAZE_GOT_64;
- break;
- case BFD_RELOC_MICROBLAZE_64_TEXTPCREL:
- microblaze_reloc = R_MICROBLAZE_TEXTPCREL_64;
- break;
- case BFD_RELOC_MICROBLAZE_64_TEXTREL:
- microblaze_reloc = R_MICROBLAZE_TEXTREL_64;
- break;
- case BFD_RELOC_MICROBLAZE_64_PLT:
- microblaze_reloc = R_MICROBLAZE_PLT_64;
- break;
- case BFD_RELOC_MICROBLAZE_64_GOTOFF:
- microblaze_reloc = R_MICROBLAZE_GOTOFF_64;
- break;
- case BFD_RELOC_MICROBLAZE_32_GOTOFF:
- microblaze_reloc = R_MICROBLAZE_GOTOFF_32;
- break;
- case BFD_RELOC_MICROBLAZE_64_TLSGD:
- microblaze_reloc = R_MICROBLAZE_TLSGD;
- break;
- case BFD_RELOC_MICROBLAZE_64_TLSLD:
- microblaze_reloc = R_MICROBLAZE_TLSLD;
- break;
- case BFD_RELOC_MICROBLAZE_32_TLSDTPREL:
- microblaze_reloc = R_MICROBLAZE_TLSDTPREL32;
- break;
- case BFD_RELOC_MICROBLAZE_64_TLSDTPREL:
- microblaze_reloc = R_MICROBLAZE_TLSDTPREL64;
- break;
- case BFD_RELOC_MICROBLAZE_32_TLSDTPMOD:
- microblaze_reloc = R_MICROBLAZE_TLSDTPMOD32;
- break;
- case BFD_RELOC_MICROBLAZE_64_TLSGOTTPREL:
- microblaze_reloc = R_MICROBLAZE_TLSGOTTPREL32;
- break;
- case BFD_RELOC_MICROBLAZE_64_TLSTPREL:
- microblaze_reloc = R_MICROBLAZE_TLSTPREL32;
- break;
- case BFD_RELOC_MICROBLAZE_COPY:
- microblaze_reloc = R_MICROBLAZE_COPY;
- break;
- default:
- return (reloc_howto_type *) NULL;
- }
- if (!microblaze_elf_howto_table [R_MICROBLAZE_32])
- /* Initialize howto table if needed. */
- microblaze_elf_howto_init ();
- return microblaze_elf_howto_table [(int) microblaze_reloc];
- };
- static reloc_howto_type *
- microblaze_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
- const char *r_name)
- {
- unsigned int i;
- for (i = 0; i < NUM_ELEM (microblaze_elf_howto_raw); i++)
- if (microblaze_elf_howto_raw[i].name != NULL
- && strcasecmp (microblaze_elf_howto_raw[i].name, r_name) == 0)
- return µblaze_elf_howto_raw[i];
- return NULL;
- }
- /* Set the howto pointer for a RCE ELF reloc. */
- static bool
- microblaze_elf_info_to_howto (bfd * abfd,
- arelent * cache_ptr,
- Elf_Internal_Rela * dst)
- {
- unsigned int r_type;
- if (!microblaze_elf_howto_table [R_MICROBLAZE_32])
- /* Initialize howto table if needed. */
- microblaze_elf_howto_init ();
- r_type = ELF32_R_TYPE (dst->r_info);
- if (r_type >= R_MICROBLAZE_max)
- {
- /* xgettext:c-format */
- _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
- abfd, r_type);
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- cache_ptr->howto = microblaze_elf_howto_table [r_type];
- return true;
- }
- /* Relax table contains information about instructions which can
- be removed by relaxation -- replacing a long address with a
- short address. */
- struct relax_table
- {
- /* Address where bytes may be deleted. */
- bfd_vma addr;
- /* Number of bytes to be deleted. */
- size_t size;
- };
- struct _microblaze_elf_section_data
- {
- struct bfd_elf_section_data elf;
- /* Count of used relaxation table entries. */
- size_t relax_count;
- /* Relaxation table. */
- struct relax_table *relax;
- };
- #define microblaze_elf_section_data(sec) \
- ((struct _microblaze_elf_section_data *) elf_section_data (sec))
- static bool
- microblaze_elf_new_section_hook (bfd *abfd, asection *sec)
- {
- if (!sec->used_by_bfd)
- {
- struct _microblaze_elf_section_data *sdata;
- size_t amt = sizeof (*sdata);
- sdata = bfd_zalloc (abfd, amt);
- if (sdata == NULL)
- return false;
- sec->used_by_bfd = sdata;
- }
- return _bfd_elf_new_section_hook (abfd, sec);
- }
- /* Microblaze ELF local labels start with 'L.' or '$L', not '.L'. */
- static bool
- microblaze_elf_is_local_label_name (bfd *abfd, const char *name)
- {
- if (name[0] == 'L' && name[1] == '.')
- return true;
- if (name[0] == '$' && name[1] == 'L')
- return true;
- /* With gcc, the labels go back to starting with '.', so we accept
- the generic ELF local label syntax as well. */
- return _bfd_elf_is_local_label_name (abfd, name);
- }
- /* ELF linker hash entry. */
- struct elf32_mb_link_hash_entry
- {
- struct elf_link_hash_entry elf;
- /* TLS Reference Types for the symbol; Updated by check_relocs */
- #define TLS_GD 1 /* GD reloc. */
- #define TLS_LD 2 /* LD reloc. */
- #define TLS_TPREL 4 /* TPREL reloc, => IE. */
- #define TLS_DTPREL 8 /* DTPREL reloc, => LD. */
- #define TLS_TLS 16 /* Any TLS reloc. */
- unsigned char tls_mask;
- };
- #define IS_TLS_GD(x) (x == (TLS_TLS | TLS_GD))
- #define IS_TLS_LD(x) (x == (TLS_TLS | TLS_LD))
- #define IS_TLS_DTPREL(x) (x == (TLS_TLS | TLS_DTPREL))
- #define IS_TLS_NONE(x) (x == 0)
- #define elf32_mb_hash_entry(ent) ((struct elf32_mb_link_hash_entry *)(ent))
- /* ELF linker hash table. */
- struct elf32_mb_link_hash_table
- {
- struct elf_link_hash_table elf;
- /* TLS Local Dynamic GOT Entry */
- union {
- bfd_signed_vma refcount;
- bfd_vma offset;
- } tlsld_got;
- };
- /* Nonzero if this section has TLS related relocations. */
- #define has_tls_reloc sec_flg0
- /* Get the ELF linker hash table from a link_info structure. */
- #define elf32_mb_hash_table(p) \
- ((is_elf_hash_table ((p)->hash) \
- && elf_hash_table_id (elf_hash_table (p)) == MICROBLAZE_ELF_DATA) \
- ? (struct elf32_mb_link_hash_table *) (p)->hash : NULL)
- /* Create an entry in a microblaze ELF linker hash table. */
- static struct bfd_hash_entry *
- link_hash_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table,
- const char *string)
- {
- /* Allocate the structure if it has not already been allocated by a
- subclass. */
- if (entry == NULL)
- {
- entry = bfd_hash_allocate (table,
- sizeof (struct elf32_mb_link_hash_entry));
- if (entry == NULL)
- return entry;
- }
- /* Call the allocation method of the superclass. */
- entry = _bfd_elf_link_hash_newfunc (entry, table, string);
- if (entry != NULL)
- {
- struct elf32_mb_link_hash_entry *eh;
- eh = (struct elf32_mb_link_hash_entry *) entry;
- eh->tls_mask = 0;
- }
- return entry;
- }
- /* Create a mb ELF linker hash table. */
- static struct bfd_link_hash_table *
- microblaze_elf_link_hash_table_create (bfd *abfd)
- {
- struct elf32_mb_link_hash_table *ret;
- size_t amt = sizeof (struct elf32_mb_link_hash_table);
- ret = (struct elf32_mb_link_hash_table *) bfd_zmalloc (amt);
- if (ret == NULL)
- return NULL;
- if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc,
- sizeof (struct elf32_mb_link_hash_entry),
- MICROBLAZE_ELF_DATA))
- {
- free (ret);
- return NULL;
- }
- return &ret->elf.root;
- }
- /* Set the values of the small data pointers. */
- static void
- microblaze_elf_final_sdp (struct bfd_link_info *info)
- {
- struct bfd_link_hash_entry *h;
- h = bfd_link_hash_lookup (info->hash, RO_SDA_ANCHOR_NAME, false, false, true);
- if (h != (struct bfd_link_hash_entry *) NULL
- && h->type == bfd_link_hash_defined)
- ro_small_data_pointer = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
- h = bfd_link_hash_lookup (info->hash, RW_SDA_ANCHOR_NAME, false, false, true);
- if (h != (struct bfd_link_hash_entry *) NULL
- && h->type == bfd_link_hash_defined)
- rw_small_data_pointer = (h->u.def.value
- + h->u.def.section->output_section->vma
- + h->u.def.section->output_offset);
- }
- static bfd_vma
- dtprel_base (struct bfd_link_info *info)
- {
- /* If tls_sec is NULL, we should have signalled an error already. */
- if (elf_hash_table (info)->tls_sec == NULL)
- return 0;
- return elf_hash_table (info)->tls_sec->vma;
- }
- /* The size of the thread control block. */
- #define TCB_SIZE 8
- /* Output a simple dynamic relocation into SRELOC. */
- static void
- microblaze_elf_output_dynamic_relocation (bfd *output_bfd,
- asection *sreloc,
- unsigned long reloc_index,
- unsigned long indx,
- int r_type,
- bfd_vma offset,
- bfd_vma addend)
- {
- Elf_Internal_Rela rel;
- rel.r_info = ELF32_R_INFO (indx, r_type);
- rel.r_offset = offset;
- rel.r_addend = addend;
- bfd_elf32_swap_reloca_out (output_bfd, &rel,
- (sreloc->contents + reloc_index * sizeof (Elf32_External_Rela)));
- }
- /* This code is taken from elf32-m32r.c
- There is some attempt to make this function usable for many architectures,
- both USE_REL and USE_RELA ['twould be nice if such a critter existed],
- if only to serve as a learning tool.
- The RELOCATE_SECTION function is called by the new ELF backend linker
- to handle the relocations for a section.
- The relocs are always passed as Rela structures; if the section
- actually uses Rel structures, the r_addend field will always be
- zero.
- This function is responsible for adjust the section contents as
- necessary, and (if using Rela relocs and generating a
- relocatable output file) adjusting the reloc addend as
- necessary.
- This function does not have to worry about setting the reloc
- address or the reloc symbol index.
- LOCAL_SYMS is a pointer to the swapped in local symbols.
- LOCAL_SECTIONS is an array giving the section in the input file
- corresponding to the st_shndx field of each local symbol.
- The global hash table entry for the global symbols can be found
- via elf_sym_hashes (input_bfd).
- When generating relocatable output, this function must handle
- STB_LOCAL/STT_SECTION symbols specially. The output symbol is
- going to be the section symbol corresponding to the output
- section, which means that the addend must be adjusted
- accordingly. */
- static int
- microblaze_elf_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)
- {
- struct elf32_mb_link_hash_table *htab;
- Elf_Internal_Shdr *symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
- struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
- Elf_Internal_Rela *rel, *relend;
- int endian = (bfd_little_endian (output_bfd)) ? 0 : 2;
- /* Assume success. */
- bool ret = true;
- asection *sreloc;
- bfd_vma *local_got_offsets;
- unsigned int tls_type;
- if (!microblaze_elf_howto_table[R_MICROBLAZE_max-1])
- microblaze_elf_howto_init ();
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- local_got_offsets = elf_local_got_offsets (input_bfd);
- sreloc = elf_section_data (input_section)->sreloc;
- rel = relocs;
- relend = relocs + input_section->reloc_count;
- for (; rel < relend; rel++)
- {
- int r_type;
- reloc_howto_type *howto;
- unsigned long r_symndx;
- bfd_vma addend = rel->r_addend;
- bfd_vma offset = rel->r_offset;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
- asection *sec;
- const char *sym_name;
- bfd_reloc_status_type r = bfd_reloc_ok;
- const char *errmsg = NULL;
- bool unresolved_reloc = false;
- h = NULL;
- r_type = ELF32_R_TYPE (rel->r_info);
- tls_type = 0;
- if (r_type < 0 || r_type >= (int) R_MICROBLAZE_max)
- {
- /* xgettext:c-format */
- _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
- input_bfd, (int) r_type);
- bfd_set_error (bfd_error_bad_value);
- ret = false;
- continue;
- }
- howto = microblaze_elf_howto_table[r_type];
- r_symndx = ELF32_R_SYM (rel->r_info);
- if (bfd_link_relocatable (info))
- {
- /* This is a relocatable link. We don't have to change
- anything, unless the reloc is against a section symbol,
- in which case we have to adjust according to where the
- section symbol winds up in the output section. */
- sec = NULL;
- if (r_symndx >= symtab_hdr->sh_info)
- /* External symbol. */
- continue;
- /* Local symbol. */
- sym = local_syms + r_symndx;
- sym_name = "<local symbol>";
- /* STT_SECTION: symbol is associated with a section. */
- if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
- /* Symbol isn't associated with a section. Nothing to do. */
- continue;
- sec = local_sections[r_symndx];
- addend += sec->output_offset + sym->st_value;
- #ifndef USE_REL
- /* This can't be done for USE_REL because it doesn't mean anything
- and elf_link_input_bfd asserts this stays zero. */
- /* rel->r_addend = addend; */
- #endif
- #ifndef USE_REL
- /* Addends are stored with relocs. We're done. */
- continue;
- #else /* USE_REL */
- /* If partial_inplace, we need to store any additional addend
- back in the section. */
- if (!howto->partial_inplace)
- continue;
- /* ??? Here is a nice place to call a special_function like handler. */
- r = _bfd_relocate_contents (howto, input_bfd, addend,
- contents + offset);
- #endif /* USE_REL */
- }
- else
- {
- bfd_vma relocation;
- bool resolved_to_zero;
- /* This is a final link. */
- sym = NULL;
- sec = NULL;
- unresolved_reloc = false;
- if (r_symndx < symtab_hdr->sh_info)
- {
- /* Local symbol. */
- sym = local_syms + r_symndx;
- sec = local_sections[r_symndx];
- if (sec == 0)
- continue;
- sym_name = "<local symbol>";
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
- /* r_addend may have changed if the reference section was
- a merge section. */
- addend = rel->r_addend;
- }
- else
- {
- /* External symbol. */
- bool warned ATTRIBUTE_UNUSED;
- bool ignored ATTRIBUTE_UNUSED;
- RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
- r_symndx, symtab_hdr, sym_hashes,
- h, sec, relocation,
- unresolved_reloc, warned, ignored);
- sym_name = h->root.root.string;
- }
- /* Sanity check the address. */
- if (offset > bfd_get_section_limit (input_bfd, input_section))
- {
- r = bfd_reloc_outofrange;
- goto check_reloc;
- }
- resolved_to_zero = (h != NULL
- && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
- switch ((int) r_type)
- {
- case (int) R_MICROBLAZE_SRO32 :
- {
- const char *name;
- /* Only relocate if the symbol is defined. */
- if (sec)
- {
- name = bfd_section_name (sec);
- if (strcmp (name, ".sdata2") == 0
- || strcmp (name, ".sbss2") == 0)
- {
- if (ro_small_data_pointer == 0)
- microblaze_elf_final_sdp (info);
- if (ro_small_data_pointer == 0)
- {
- ret = false;
- r = bfd_reloc_undefined;
- goto check_reloc;
- }
- /* At this point `relocation' contains the object's
- address. */
- relocation -= ro_small_data_pointer;
- /* Now it contains the offset from _SDA2_BASE_. */
- r = _bfd_final_link_relocate (howto, input_bfd,
- input_section,
- contents, offset,
- relocation, addend);
- }
- else
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: the target (%s) of an %s relocation"
- " is in the wrong section (%pA)"),
- input_bfd,
- sym_name,
- microblaze_elf_howto_table[(int) r_type]->name,
- sec);
- /*bfd_set_error (bfd_error_bad_value); ??? why? */
- ret = false;
- continue;
- }
- }
- }
- break;
- case (int) R_MICROBLAZE_SRW32 :
- {
- const char *name;
- /* Only relocate if the symbol is defined. */
- if (sec)
- {
- name = bfd_section_name (sec);
- if (strcmp (name, ".sdata") == 0
- || strcmp (name, ".sbss") == 0)
- {
- if (rw_small_data_pointer == 0)
- microblaze_elf_final_sdp (info);
- if (rw_small_data_pointer == 0)
- {
- ret = false;
- r = bfd_reloc_undefined;
- goto check_reloc;
- }
- /* At this point `relocation' contains the object's
- address. */
- relocation -= rw_small_data_pointer;
- /* Now it contains the offset from _SDA_BASE_. */
- r = _bfd_final_link_relocate (howto, input_bfd,
- input_section,
- contents, offset,
- relocation, addend);
- }
- else
- {
- _bfd_error_handler
- /* xgettext:c-format */
- (_("%pB: the target (%s) of an %s relocation"
- " is in the wrong section (%pA)"),
- input_bfd,
- sym_name,
- microblaze_elf_howto_table[(int) r_type]->name,
- sec);
- /*bfd_set_error (bfd_error_bad_value); ??? why? */
- ret = false;
- continue;
- }
- }
- }
- break;
- case (int) R_MICROBLAZE_32_SYM_OP_SYM:
- break; /* Do nothing. */
- case (int) R_MICROBLAZE_GOTPC_64:
- relocation = (htab->elf.sgotplt->output_section->vma
- + htab->elf.sgotplt->output_offset);
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- relocation += addend;
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- break;
- case (int) R_MICROBLAZE_TEXTPCREL_64:
- relocation = input_section->output_section->vma;
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- relocation += addend;
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- break;
- case (int) R_MICROBLAZE_PLT_64:
- {
- bfd_vma immediate;
- if (htab->elf.splt != NULL && h != NULL
- && h->plt.offset != (bfd_vma) -1)
- {
- relocation = (htab->elf.splt->output_section->vma
- + htab->elf.splt->output_offset
- + h->plt.offset);
- unresolved_reloc = false;
- immediate = relocation - (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, immediate & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- }
- else
- {
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- immediate = relocation;
- bfd_put_16 (input_bfd, (immediate >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, immediate & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- }
- break;
- }
- case (int) R_MICROBLAZE_TLSGD:
- tls_type = (TLS_TLS | TLS_GD);
- goto dogot;
- case (int) R_MICROBLAZE_TLSLD:
- tls_type = (TLS_TLS | TLS_LD);
- /* Fall through. */
- dogot:
- case (int) R_MICROBLAZE_GOT_64:
- {
- bfd_vma *offp;
- bfd_vma off, off2;
- unsigned long indx;
- bfd_vma static_value;
- bool need_relocs = false;
- if (htab->elf.sgot == NULL)
- abort ();
- indx = 0;
- offp = NULL;
- /* 1. Identify GOT Offset;
- 2. Compute Static Values
- 3. Process Module Id, Process Offset
- 4. Fixup Relocation with GOT offset value. */
- /* 1. Determine GOT Offset to use : TLS_LD, global, local */
- if (IS_TLS_LD (tls_type))
- offp = &htab->tlsld_got.offset;
- else if (h != NULL)
- {
- if (htab->elf.sgotplt != NULL
- && h->got.offset != (bfd_vma) -1)
- offp = &h->got.offset;
- else
- abort ();
- }
- else
- {
- if (local_got_offsets == NULL)
- abort ();
- offp = &local_got_offsets[r_symndx];
- }
- if (!offp)
- abort ();
- off = (*offp) & ~1;
- off2 = off;
- if (IS_TLS_LD(tls_type) || IS_TLS_GD(tls_type))
- off2 = off + 4;
- /* Symbol index to use for relocs */
- if (h != NULL)
- {
- bool dyn =
- elf_hash_table (info)->dynamic_sections_created;
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
- bfd_link_pic (info),
- h)
- && (!bfd_link_pic (info)
- || !SYMBOL_REFERENCES_LOCAL (info, h)))
- indx = h->dynindx;
- }
- /* Need to generate relocs ? */
- if ((bfd_link_pic (info) || indx != 0)
- && (h == NULL
- || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- && !resolved_to_zero)
- || h->root.type != bfd_link_hash_undefweak))
- need_relocs = true;
- /* 2. Compute/Emit Static value of r-expression */
- static_value = relocation + addend;
- /* 3. Process module-id and offset */
- if (! ((*offp) & 1) )
- {
- bfd_vma got_offset;
- got_offset = (htab->elf.sgot->output_section->vma
- + htab->elf.sgot->output_offset
- + off);
- /* Process module-id */
- if (IS_TLS_LD(tls_type))
- {
- if (! bfd_link_pic (info))
- bfd_put_32 (output_bfd, 1,
- htab->elf.sgot->contents + off);
- else
- microblaze_elf_output_dynamic_relocation
- (output_bfd,
- htab->elf.srelgot,
- htab->elf.srelgot->reloc_count++,
- /* symindex= */ 0, R_MICROBLAZE_TLSDTPMOD32,
- got_offset, 0);
- }
- else if (IS_TLS_GD(tls_type))
- {
- if (! need_relocs)
- bfd_put_32 (output_bfd, 1,
- htab->elf.sgot->contents + off);
- else
- microblaze_elf_output_dynamic_relocation
- (output_bfd,
- htab->elf.srelgot,
- htab->elf.srelgot->reloc_count++,
- /* symindex= */ indx, R_MICROBLAZE_TLSDTPMOD32,
- got_offset, indx ? 0 : static_value);
- }
- /* Process Offset */
- if (htab->elf.srelgot == NULL)
- abort ();
- got_offset = (htab->elf.sgot->output_section->vma
- + htab->elf.sgot->output_offset
- + off2);
- if (IS_TLS_LD(tls_type))
- {
- /* For LD, offset should be 0 */
- *offp |= 1;
- bfd_put_32 (output_bfd, 0,
- htab->elf.sgot->contents + off2);
- }
- else if (IS_TLS_GD(tls_type))
- {
- *offp |= 1;
- static_value -= dtprel_base(info);
- if (need_relocs)
- microblaze_elf_output_dynamic_relocation
- (output_bfd,
- htab->elf.srelgot,
- htab->elf.srelgot->reloc_count++,
- /* symindex= */ indx, R_MICROBLAZE_TLSDTPREL32,
- got_offset, indx ? 0 : static_value);
- else
- bfd_put_32 (output_bfd, static_value,
- htab->elf.sgot->contents + off2);
- }
- else
- {
- bfd_put_32 (output_bfd, static_value,
- htab->elf.sgot->contents + off2);
- /* Relocs for dyn symbols generated by
- finish_dynamic_symbols */
- if (bfd_link_pic (info) && h == NULL)
- {
- *offp |= 1;
- microblaze_elf_output_dynamic_relocation
- (output_bfd,
- htab->elf.srelgot,
- htab->elf.srelgot->reloc_count++,
- /* symindex= */ indx, R_MICROBLAZE_REL,
- got_offset, static_value);
- }
- }
- }
- /* 4. Fixup Relocation with GOT offset value
- Compute relative address of GOT entry for applying
- the current relocation */
- relocation = htab->elf.sgot->output_section->vma
- + htab->elf.sgot->output_offset
- + off
- - htab->elf.sgotplt->output_section->vma
- - htab->elf.sgotplt->output_offset;
- /* Apply Current Relocation */
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- unresolved_reloc = false;
- break;
- }
- case (int) R_MICROBLAZE_GOTOFF_64:
- {
- bfd_vma immediate;
- unsigned short lo, high;
- relocation += addend;
- relocation -= (htab->elf.sgotplt->output_section->vma
- + htab->elf.sgotplt->output_offset);
- /* Write this value into correct location. */
- immediate = relocation;
- lo = immediate & 0x0000ffff;
- high = (immediate >> 16) & 0x0000ffff;
- bfd_put_16 (input_bfd, high, contents + offset + endian);
- bfd_put_16 (input_bfd, lo,
- contents + offset + INST_WORD_SIZE + endian);
- break;
- }
- case (int) R_MICROBLAZE_GOTOFF_32:
- {
- relocation += addend;
- relocation -= (htab->elf.sgotplt->output_section->vma
- + htab->elf.sgotplt->output_offset);
- /* Write this value into correct location. */
- bfd_put_32 (input_bfd, relocation, contents + offset);
- break;
- }
- case (int) R_MICROBLAZE_TLSDTPREL64:
- relocation += addend;
- relocation -= dtprel_base(info);
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + 2);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + 2 + INST_WORD_SIZE);
- break;
- case (int) R_MICROBLAZE_TEXTREL_64:
- case (int) R_MICROBLAZE_TEXTREL_32_LO:
- case (int) R_MICROBLAZE_64_PCREL :
- case (int) R_MICROBLAZE_64:
- case (int) R_MICROBLAZE_32:
- {
- /* r_symndx will be STN_UNDEF (zero) only for relocs against symbols
- from removed linkonce sections, or sections discarded by
- a linker script. */
- if (r_symndx == STN_UNDEF || (input_section->flags & SEC_ALLOC) == 0)
- {
- relocation += addend;
- if (r_type == R_MICROBLAZE_32)
- bfd_put_32 (input_bfd, relocation, contents + offset);
- else
- {
- if (r_type == R_MICROBLAZE_64_PCREL)
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- else if (r_type == R_MICROBLAZE_TEXTREL_64
- || r_type == R_MICROBLAZE_TEXTREL_32_LO)
- relocation -= input_section->output_section->vma;
- if (r_type == R_MICROBLAZE_TEXTREL_32_LO)
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian);
- else
- {
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian + INST_WORD_SIZE);
- }
- }
- break;
- }
- if ((bfd_link_pic (info)
- && (h == NULL
- || (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
- && !resolved_to_zero)
- || h->root.type != bfd_link_hash_undefweak)
- && (!howto->pc_relative
- || (h != NULL
- && h->dynindx != -1
- && (!info->symbolic
- || !h->def_regular))))
- || (!bfd_link_pic (info)
- && h != NULL
- && h->dynindx != -1
- && !h->non_got_ref
- && ((h->def_dynamic
- && !h->def_regular)
- || h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_undefined)))
- {
- Elf_Internal_Rela outrel;
- bfd_byte *loc;
- bool skip;
- /* When generating a shared object, these relocations
- are copied into the output file to be resolved at run
- time. */
- BFD_ASSERT (sreloc != NULL);
- skip = false;
- outrel.r_offset =
- _bfd_elf_section_offset (output_bfd, info, input_section,
- rel->r_offset);
- if (outrel.r_offset == (bfd_vma) -1)
- skip = true;
- else if (outrel.r_offset == (bfd_vma) -2)
- skip = true;
- outrel.r_offset += (input_section->output_section->vma
- + input_section->output_offset);
- if (skip)
- memset (&outrel, 0, sizeof outrel);
- /* h->dynindx may be -1 if the symbol was marked to
- become local. */
- else if (h != NULL
- && ((! info->symbolic && h->dynindx != -1)
- || !h->def_regular))
- {
- BFD_ASSERT (h->dynindx != -1);
- outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
- outrel.r_addend = addend;
- }
- else
- {
- if (r_type == R_MICROBLAZE_32)
- {
- outrel.r_info = ELF32_R_INFO (0, R_MICROBLAZE_REL);
- outrel.r_addend = relocation + addend;
- }
- else
- {
- BFD_FAIL ();
- _bfd_error_handler
- (_("%pB: probably compiled without -fPIC?"),
- input_bfd);
- bfd_set_error (bfd_error_bad_value);
- return false;
- }
- }
- loc = sreloc->contents;
- loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
- break;
- }
- else
- {
- relocation += addend;
- if (r_type == R_MICROBLAZE_32)
- bfd_put_32 (input_bfd, relocation, contents + offset);
- else
- {
- if (r_type == R_MICROBLAZE_64_PCREL)
- relocation -= (input_section->output_section->vma
- + input_section->output_offset
- + offset + INST_WORD_SIZE);
- else if (r_type == R_MICROBLAZE_TEXTREL_64
- || r_type == R_MICROBLAZE_TEXTREL_32_LO)
- relocation -= input_section->output_section->vma;
- if (r_type == R_MICROBLAZE_TEXTREL_32_LO)
- {
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian);
- }
- else
- {
- bfd_put_16 (input_bfd, (relocation >> 16) & 0xffff,
- contents + offset + endian);
- bfd_put_16 (input_bfd, relocation & 0xffff,
- contents + offset + endian
- + INST_WORD_SIZE);
- }
- }
- break;
- }
- }
- default :
- r = _bfd_final_link_relocate (howto, input_bfd, input_section,
- contents, offset,
- relocation, addend);
- break;
- }
- }
- check_reloc:
- if (r != bfd_reloc_ok)
- {
- /* FIXME: This should be generic enough to go in a utility. */
- const char *name;
- if (h != NULL)
- name = h->root.root.string;
- else
- {
- name = (bfd_elf_string_from_elf_section
- (input_bfd, symtab_hdr->sh_link, sym->st_name));
- if (name == NULL || *name == '\0')
- name = bfd_section_name (sec);
- }
- if (errmsg != NULL)
- goto common_error;
- switch (r)
- {
- case bfd_reloc_overflow:
- (*info->callbacks->reloc_overflow)
- (info, (h ? &h->root : NULL), name, howto->name,
- (bfd_vma) 0, input_bfd, input_section, offset);
- break;
- case bfd_reloc_undefined:
- (*info->callbacks->undefined_symbol)
- (info, name, input_bfd, input_section, offset, true);
- break;
- case bfd_reloc_outofrange:
- errmsg = _("internal error: out of range error");
- goto common_error;
- case bfd_reloc_notsupported:
- errmsg = _("internal error: unsupported relocation error");
- goto common_error;
- case bfd_reloc_dangerous:
- errmsg = _("internal error: dangerous error");
- goto common_error;
- default:
- errmsg = _("internal error: unknown error");
- /* Fall through. */
- common_error:
- (*info->callbacks->warning) (info, errmsg, name, input_bfd,
- input_section, offset);
- break;
- }
- }
- }
- return ret;
- }
- /* Calculate fixup value for reference. */
- static size_t
- calc_fixup (bfd_vma start, bfd_vma size, asection *sec)
- {
- bfd_vma end = start + size;
- size_t i, fixup = 0;
- struct _microblaze_elf_section_data *sdata;
- if (sec == NULL || (sdata = microblaze_elf_section_data (sec)) == NULL)
- return 0;
- /* Look for addr in relax table, total fixup value. */
- for (i = 0; i < sdata->relax_count; i++)
- {
- if (end <= sdata->relax[i].addr)
- break;
- if (end != start && start > sdata->relax[i].addr)
- continue;
- fixup += sdata->relax[i].size;
- }
- return fixup;
- }
- /* Read-modify-write into the bfd, an immediate value into appropriate fields of
- a 32-bit instruction. */
- static void
- microblaze_bfd_write_imm_value_32 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
- {
- unsigned long instr = bfd_get_32 (abfd, bfd_addr);
- instr &= ~0x0000ffff;
- instr |= (val & 0x0000ffff);
- bfd_put_32 (abfd, instr, bfd_addr);
- }
- /* Read-modify-write into the bfd, an immediate value into appropriate fields of
- two consecutive 32-bit instructions. */
- static void
- microblaze_bfd_write_imm_value_64 (bfd *abfd, bfd_byte *bfd_addr, bfd_vma val)
- {
- unsigned long instr_hi;
- unsigned long instr_lo;
- instr_hi = bfd_get_32 (abfd, bfd_addr);
- instr_hi &= ~0x0000ffff;
- instr_hi |= ((val >> 16) & 0x0000ffff);
- bfd_put_32 (abfd, instr_hi, bfd_addr);
- instr_lo = bfd_get_32 (abfd, bfd_addr + INST_WORD_SIZE);
- instr_lo &= ~0x0000ffff;
- instr_lo |= (val & 0x0000ffff);
- bfd_put_32 (abfd, instr_lo, bfd_addr + INST_WORD_SIZE);
- }
- static bool
- microblaze_elf_relax_section (bfd *abfd,
- asection *sec,
- struct bfd_link_info *link_info,
- bool *again)
- {
- Elf_Internal_Shdr *symtab_hdr;
- Elf_Internal_Rela *internal_relocs;
- Elf_Internal_Rela *free_relocs = NULL;
- Elf_Internal_Rela *irel, *irelend;
- bfd_byte *contents = NULL;
- bfd_byte *free_contents = NULL;
- int rel_count;
- unsigned int shndx;
- size_t i, sym_index;
- asection *o;
- struct elf_link_hash_entry *sym_hash;
- Elf_Internal_Sym *isymbuf, *isymend;
- Elf_Internal_Sym *isym;
- size_t symcount;
- size_t offset;
- bfd_vma src, dest;
- struct _microblaze_elf_section_data *sdata;
- /* We only do this once per section. We may be able to delete some code
- by running multiple passes, but it is not worth it. */
- *again = false;
- /* Only do this for a text section. */
- if (bfd_link_relocatable (link_info)
- || (sec->flags & SEC_RELOC) == 0
- || (sec->flags & SEC_CODE) == 0
- || sec->reloc_count == 0
- || (sdata = microblaze_elf_section_data (sec)) == NULL)
- return true;
- BFD_ASSERT ((sec->size > 0) || (sec->rawsize > 0));
- /* If this is the first time we have been called for this section,
- initialize the cooked size. */
- if (sec->size == 0)
- sec->size = sec->rawsize;
- /* Get symbols for this section. */
- symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
- isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
- symcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
- if (isymbuf == NULL)
- isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, symcount,
- 0, NULL, NULL, NULL);
- BFD_ASSERT (isymbuf != NULL);
- internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory);
- if (internal_relocs == NULL)
- goto error_return;
- if (! link_info->keep_memory)
- free_relocs = internal_relocs;
- sdata->relax_count = 0;
- sdata->relax = (struct relax_table *) bfd_malloc ((sec->reloc_count + 1)
- * sizeof (*sdata->relax));
- if (sdata->relax == NULL)
- goto error_return;
- irelend = internal_relocs + sec->reloc_count;
- rel_count = 0;
- for (irel = internal_relocs; irel < irelend; irel++, rel_count++)
- {
- bfd_vma symval;
- if ((ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64_PCREL)
- && (ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_64)
- && (ELF32_R_TYPE (irel->r_info) != (int) R_MICROBLAZE_TEXTREL_64))
- continue; /* Can't delete this reloc. */
- /* Get the section contents. */
- if (contents == NULL)
- {
- if (elf_section_data (sec)->this_hdr.contents != NULL)
- contents = elf_section_data (sec)->this_hdr.contents;
- else
- {
- contents = (bfd_byte *) bfd_malloc (sec->size);
- if (contents == NULL)
- goto error_return;
- free_contents = contents;
- if (!bfd_get_section_contents (abfd, sec, contents,
- (file_ptr) 0, sec->size))
- goto error_return;
- elf_section_data (sec)->this_hdr.contents = contents;
- }
- }
- /* Get the value of the symbol referred to by the reloc. */
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- /* A local symbol. */
- asection *sym_sec;
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- if (isym->st_shndx == SHN_UNDEF)
- sym_sec = bfd_und_section_ptr;
- else if (isym->st_shndx == SHN_ABS)
- sym_sec = bfd_abs_section_ptr;
- else if (isym->st_shndx == SHN_COMMON)
- sym_sec = bfd_com_section_ptr;
- else
- sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
- symval = _bfd_elf_rela_local_sym (abfd, isym, &sym_sec, irel);
- }
- else
- {
- unsigned long indx;
- struct elf_link_hash_entry *h;
- indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
- h = elf_sym_hashes (abfd)[indx];
- BFD_ASSERT (h != NULL);
- if (h->root.type != bfd_link_hash_defined
- && h->root.type != bfd_link_hash_defweak)
- /* This appears to be a reference to an undefined
- symbol. Just ignore it--it will be caught by the
- regular reloc processing. */
- continue;
- symval = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
- }
- /* If this is a PC-relative reloc, subtract the instr offset from
- the symbol value. */
- if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROBLAZE_64_PCREL)
- {
- symval = symval + irel->r_addend
- - (irel->r_offset
- + sec->output_section->vma
- + sec->output_offset);
- }
- else if (ELF32_R_TYPE (irel->r_info) == (int) R_MICROBLAZE_TEXTREL_64)
- {
- symval = symval + irel->r_addend - (sec->output_section->vma);
- }
- else
- symval += irel->r_addend;
- if ((symval & 0xffff8000) == 0
- || (symval & 0xffff8000) == 0xffff8000)
- {
- /* We can delete this instruction. */
- sdata->relax[sdata->relax_count].addr = irel->r_offset;
- sdata->relax[sdata->relax_count].size = INST_WORD_SIZE;
- sdata->relax_count++;
- /* Rewrite relocation type. */
- switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info))
- {
- case R_MICROBLAZE_64_PCREL:
- irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
- (int) R_MICROBLAZE_32_PCREL_LO);
- break;
- case R_MICROBLAZE_64:
- irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
- (int) R_MICROBLAZE_32_LO);
- break;
- case R_MICROBLAZE_TEXTREL_64:
- irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
- (int) R_MICROBLAZE_TEXTREL_32_LO);
- break;
- default:
- /* Cannot happen. */
- BFD_ASSERT (false);
- }
- }
- } /* Loop through all relocations. */
- /* Loop through the relocs again, and see if anything needs to change. */
- if (sdata->relax_count > 0)
- {
- shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
- rel_count = 0;
- sdata->relax[sdata->relax_count].addr = sec->size;
- for (irel = internal_relocs; irel < irelend; irel++, rel_count++)
- {
- bfd_vma nraddr;
- /* Get the new reloc address. */
- nraddr = irel->r_offset - calc_fixup (irel->r_offset, 0, sec);
- switch ((enum elf_microblaze_reloc_type) ELF32_R_TYPE (irel->r_info))
- {
- default:
- break;
- case R_MICROBLAZE_64_PCREL:
- break;
- case R_MICROBLAZE_TEXTREL_64:
- case R_MICROBLAZE_TEXTREL_32_LO:
- case R_MICROBLAZE_64:
- case R_MICROBLAZE_32_LO:
- /* If this reloc is against a symbol defined in this
- section, we must check the addend to see it will put the value in
- range to be adjusted, and hence must be changed. */
- if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
- {
- isym = isymbuf + ELF32_R_SYM (irel->r_info);
- /* Only handle relocs against .text. */
- if (isym->st_shndx == shndx
- && ELF32_ST_TYPE (isym->st_info) == STT_SECTION)
- irel->r_addend -= calc_fixup (irel->r_addend, 0, sec);
- }
- break;
- case R_MICROBLAZE_NONE:
- {
- /* This was a PC-relative instruction that was
- completely resolved. */
- size_t sfix, efix;
- bfd_vma target_address;
- target_address = irel->r_addend + irel->r_offset;
- sfix = calc_fixup (irel->r_offset, 0, sec);
- efix = calc_fixup (target_address, 0, sec);
- irel->r_addend -= (efix - sfix);
- /* Should use HOWTO. */
- microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset,
- irel->r_addend);
- }
- break;
- case R_MICROBLAZE_64_NONE:
- {
- /* This was a PC-relative 64-bit instruction that was
- completely resolved. */
- size_t sfix, efix;
- bfd_vma target_address;
- target_address = irel->r_addend + irel->r_offset + INST_WORD_SIZE;
- sfix = calc_fixup (irel->r_offset + INST_WORD_SIZE, 0, sec);
- efix = calc_fixup (target_address, 0, sec);
- irel->r_addend -= (efix - sfix);
- microblaze_bfd_write_imm_value_32 (abfd, contents + irel->r_offset
- + INST_WORD_SIZE, irel->r_addend);
- }
- break;
- }
- irel->r_offset = nraddr;
- } /* Change all relocs in this section. */
- /* Look through all other sections. */
- for (o = abfd->sections; o != NULL; o = o->next)
- {
- Elf_Internal_Rela *irelocs;
- Elf_Internal_Rela *irelscan, *irelscanend;
- bfd_byte *ocontents;
- if (o == sec
- || (o->flags & SEC_RELOC) == 0
- || o->reloc_count == 0)
- continue;
- /* We always cache the relocs. Perhaps, if info->keep_memory is
- FALSE, we should free them, if we are permitted to. */
- irelocs = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, true);
- if (irelocs == NULL)
- goto error_return;
- ocontents = NULL;
- irelscanend = irelocs + o->reloc_count;
- for (irelscan = irelocs; irelscan < irelscanend; irelscan++)
- {
- if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32)
- {
- isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
- /* Look at the reloc only if the value has been resolved. */
- if (isym->st_shndx == shndx
- && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
- {
- if (ocontents == NULL)
- {
- if (elf_section_data (o)->this_hdr.contents != NULL)
- ocontents = elf_section_data (o)->this_hdr.contents;
- else
- {
- /* We always cache the section contents.
- Perhaps, if info->keep_memory is FALSE, we
- should free them, if we are permitted to. */
- if (o->rawsize == 0)
- o->rawsize = o->size;
- ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
- if (ocontents == NULL)
- goto error_return;
- if (!bfd_get_section_contents (abfd, o, ocontents,
- (file_ptr) 0,
- o->rawsize))
- goto error_return;
- elf_section_data (o)->this_hdr.contents = ocontents;
- }
- }
- irelscan->r_addend -= calc_fixup (irelscan->r_addend, 0, sec);
- }
- else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_SYM_OP_SYM)
- {
- isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
- /* Look at the reloc only if the value has been resolved. */
- if (ocontents == NULL)
- {
- if (elf_section_data (o)->this_hdr.contents != NULL)
- ocontents = elf_section_data (o)->this_hdr.contents;
- else
- {
- /* We always cache the section contents.
- Perhaps, if info->keep_memory is FALSE, we
- should free them, if we are permitted to. */
- if (o->rawsize == 0)
- o->rawsize = o->size;
- ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
- if (ocontents == NULL)
- goto error_return;
- if (!bfd_get_section_contents (abfd, o, ocontents,
- (file_ptr) 0,
- o->rawsize))
- goto error_return;
- elf_section_data (o)->this_hdr.contents = ocontents;
- }
- }
- irelscan->r_addend -= calc_fixup (irel->r_addend
- + isym->st_value,
- 0,
- sec);
- }
- }
- else if ((ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_32_PCREL_LO)
- || (ELF32_R_TYPE (irelscan->r_info)
- == (int) R_MICROBLAZE_32_LO)
- || (ELF32_R_TYPE (irelscan->r_info)
- == (int) R_MICROBLAZE_TEXTREL_32_LO))
- {
- isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
- /* Look at the reloc only if the value has been resolved. */
- if (isym->st_shndx == shndx
- && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
- {
- bfd_vma immediate;
- bfd_vma target_address;
- if (ocontents == NULL)
- {
- if (elf_section_data (o)->this_hdr.contents != NULL)
- ocontents = elf_section_data (o)->this_hdr.contents;
- else
- {
- /* We always cache the section contents.
- Perhaps, if info->keep_memory is FALSE, we
- should free them, if we are permitted to. */
- if (o->rawsize == 0)
- o->rawsize = o->size;
- ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
- if (ocontents == NULL)
- goto error_return;
- if (!bfd_get_section_contents (abfd, o, ocontents,
- (file_ptr) 0,
- o->rawsize))
- goto error_return;
- elf_section_data (o)->this_hdr.contents = ocontents;
- }
- }
- unsigned long instr = bfd_get_32 (abfd, ocontents + irelscan->r_offset);
- immediate = instr & 0x0000ffff;
- target_address = immediate;
- offset = calc_fixup (target_address, 0, sec);
- immediate -= offset;
- irelscan->r_addend -= offset;
- microblaze_bfd_write_imm_value_32 (abfd, ocontents + irelscan->r_offset,
- irelscan->r_addend);
- }
- }
- if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64
- || (ELF32_R_TYPE (irelscan->r_info)
- == (int) R_MICROBLAZE_TEXTREL_64))
- {
- isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
- /* Look at the reloc only if the value has been resolved. */
- if (isym->st_shndx == shndx
- && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
- {
- if (ocontents == NULL)
- {
- if (elf_section_data (o)->this_hdr.contents != NULL)
- ocontents = elf_section_data (o)->this_hdr.contents;
- else
- {
- /* We always cache the section contents.
- Perhaps, if info->keep_memory is FALSE, we
- should free them, if we are permitted to. */
- if (o->rawsize == 0)
- o->rawsize = o->size;
- ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
- if (ocontents == NULL)
- goto error_return;
- if (!bfd_get_section_contents (abfd, o, ocontents,
- (file_ptr) 0,
- o->rawsize))
- goto error_return;
- elf_section_data (o)->this_hdr.contents = ocontents;
- }
- }
- offset = calc_fixup (irelscan->r_addend, 0, sec);
- irelscan->r_addend -= offset;
- }
- }
- else if (ELF32_R_TYPE (irelscan->r_info) == (int) R_MICROBLAZE_64_PCREL)
- {
- isym = isymbuf + ELF32_R_SYM (irelscan->r_info);
- /* Look at the reloc only if the value has been resolved. */
- if (isym->st_shndx == shndx
- && (ELF32_ST_TYPE (isym->st_info) == STT_SECTION))
- {
- bfd_vma immediate;
- bfd_vma target_address;
- if (ocontents == NULL)
- {
- if (elf_section_data (o)->this_hdr.contents != NULL)
- ocontents = elf_section_data (o)->this_hdr.contents;
- else
- {
- /* We always cache the section contents.
- Perhaps, if info->keep_memory is FALSE, we
- should free them, if we are permitted to. */
- if (o->rawsize == 0)
- o->rawsize = o->size;
- ocontents = (bfd_byte *) bfd_malloc (o->rawsize);
- if (ocontents == NULL)
- goto error_return;
- if (!bfd_get_section_contents (abfd, o, ocontents,
- (file_ptr) 0,
- o->rawsize))
- goto error_return;
- elf_section_data (o)->this_hdr.contents = ocontents;
- }
- }
- unsigned long instr_hi = bfd_get_32 (abfd, ocontents
- + irelscan->r_offset);
- unsigned long instr_lo = bfd_get_32 (abfd, ocontents
- + irelscan->r_offset
- + INST_WORD_SIZE);
- immediate = (instr_hi & 0x0000ffff) << 16;
- immediate |= (instr_lo & 0x0000ffff);
- target_address = immediate;
- offset = calc_fixup (target_address, 0, sec);
- immediate -= offset;
- irelscan->r_addend -= offset;
- microblaze_bfd_write_imm_value_64 (abfd, ocontents
- + irelscan->r_offset, immediate);
- }
- }
- }
- }
- /* Adjust the local symbols defined in this section. */
- isymend = isymbuf + symtab_hdr->sh_info;
- for (isym = isymbuf; isym < isymend; isym++)
- {
- if (isym->st_shndx == shndx)
- {
- isym->st_value -= calc_fixup (isym->st_value, 0, sec);
- if (isym->st_size)
- isym->st_size -= calc_fixup (isym->st_value, isym->st_size, sec);
- }
- }
- /* Now adjust the global symbols defined in this section. */
- isym = isymbuf + symtab_hdr->sh_info;
- symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)) - symtab_hdr->sh_info;
- for (sym_index = 0; sym_index < symcount; sym_index++)
- {
- sym_hash = elf_sym_hashes (abfd)[sym_index];
- if ((sym_hash->root.type == bfd_link_hash_defined
- || sym_hash->root.type == bfd_link_hash_defweak)
- && sym_hash->root.u.def.section == sec)
- {
- sym_hash->root.u.def.value -= calc_fixup (sym_hash->root.u.def.value,
- 0, sec);
- if (sym_hash->size)
- sym_hash->size -= calc_fixup (sym_hash->root.u.def.value,
- sym_hash->size, sec);
- }
- }
- /* Physically move the code and change the cooked size. */
- dest = sdata->relax[0].addr;
- for (i = 0; i < sdata->relax_count; i++)
- {
- size_t len;
- src = sdata->relax[i].addr + sdata->relax[i].size;
- len = (sdata->relax[i+1].addr - sdata->relax[i].addr
- - sdata->relax[i].size);
- memmove (contents + dest, contents + src, len);
- sec->size -= sdata->relax[i].size;
- dest += len;
- }
- elf_section_data (sec)->relocs = internal_relocs;
- free_relocs = NULL;
- elf_section_data (sec)->this_hdr.contents = contents;
- free_contents = NULL;
- symtab_hdr->contents = (bfd_byte *) isymbuf;
- }
- free (free_relocs);
- free_relocs = NULL;
- if (free_contents != NULL)
- {
- if (!link_info->keep_memory)
- free (free_contents);
- else
- /* Cache the section contents for elf_link_input_bfd. */
- elf_section_data (sec)->this_hdr.contents = contents;
- free_contents = NULL;
- }
- if (sdata->relax_count == 0)
- {
- *again = false;
- free (sdata->relax);
- sdata->relax = NULL;
- }
- else
- *again = true;
- return true;
- error_return:
- free (free_relocs);
- free (free_contents);
- free (sdata->relax);
- sdata->relax = NULL;
- sdata->relax_count = 0;
- return false;
- }
- /* Return the section that should be marked against GC for a given
- relocation. */
- static asection *
- microblaze_elf_gc_mark_hook (asection *sec,
- struct bfd_link_info * info,
- Elf_Internal_Rela * rel,
- struct elf_link_hash_entry * h,
- Elf_Internal_Sym * sym)
- {
- if (h != NULL)
- switch (ELF32_R_TYPE (rel->r_info))
- {
- case R_MICROBLAZE_GNU_VTINHERIT:
- case R_MICROBLAZE_GNU_VTENTRY:
- return NULL;
- }
- return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
- }
- /* PIC support. */
- #define PLT_ENTRY_SIZE 16
- #define PLT_ENTRY_WORD_0 0xb0000000 /* "imm 0". */
- #define PLT_ENTRY_WORD_1 0xe9940000 /* "lwi r12,r20,0" - relocated to lwi r12,r20,func@GOT. */
- #define PLT_ENTRY_WORD_1_NOPIC 0xe9800000 /* "lwi r12,r0,0" - non-PIC object. */
- #define PLT_ENTRY_WORD_2 0x98186000 /* "brad r12". */
- #define PLT_ENTRY_WORD_3 0x80000000 /* "nop". */
- static bool
- update_local_sym_info (bfd *abfd,
- Elf_Internal_Shdr *symtab_hdr,
- unsigned long r_symndx,
- unsigned int tls_type)
- {
- bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
- unsigned char *local_got_tls_masks;
- if (local_got_refcounts == NULL)
- {
- bfd_size_type size = symtab_hdr->sh_info;
- size *= (sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks));
- local_got_refcounts = bfd_zalloc (abfd, size);
- if (local_got_refcounts == NULL)
- return false;
- elf_local_got_refcounts (abfd) = local_got_refcounts;
- }
- local_got_tls_masks =
- (unsigned char *) (local_got_refcounts + symtab_hdr->sh_info);
- local_got_tls_masks[r_symndx] |= tls_type;
- local_got_refcounts[r_symndx] += 1;
- return true;
- }
- /* Look through the relocs for a section during the first phase. */
- static bool
- microblaze_elf_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;
- const Elf_Internal_Rela * rel;
- const Elf_Internal_Rela * rel_end;
- struct elf32_mb_link_hash_table *htab;
- asection *sreloc = NULL;
- if (bfd_link_relocatable (info))
- return true;
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- symtab_hdr = & elf_tdata (abfd)->symtab_hdr;
- sym_hashes = elf_sym_hashes (abfd);
- rel_end = relocs + sec->reloc_count;
- for (rel = relocs; rel < rel_end; rel++)
- {
- unsigned int r_type;
- struct elf_link_hash_entry * h;
- unsigned long r_symndx;
- unsigned char tls_type = 0;
- r_symndx = ELF32_R_SYM (rel->r_info);
- r_type = ELF32_R_TYPE (rel->r_info);
- if (r_symndx < symtab_hdr->sh_info)
- h = NULL;
- else
- {
- 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;
- }
- switch (r_type)
- {
- /* This relocation describes the C++ object vtable hierarchy.
- Reconstruct it for later use during GC. */
- case R_MICROBLAZE_GNU_VTINHERIT:
- if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
- return false;
- break;
- /* This relocation describes which C++ vtable entries are actually
- used. Record for later use during GC. */
- case R_MICROBLAZE_GNU_VTENTRY:
- if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
- return false;
- break;
- /* This relocation requires .plt entry. */
- case R_MICROBLAZE_PLT_64:
- if (h != NULL)
- {
- h->needs_plt = 1;
- h->plt.refcount += 1;
- }
- break;
- /* This relocation requires .got entry. */
- case R_MICROBLAZE_TLSGD:
- tls_type |= (TLS_TLS | TLS_GD);
- goto dogottls;
- case R_MICROBLAZE_TLSLD:
- tls_type |= (TLS_TLS | TLS_LD);
- /* Fall through. */
- dogottls:
- sec->has_tls_reloc = 1;
- /* Fall through. */
- case R_MICROBLAZE_GOT_64:
- if (htab->elf.sgot == NULL)
- {
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
- if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
- return false;
- }
- if (h != NULL)
- {
- h->got.refcount += 1;
- elf32_mb_hash_entry (h)->tls_mask |= tls_type;
- }
- else
- {
- if (! update_local_sym_info(abfd, symtab_hdr, r_symndx, tls_type) )
- return false;
- }
- break;
- case R_MICROBLAZE_GOTOFF_64:
- case R_MICROBLAZE_GOTOFF_32:
- if (htab->elf.sgot == NULL)
- {
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
- if (!_bfd_elf_create_got_section (htab->elf.dynobj, info))
- return false;
- }
- break;
- case R_MICROBLAZE_64:
- case R_MICROBLAZE_64_PCREL:
- case R_MICROBLAZE_32:
- {
- if (h != NULL && !bfd_link_pic (info))
- {
- /* we may need a copy reloc. */
- h->non_got_ref = 1;
- /* we may also need a .plt entry. */
- h->plt.refcount += 1;
- if (ELF32_R_TYPE (rel->r_info) != R_MICROBLAZE_64_PCREL)
- h->pointer_equality_needed = 1;
- }
- /* If we are creating a shared library, and this is a reloc
- against a global symbol, or a non PC relative reloc
- against a local symbol, then we need to copy the reloc
- into the shared library. However, if we are linking with
- -Bsymbolic, we do not need to copy a reloc against a
- global symbol which is defined in an object we are
- including in the link (i.e., DEF_REGULAR is set). At
- this point we have not seen all the input files, so it is
- possible that DEF_REGULAR is not set now but will be set
- later (it is never cleared). In case of a weak definition,
- DEF_REGULAR may be cleared later by a strong definition in
- a shared library. We account for that possibility below by
- storing information in the relocs_copied field of the hash
- table entry. A similar situation occurs when creating
- shared libraries and symbol visibility changes render the
- symbol local.
- If on the other hand, we are creating an executable, we
- may need to keep relocations for symbols satisfied by a
- dynamic library if we manage to avoid copy relocs for the
- symbol. */
- if ((bfd_link_pic (info)
- && (sec->flags & SEC_ALLOC) != 0
- && (r_type != R_MICROBLAZE_64_PCREL
- || (h != NULL
- && (! info->symbolic
- || h->root.type == bfd_link_hash_defweak
- || !h->def_regular))))
- || (!bfd_link_pic (info)
- && (sec->flags & SEC_ALLOC) != 0
- && h != NULL
- && (h->root.type == bfd_link_hash_defweak
- || !h->def_regular)))
- {
- struct elf_dyn_relocs *p;
- struct elf_dyn_relocs **head;
- /* When creating a shared object, we must copy these
- relocs into the output file. We create a reloc
- section in dynobj and make room for the reloc. */
- if (sreloc == NULL)
- {
- bfd *dynobj;
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
- dynobj = htab->elf.dynobj;
- sreloc = _bfd_elf_make_dynamic_reloc_section (sec, dynobj,
- 2, abfd, 1);
- if (sreloc == NULL)
- return false;
- }
- /* If this is a global symbol, we count the number of
- relocations we need for this symbol. */
- if (h != NULL)
- head = &h->dyn_relocs;
- else
- {
- /* Track dynamic relocs needed for local syms too.
- We really need local syms available to do this
- easily. Oh well. */
- asection *s;
- Elf_Internal_Sym *isym;
- void *vpp;
- isym = bfd_sym_from_r_symndx (&htab->elf.sym_cache,
- abfd, r_symndx);
- if (isym == NULL)
- return false;
- s = bfd_section_from_elf_index (abfd, isym->st_shndx);
- if (s == NULL)
- return false;
- vpp = &elf_section_data (s)->local_dynrel;
- head = (struct elf_dyn_relocs **) vpp;
- }
- p = *head;
- if (p == NULL || p->sec != sec)
- {
- size_t amt = sizeof *p;
- p = ((struct elf_dyn_relocs *)
- bfd_alloc (htab->elf.dynobj, amt));
- if (p == NULL)
- return false;
- p->next = *head;
- *head = p;
- p->sec = sec;
- p->count = 0;
- p->pc_count = 0;
- }
- p->count += 1;
- if (r_type == R_MICROBLAZE_64_PCREL)
- p->pc_count += 1;
- }
- }
- break;
- }
- }
- return true;
- }
- /* Copy the extra info we tack onto an elf_link_hash_entry. */
- static void
- microblaze_elf_copy_indirect_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *dir,
- struct elf_link_hash_entry *ind)
- {
- struct elf32_mb_link_hash_entry *edir, *eind;
- edir = (struct elf32_mb_link_hash_entry *) dir;
- eind = (struct elf32_mb_link_hash_entry *) ind;
- edir->tls_mask |= eind->tls_mask;
- _bfd_elf_link_hash_copy_indirect (info, dir, ind);
- }
- static bool
- microblaze_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
- struct elf_link_hash_entry *h)
- {
- struct elf32_mb_link_hash_table *htab;
- asection *s, *srel;
- unsigned int power_of_two;
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- /* If this is a function, put it in the procedure linkage table. We
- will fill in the contents of the procedure linkage table later,
- when we know the address of the .got section. */
- if (h->type == STT_FUNC
- || h->needs_plt)
- {
- if (h->plt.refcount <= 0
- || SYMBOL_CALLS_LOCAL (info, h)
- || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
- && h->root.type == bfd_link_hash_undefweak))
- {
- /* This case can occur if we saw a PLT reloc in an input
- file, but the symbol was never referred to by a dynamic
- object, or if all references were garbage collected. In
- such a case, we don't actually need to build a procedure
- linkage table, and we can just do a PC32 reloc instead. */
- h->plt.offset = (bfd_vma) -1;
- h->needs_plt = 0;
- }
- return true;
- }
- else
- /* It's possible that we incorrectly decided a .plt reloc was
- needed for an R_MICROBLAZE_64_PCREL reloc to a non-function sym in
- check_relocs. We can't decide accurately between function and
- non-function syms in check-relocs; Objects loaded later in
- the link may change h->type. So fix it now. */
- h->plt.offset = (bfd_vma) -1;
- /* If this is a weak symbol, and there is a real definition, the
- processor independent code will have arranged for us to see the
- real definition first, and we can just use the same value. */
- if (h->is_weakalias)
- {
- struct elf_link_hash_entry *def = weakdef (h);
- BFD_ASSERT (def->root.type == bfd_link_hash_defined);
- h->root.u.def.section = def->root.u.def.section;
- h->root.u.def.value = def->root.u.def.value;
- return true;
- }
- /* This is a reference to a symbol defined by a dynamic object which
- is not a function. */
- /* If we are creating a shared library, we must presume that the
- only references to the symbol are via the global offset table.
- For such cases we need not do anything here; the relocations will
- be handled correctly by relocate_section. */
- if (bfd_link_pic (info))
- return true;
- /* If there are no references to this symbol that do not use the
- GOT, we don't need to generate a copy reloc. */
- if (!h->non_got_ref)
- return true;
- /* If -z nocopyreloc was given, we won't generate them either. */
- if (info->nocopyreloc)
- {
- h->non_got_ref = 0;
- return true;
- }
- /* If we don't find any dynamic relocs in read-only sections, then
- we'll be keeping the dynamic relocs and avoiding the copy reloc. */
- if (!_bfd_elf_readonly_dynrelocs (h))
- {
- h->non_got_ref = 0;
- return true;
- }
- /* We must allocate the symbol in our .dynbss section, which will
- become part of the .bss section of the executable. There will be
- an entry for this symbol in the .dynsym section. The dynamic
- object will contain position independent code, so all references
- from the dynamic object to this symbol will go through the global
- offset table. The dynamic linker will use the .dynsym entry to
- determine the address it must put in the global offset table, so
- both the dynamic object and the regular object will refer to the
- same memory location for the variable. */
- /* We must generate a R_MICROBLAZE_COPY reloc to tell the dynamic linker
- to copy the initial value out of the dynamic object and into the
- runtime process image. */
- if ((h->root.u.def.section->flags & SEC_READONLY) != 0)
- {
- s = htab->elf.sdynrelro;
- srel = htab->elf.sreldynrelro;
- }
- else
- {
- s = htab->elf.sdynbss;
- srel = htab->elf.srelbss;
- }
- if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
- {
- srel->size += sizeof (Elf32_External_Rela);
- h->needs_copy = 1;
- }
- /* We need to figure out the alignment required for this symbol. I
- have no idea how ELF linkers handle this. */
- power_of_two = bfd_log2 (h->size);
- if (power_of_two > 3)
- power_of_two = 3;
- /* Apply the required alignment. */
- s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two));
- if (power_of_two > s->alignment_power)
- {
- if (!bfd_set_section_alignment (s, power_of_two))
- return false;
- }
- /* Define the symbol as being at this point in the section. */
- h->root.u.def.section = s;
- h->root.u.def.value = s->size;
- /* Increment the section size to make room for the symbol. */
- s->size += h->size;
- return true;
- }
- /* Allocate space in .plt, .got and associated reloc sections for
- dynamic relocs. */
- static bool
- allocate_dynrelocs (struct elf_link_hash_entry *h, void * dat)
- {
- struct bfd_link_info *info;
- struct elf32_mb_link_hash_table *htab;
- struct elf32_mb_link_hash_entry *eh;
- struct elf_dyn_relocs *p;
- if (h->root.type == bfd_link_hash_indirect)
- return true;
- info = (struct bfd_link_info *) dat;
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- if (htab->elf.dynamic_sections_created
- && h->plt.refcount > 0)
- {
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
- }
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
- {
- asection *s = htab->elf.splt;
- /* The first entry in .plt is reserved. */
- if (s->size == 0)
- s->size = PLT_ENTRY_SIZE;
- h->plt.offset = s->size;
- /* If this symbol is not defined in a regular file, and we are
- not generating a shared library, then set the symbol to this
- location in the .plt. This is required to make function
- pointers compare as equal between the normal executable and
- the shared library. */
- if (! bfd_link_pic (info)
- && !h->def_regular)
- {
- h->root.u.def.section = s;
- h->root.u.def.value = h->plt.offset;
- }
- /* Make room for this entry. */
- s->size += PLT_ENTRY_SIZE;
- /* We also need to make an entry in the .got.plt section, which
- will be placed in the .got section by the linker script. */
- htab->elf.sgotplt->size += 4;
- /* We also need to make an entry in the .rel.plt section. */
- htab->elf.srelplt->size += sizeof (Elf32_External_Rela);
- }
- else
- {
- h->plt.offset = (bfd_vma) -1;
- h->needs_plt = 0;
- }
- }
- else
- {
- h->plt.offset = (bfd_vma) -1;
- h->needs_plt = 0;
- }
- eh = (struct elf32_mb_link_hash_entry *) h;
- if (h->got.refcount > 0)
- {
- unsigned int need;
- asection *s;
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
- }
- need = 0;
- if ((eh->tls_mask & TLS_TLS) != 0)
- {
- /* Handle TLS Symbol */
- if ((eh->tls_mask & TLS_LD) != 0)
- {
- if (!eh->elf.def_dynamic)
- /* We'll just use htab->tlsld_got.offset. This should
- always be the case. It's a little odd if we have
- a local dynamic reloc against a non-local symbol. */
- htab->tlsld_got.refcount += 1;
- else
- need += 8;
- }
- if ((eh->tls_mask & TLS_GD) != 0)
- need += 8;
- }
- else
- {
- /* Regular (non-TLS) symbol */
- need += 4;
- }
- if (need == 0)
- {
- h->got.offset = (bfd_vma) -1;
- }
- else
- {
- s = htab->elf.sgot;
- h->got.offset = s->size;
- s->size += need;
- htab->elf.srelgot->size += need * (sizeof (Elf32_External_Rela) / 4);
- }
- }
- else
- h->got.offset = (bfd_vma) -1;
- if (h->dyn_relocs == NULL)
- return true;
- /* In the shared -Bsymbolic case, discard space allocated for
- dynamic pc-relative relocs against symbols which turn out to be
- defined in regular objects. For the normal shared case, discard
- space for pc-relative relocs that have become local due to symbol
- visibility changes. */
- if (bfd_link_pic (info))
- {
- if (h->def_regular
- && (h->forced_local
- || info->symbolic))
- {
- struct elf_dyn_relocs **pp;
- for (pp = &h->dyn_relocs; (p = *pp) != NULL; )
- {
- p->count -= p->pc_count;
- p->pc_count = 0;
- if (p->count == 0)
- *pp = p->next;
- else
- pp = &p->next;
- }
- }
- else if (UNDEFWEAK_NO_DYNAMIC_RELOC (info, h))
- h->dyn_relocs = NULL;
- }
- else
- {
- /* For the non-shared case, discard space for relocs against
- symbols which turn out to need copy relocs or are not
- dynamic. */
- if (!h->non_got_ref
- && ((h->def_dynamic
- && !h->def_regular)
- || (htab->elf.dynamic_sections_created
- && (h->root.type == bfd_link_hash_undefweak
- || h->root.type == bfd_link_hash_undefined))))
- {
- /* Make sure this symbol is output as a dynamic symbol.
- Undefined weak syms won't yet be marked as dynamic. */
- if (h->dynindx == -1
- && !h->forced_local)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return false;
- }
- /* If that succeeded, we know we'll be keeping all the
- relocs. */
- if (h->dynindx != -1)
- goto keep;
- }
- h->dyn_relocs = NULL;
- keep: ;
- }
- /* Finally, allocate space. */
- for (p = h->dyn_relocs; p != NULL; p = p->next)
- {
- asection *sreloc = elf_section_data (p->sec)->sreloc;
- sreloc->size += p->count * sizeof (Elf32_External_Rela);
- }
- return true;
- }
- /* Set the sizes of the dynamic sections. */
- static bool
- microblaze_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
- struct bfd_link_info *info)
- {
- struct elf32_mb_link_hash_table *htab;
- bfd *dynobj;
- asection *s;
- bfd *ibfd;
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- dynobj = htab->elf.dynobj;
- BFD_ASSERT (dynobj != NULL);
- /* Set up .got offsets for local syms, and space for local dynamic
- relocs. */
- for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next)
- {
- bfd_signed_vma *local_got;
- bfd_signed_vma *end_local_got;
- bfd_size_type locsymcount;
- Elf_Internal_Shdr *symtab_hdr;
- unsigned char *lgot_masks;
- asection *srel;
- if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
- continue;
- for (s = ibfd->sections; s != NULL; s = s->next)
- {
- struct elf_dyn_relocs *p;
- for (p = ((struct elf_dyn_relocs *)
- elf_section_data (s)->local_dynrel);
- p != NULL;
- p = p->next)
- {
- if (!bfd_is_abs_section (p->sec)
- && bfd_is_abs_section (p->sec->output_section))
- {
- /* Input section has been discarded, either because
- it is a copy of a linkonce section or due to
- linker script /DISCARD/, so we'll be discarding
- the relocs too. */
- }
- else if (p->count != 0)
- {
- srel = elf_section_data (p->sec)->sreloc;
- srel->size += p->count * sizeof (Elf32_External_Rela);
- if ((p->sec->output_section->flags & SEC_READONLY) != 0)
- info->flags |= DF_TEXTREL;
- }
- }
- }
- local_got = elf_local_got_refcounts (ibfd);
- if (!local_got)
- continue;
- symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
- locsymcount = symtab_hdr->sh_info;
- end_local_got = local_got + locsymcount;
- lgot_masks = (unsigned char *) end_local_got;
- s = htab->elf.sgot;
- srel = htab->elf.srelgot;
- for (; local_got < end_local_got; ++local_got, ++lgot_masks)
- {
- if (*local_got > 0)
- {
- unsigned int need = 0;
- if ((*lgot_masks & TLS_TLS) != 0)
- {
- if ((*lgot_masks & TLS_GD) != 0)
- need += 8;
- if ((*lgot_masks & TLS_LD) != 0)
- htab->tlsld_got.refcount += 1;
- }
- else
- need += 4;
- if (need == 0)
- {
- *local_got = (bfd_vma) -1;
- }
- else
- {
- *local_got = s->size;
- s->size += need;
- if (bfd_link_pic (info))
- srel->size += need * (sizeof (Elf32_External_Rela) / 4);
- }
- }
- else
- *local_got = (bfd_vma) -1;
- }
- }
- /* Allocate global sym .plt and .got entries, and space for global
- sym dynamic relocs. */
- elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
- if (htab->tlsld_got.refcount > 0)
- {
- htab->tlsld_got.offset = htab->elf.sgot->size;
- htab->elf.sgot->size += 8;
- if (bfd_link_pic (info))
- htab->elf.srelgot->size += sizeof (Elf32_External_Rela);
- }
- else
- htab->tlsld_got.offset = (bfd_vma) -1;
- if (elf_hash_table (info)->dynamic_sections_created)
- {
- /* Make space for the trailing nop in .plt. */
- if (htab->elf.splt->size > 0)
- htab->elf.splt->size += 4;
- }
- /* The check_relocs and adjust_dynamic_symbol entry points have
- determined the sizes of the various dynamic sections. Allocate
- memory for them. */
- for (s = dynobj->sections; s != NULL; s = s->next)
- {
- const char *name;
- bool strip = false;
- if ((s->flags & SEC_LINKER_CREATED) == 0)
- continue;
- /* It's OK to base decisions on the section name, because none
- of the dynobj section names depend upon the input files. */
- name = bfd_section_name (s);
- if (startswith (name, ".rela"))
- {
- if (s->size == 0)
- {
- /* If we don't need this section, strip it from the
- output file. This is to handle .rela.bss and
- .rela.plt. We must create it in
- create_dynamic_sections, because it must be created
- before the linker maps input sections to output
- sections. The linker does that before
- adjust_dynamic_symbol is called, and it is that
- function which decides whether anything needs to go
- into these sections. */
- strip = true;
- }
- else
- {
- /* We use the reloc_count field as a counter if we need
- to copy relocs into the output file. */
- s->reloc_count = 0;
- }
- }
- else if (s != htab->elf.splt
- && s != htab->elf.sgot
- && s != htab->elf.sgotplt
- && s != htab->elf.sdynbss
- && s != htab->elf.sdynrelro)
- {
- /* It's not one of our sections, so don't allocate space. */
- continue;
- }
- if (strip)
- {
- s->flags |= SEC_EXCLUDE;
- continue;
- }
- /* Allocate memory for the section contents. */
- /* FIXME: This should be a call to bfd_alloc not bfd_zalloc.
- Unused entries should be reclaimed before the section's contents
- are written out, but at the moment this does not happen. Thus in
- order to prevent writing out garbage, we initialise the section's
- contents to zero. */
- s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
- if (s->contents == NULL && s->size != 0)
- return false;
- }
- /* ??? Force DF_BIND_NOW? */
- info->flags |= DF_BIND_NOW;
- return _bfd_elf_add_dynamic_tags (output_bfd, info, true);
- }
- /* Finish up dynamic symbol handling. We set the contents of various
- dynamic sections here. */
- static bool
- microblaze_elf_finish_dynamic_symbol (bfd *output_bfd,
- struct bfd_link_info *info,
- struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym)
- {
- struct elf32_mb_link_hash_table *htab;
- struct elf32_mb_link_hash_entry *eh = elf32_mb_hash_entry(h);
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- if (h->plt.offset != (bfd_vma) -1)
- {
- asection *splt;
- asection *srela;
- asection *sgotplt;
- Elf_Internal_Rela rela;
- bfd_byte *loc;
- bfd_vma plt_index;
- bfd_vma got_offset;
- bfd_vma got_addr;
- /* This symbol has an entry in the procedure linkage table. Set
- it up. */
- BFD_ASSERT (h->dynindx != -1);
- splt = htab->elf.splt;
- srela = htab->elf.srelplt;
- sgotplt = htab->elf.sgotplt;
- BFD_ASSERT (splt != NULL && srela != NULL && sgotplt != NULL);
- plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; /* first entry reserved. */
- got_offset = (plt_index + 3) * 4; /* 3 reserved ??? */
- got_addr = got_offset;
- /* For non-PIC objects we need absolute address of the GOT entry. */
- if (!bfd_link_pic (info))
- got_addr += sgotplt->output_section->vma + sgotplt->output_offset;
- /* Fill in the entry in the procedure linkage table. */
- bfd_put_32 (output_bfd, PLT_ENTRY_WORD_0 + ((got_addr >> 16) & 0xffff),
- splt->contents + h->plt.offset);
- if (bfd_link_pic (info))
- bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1 + (got_addr & 0xffff),
- splt->contents + h->plt.offset + 4);
- else
- bfd_put_32 (output_bfd, PLT_ENTRY_WORD_1_NOPIC + (got_addr & 0xffff),
- splt->contents + h->plt.offset + 4);
- bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_2,
- splt->contents + h->plt.offset + 8);
- bfd_put_32 (output_bfd, (bfd_vma) PLT_ENTRY_WORD_3,
- splt->contents + h->plt.offset + 12);
- /* Any additions to the .got section??? */
- /* bfd_put_32 (output_bfd,
- splt->output_section->vma + splt->output_offset + h->plt.offset + 4,
- sgotplt->contents + got_offset); */
- /* Fill in the entry in the .rela.plt section. */
- rela.r_offset = (sgotplt->output_section->vma
- + sgotplt->output_offset
- + got_offset);
- rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_JUMP_SLOT);
- rela.r_addend = 0;
- loc = srela->contents;
- loc += plt_index * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
- if (!h->def_regular)
- {
- /* Mark the symbol as undefined, rather than as defined in
- the .plt section. Zero the value. */
- sym->st_shndx = SHN_UNDEF;
- sym->st_value = 0;
- }
- }
- /* h->got.refcount to be checked ? */
- if (h->got.offset != (bfd_vma) -1 &&
- ! ((h->got.offset & 1) ||
- IS_TLS_LD(eh->tls_mask) || IS_TLS_GD(eh->tls_mask)))
- {
- asection *sgot;
- asection *srela;
- bfd_vma offset;
- /* This symbol has an entry in the global offset table. Set it
- up. */
- sgot = htab->elf.sgot;
- srela = htab->elf.srelgot;
- BFD_ASSERT (sgot != NULL && srela != NULL);
- offset = (sgot->output_section->vma + sgot->output_offset
- + (h->got.offset &~ (bfd_vma) 1));
- /* If this is a -Bsymbolic link, and the symbol is defined
- locally, we just want to emit a RELATIVE reloc. Likewise if
- the symbol was forced to be local because of a version file.
- The entry in the global offset table will already have been
- initialized in the relocate_section function. */
- if (bfd_link_pic (info)
- && ((info->symbolic && h->def_regular)
- || h->dynindx == -1))
- {
- asection *sec = h->root.u.def.section;
- bfd_vma value;
- value = h->root.u.def.value;
- if (sec->output_section != NULL)
- /* PR 21180: If the output section is NULL, then the symbol is no
- longer needed, and in theory the GOT entry is redundant. But
- it is too late to change our minds now... */
- value += sec->output_section->vma + sec->output_offset;
- microblaze_elf_output_dynamic_relocation (output_bfd,
- srela, srela->reloc_count++,
- /* symindex= */ 0,
- R_MICROBLAZE_REL, offset,
- value);
- }
- else
- {
- microblaze_elf_output_dynamic_relocation (output_bfd,
- srela, srela->reloc_count++,
- h->dynindx,
- R_MICROBLAZE_GLOB_DAT,
- offset, 0);
- }
- bfd_put_32 (output_bfd, (bfd_vma) 0,
- sgot->contents + (h->got.offset &~ (bfd_vma) 1));
- }
- if (h->needs_copy)
- {
- asection *s;
- Elf_Internal_Rela rela;
- bfd_byte *loc;
- /* This symbols needs a copy reloc. Set it up. */
- BFD_ASSERT (h->dynindx != -1);
- rela.r_offset = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
- rela.r_info = ELF32_R_INFO (h->dynindx, R_MICROBLAZE_COPY);
- rela.r_addend = 0;
- if (h->root.u.def.section == htab->elf.sdynrelro)
- s = htab->elf.sreldynrelro;
- else
- s = htab->elf.srelbss;
- loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
- bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
- }
- /* Mark some specially defined symbols as absolute. */
- if (h == htab->elf.hdynamic
- || h == htab->elf.hgot
- || h == htab->elf.hplt)
- sym->st_shndx = SHN_ABS;
- return true;
- }
- /* Finish up the dynamic sections. */
- static bool
- microblaze_elf_finish_dynamic_sections (bfd *output_bfd,
- struct bfd_link_info *info)
- {
- bfd *dynobj;
- asection *sdyn, *sgot;
- struct elf32_mb_link_hash_table *htab;
- htab = elf32_mb_hash_table (info);
- if (htab == NULL)
- return false;
- dynobj = htab->elf.dynobj;
- sdyn = bfd_get_linker_section (dynobj, ".dynamic");
- if (htab->elf.dynamic_sections_created)
- {
- asection *splt;
- Elf32_External_Dyn *dyncon, *dynconend;
- dyncon = (Elf32_External_Dyn *) sdyn->contents;
- dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
- for (; dyncon < dynconend; dyncon++)
- {
- Elf_Internal_Dyn dyn;
- asection *s;
- bool size;
- bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
- switch (dyn.d_tag)
- {
- case DT_PLTGOT:
- s = htab->elf.sgotplt;
- size = false;
- break;
- case DT_PLTRELSZ:
- s = htab->elf.srelplt;
- size = true;
- break;
- case DT_JMPREL:
- s = htab->elf.srelplt;
- size = false;
- break;
- default:
- continue;
- }
- if (s == NULL)
- dyn.d_un.d_val = 0;
- else
- {
- if (!size)
- dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
- else
- dyn.d_un.d_val = s->size;
- }
- bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
- }
- splt = htab->elf.splt;
- BFD_ASSERT (splt != NULL && sdyn != NULL);
- /* Clear the first entry in the procedure linkage table,
- and put a nop in the last four bytes. */
- if (splt->size > 0)
- {
- memset (splt->contents, 0, PLT_ENTRY_SIZE);
- bfd_put_32 (output_bfd, (bfd_vma) 0x80000000 /* nop. */,
- splt->contents + splt->size - 4);
- if (splt->output_section != bfd_abs_section_ptr)
- elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
- }
- }
- /* Set the first entry in the global offset table to the address of
- the dynamic section. */
- sgot = htab->elf.sgotplt;
- if (sgot && sgot->size > 0)
- {
- if (sdyn == NULL)
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
- else
- bfd_put_32 (output_bfd,
- sdyn->output_section->vma + sdyn->output_offset,
- sgot->contents);
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
- }
- if (htab->elf.sgot && htab->elf.sgot->size > 0)
- elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4;
- return true;
- }
- /* Hook called by the linker routine which adds symbols from an object
- file. We use it to put .comm items in .sbss, and not .bss. */
- static bool
- microblaze_elf_add_symbol_hook (bfd *abfd,
- struct bfd_link_info *info,
- Elf_Internal_Sym *sym,
- const char **namep ATTRIBUTE_UNUSED,
- flagword *flagsp ATTRIBUTE_UNUSED,
- asection **secp,
- bfd_vma *valp)
- {
- if (sym->st_shndx == SHN_COMMON
- && !bfd_link_relocatable (info)
- && sym->st_size <= elf_gp_size (abfd))
- {
- /* Common symbols less than or equal to -G nn bytes are automatically
- put into .sbss. */
- *secp = bfd_make_section_old_way (abfd, ".sbss");
- if (*secp == NULL
- || !bfd_set_section_flags (*secp, SEC_IS_COMMON | SEC_SMALL_DATA))
- return false;
- *valp = sym->st_size;
- }
- return true;
- }
- #define TARGET_LITTLE_SYM microblaze_elf32_le_vec
- #define TARGET_LITTLE_NAME "elf32-microblazeel"
- #define TARGET_BIG_SYM microblaze_elf32_vec
- #define TARGET_BIG_NAME "elf32-microblaze"
- #define ELF_ARCH bfd_arch_microblaze
- #define ELF_TARGET_ID MICROBLAZE_ELF_DATA
- #define ELF_MACHINE_CODE EM_MICROBLAZE
- #define ELF_MACHINE_ALT1 EM_MICROBLAZE_OLD
- #define ELF_MAXPAGESIZE 0x1000
- #define elf_info_to_howto microblaze_elf_info_to_howto
- #define elf_info_to_howto_rel NULL
- #define bfd_elf32_bfd_reloc_type_lookup microblaze_elf_reloc_type_lookup
- #define bfd_elf32_bfd_is_local_label_name microblaze_elf_is_local_label_name
- #define bfd_elf32_new_section_hook microblaze_elf_new_section_hook
- #define elf_backend_relocate_section microblaze_elf_relocate_section
- #define bfd_elf32_bfd_relax_section microblaze_elf_relax_section
- #define bfd_elf32_bfd_merge_private_bfd_data _bfd_generic_verify_endian_match
- #define bfd_elf32_bfd_reloc_name_lookup microblaze_elf_reloc_name_lookup
- #define elf_backend_gc_mark_hook microblaze_elf_gc_mark_hook
- #define elf_backend_check_relocs microblaze_elf_check_relocs
- #define elf_backend_copy_indirect_symbol microblaze_elf_copy_indirect_symbol
- #define bfd_elf32_bfd_link_hash_table_create microblaze_elf_link_hash_table_create
- #define elf_backend_can_gc_sections 1
- #define elf_backend_can_refcount 1
- #define elf_backend_want_got_plt 1
- #define elf_backend_plt_readonly 1
- #define elf_backend_got_header_size 12
- #define elf_backend_want_dynrelro 1
- #define elf_backend_rela_normal 1
- #define elf_backend_dtrel_excludes_plt 1
- #define elf_backend_adjust_dynamic_symbol microblaze_elf_adjust_dynamic_symbol
- #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections
- #define elf_backend_finish_dynamic_sections microblaze_elf_finish_dynamic_sections
- #define elf_backend_finish_dynamic_symbol microblaze_elf_finish_dynamic_symbol
- #define elf_backend_size_dynamic_sections microblaze_elf_size_dynamic_sections
- #define elf_backend_add_symbol_hook microblaze_elf_add_symbol_hook
- #include "elf32-target.h"
|