12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112 |
- /* Altera Nios II assembler.
- Copyright (C) 2012-2015 Free Software Foundation, Inc.
- Contributed by Nigel Gray (ngray@altera.com).
- Contributed by Mentor Graphics, Inc.
- This file is part of GAS, the GNU Assembler.
- GAS 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, or (at your option)
- any later version.
- GAS 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 GAS; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
- #include "as.h"
- #include "opcode/nios2.h"
- #include "elf/nios2.h"
- #include "tc-nios2.h"
- #include "bfd.h"
- #include "libbfd.h"
- #include "dwarf2dbg.h"
- #include "subsegs.h"
- #include "safe-ctype.h"
- #include "dw2gencfi.h"
- #ifndef OBJ_ELF
- /* We are not supporting any other target so we throw a compile time error. */
- OBJ_ELF not defined
- #endif
- /* We can choose our endianness at run-time, regardless of configuration. */
- extern int target_big_endian;
- /* This array holds the chars that always start a comment. If the
- pre-processor is disabled, these aren't very useful. */
- const char comment_chars[] = "#";
- /* This array holds the chars that only start a comment at the beginning of
- a line. If the line seems to have the form '# 123 filename'
- .line and .file directives will appear in the pre-processed output. */
- /* Note that input_file.c hand checks for '#' at the beginning of the
- first line of the input file. This is because the compiler outputs
- #NO_APP at the beginning of its output. */
- /* Also note that C style comments are always supported. */
- const char line_comment_chars[] = "#";
- /* This array holds machine specific line separator characters. */
- const char line_separator_chars[] = ";";
- /* Chars that can be used to separate mant from exp in floating point nums. */
- const char EXP_CHARS[] = "eE";
- /* Chars that mean this number is a floating point constant. */
- /* As in 0f12.456 */
- /* or 0d1.2345e12 */
- const char FLT_CHARS[] = "rRsSfFdDxXpP";
- /* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be
- changed in read.c. Ideally it shouldn't have to know about it at all,
- but nothing is ideal around here. */
- /* Machine-dependent command-line options. */
- const char *md_shortopts = "r";
- struct option md_longopts[] = {
- #define OPTION_RELAX_ALL (OPTION_MD_BASE + 0)
- {"relax-all", no_argument, NULL, OPTION_RELAX_ALL},
- #define OPTION_NORELAX (OPTION_MD_BASE + 1)
- {"no-relax", no_argument, NULL, OPTION_NORELAX},
- #define OPTION_RELAX_SECTION (OPTION_MD_BASE + 2)
- {"relax-section", no_argument, NULL, OPTION_RELAX_SECTION},
- #define OPTION_EB (OPTION_MD_BASE + 3)
- {"EB", no_argument, NULL, OPTION_EB},
- #define OPTION_EL (OPTION_MD_BASE + 4)
- {"EL", no_argument, NULL, OPTION_EL},
- #define OPTION_MARCH (OPTION_MD_BASE + 5)
- {"march", required_argument, NULL, OPTION_MARCH}
- };
- size_t md_longopts_size = sizeof (md_longopts);
- /* The assembler supports three different relaxation modes, controlled by
- command-line options. */
- typedef enum
- {
- relax_section = 0,
- relax_none,
- relax_all
- } relax_optionT;
- /* Struct contains all assembler options set with .set. */
- struct
- {
- /* .set noat -> noat = 1 allows assembly code to use at without warning
- and macro expansions generate a warning.
- .set at -> noat = 0, assembly code using at warn but macro expansions
- do not generate warnings. */
- bfd_boolean noat;
- /* .set nobreak -> nobreak = 1 allows assembly code to use ba,bt without
- warning.
- .set break -> nobreak = 0, assembly code using ba,bt warns. */
- bfd_boolean nobreak;
- /* .cmd line option -relax-all allows all branches and calls to be replaced
- with longer versions.
- -no-relax inhibits branch/call conversion.
- The default value is relax_section, which relaxes branches within
- a section. */
- relax_optionT relax;
- } nios2_as_options = {FALSE, FALSE, relax_section};
- typedef struct nios2_insn_reloc
- {
- /* Any expression in the instruction is parsed into this field,
- which is passed to fix_new_exp() to generate a fixup. */
- expressionS reloc_expression;
- /* The type of the relocation to be applied. */
- bfd_reloc_code_real_type reloc_type;
- /* PC-relative. */
- unsigned int reloc_pcrel;
- /* The next relocation to be applied to the instruction. */
- struct nios2_insn_reloc *reloc_next;
- } nios2_insn_relocS;
- /* This struct is used to hold state when assembling instructions. */
- typedef struct nios2_insn_info
- {
- /* Assembled instruction. */
- unsigned long insn_code;
- /* Constant bits masked into insn_code for self-check mode. */
- unsigned long constant_bits;
- /* Pointer to the relevant bit of the opcode table. */
- const struct nios2_opcode *insn_nios2_opcode;
- /* After parsing ptrs to the tokens in the instruction fill this array
- it is terminated with a null pointer (hence the first +1).
- The second +1 is because in some parts of the code the opcode
- is not counted as a token, but still placed in this array. */
- const char *insn_tokens[NIOS2_MAX_INSN_TOKENS + 1 + 1];
- /* This holds information used to generate fixups
- and eventually relocations if it is not null. */
- nios2_insn_relocS *insn_reloc;
- } nios2_insn_infoS;
- /* This struct is used to convert Nios II pseudo-ops into the
- corresponding real op. */
- typedef struct nios2_ps_insn_info
- {
- /* Map this pseudo_op... */
- const char *pseudo_insn;
- /* ...to this real instruction. */
- const char *insn;
- /* Call this function to modify the operands.... */
- void (*arg_modifer_func) (char ** parsed_args, const char *arg, int num,
- int start);
- /* ...with these arguments. */
- const char *arg_modifier;
- int num;
- int index;
- /* If arg_modifier_func allocates new memory, provide this function
- to free it afterwards. */
- void (*arg_cleanup_func) (char **parsed_args, int num, int start);
- } nios2_ps_insn_infoS;
- /* Opcode hash table. */
- static struct hash_control *nios2_opcode_hash = NULL;
- #define nios2_opcode_lookup(NAME) \
- ((struct nios2_opcode *) hash_find (nios2_opcode_hash, (NAME)))
- /* Register hash table. */
- static struct hash_control *nios2_reg_hash = NULL;
- #define nios2_reg_lookup(NAME) \
- ((struct nios2_reg *) hash_find (nios2_reg_hash, (NAME)))
- /* Pseudo-op hash table. */
- static struct hash_control *nios2_ps_hash = NULL;
- #define nios2_ps_lookup(NAME) \
- ((nios2_ps_insn_infoS *) hash_find (nios2_ps_hash, (NAME)))
- /* The known current alignment of the current section. */
- static int nios2_current_align;
- static segT nios2_current_align_seg;
- static int nios2_auto_align_on = 1;
- /* The last seen label in the current section. This is used to auto-align
- labels preceeding instructions. */
- static symbolS *nios2_last_label;
- /* If we saw a 16-bit CDX instruction, we can align on 2-byte boundaries
- instead of 4-bytes. Use this to keep track of the minimum power-of-2
- alignment. */
- static int nios2_min_align = 2;
- #ifdef OBJ_ELF
- /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
- symbolS *GOT_symbol;
- #endif
- /* The processor architecture value, EF_NIOS2_ARCH_R1 by default. */
- static int nios2_architecture = EF_NIOS2_ARCH_R1;
- /** Utility routines. */
- /* Function md_chars_to_number takes the sequence of
- bytes in buf and returns the corresponding value
- in an int. n must be 1, 2 or 4. */
- static valueT
- md_chars_to_number (char *buf, int n)
- {
- int i;
- valueT val;
- gas_assert (n == 1 || n == 2 || n == 4);
- val = 0;
- if (target_big_endian)
- for (i = 0; i < n; ++i)
- val = val | ((buf[i] & 0xff) << 8 * (n - (i + 1)));
- else
- for (i = 0; i < n; ++i)
- val = val | ((buf[i] & 0xff) << 8 * i);
- return val;
- }
- /* This function turns a C long int, short int or char
- into the series of bytes that represent the number
- on the target machine. */
- void
- md_number_to_chars (char *buf, valueT val, int n)
- {
- gas_assert (n == 1 || n == 2 || n == 4 || n == 8);
- if (target_big_endian)
- number_to_chars_bigendian (buf, val, n);
- else
- number_to_chars_littleendian (buf, val, n);
- }
- /* Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
- char *
- md_atof (int type, char *litP, int *sizeP)
- {
- int prec;
- LITTLENUM_TYPE words[4];
- char *t;
- int i;
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
- case 'd':
- prec = 4;
- break;
- default:
- *sizeP = 0;
- return _("bad call to md_atof");
- }
- t = atof_ieee (input_line_pointer, type, words);
- if (t)
- input_line_pointer = t;
- *sizeP = prec * 2;
- if (! target_big_endian)
- for (i = prec - 1; i >= 0; i--, litP += 2)
- md_number_to_chars (litP, (valueT) words[i], 2);
- else
- for (i = 0; i < prec; i++, litP += 2)
- md_number_to_chars (litP, (valueT) words[i], 2);
- return NULL;
- }
- /* Return true if STR starts with PREFIX, which should be a string literal. */
- #define strprefix(STR, PREFIX) \
- (strncmp ((STR), PREFIX, strlen (PREFIX)) == 0)
- /* Return true if STR is prefixed with a special relocation operator. */
- static int
- nios2_special_relocation_p (const char *str)
- {
- return (strprefix (str, "%lo")
- || strprefix (str, "%hi")
- || strprefix (str, "%hiadj")
- || strprefix (str, "%gprel")
- || strprefix (str, "%got")
- || strprefix (str, "%call")
- || strprefix (str, "%gotoff_lo")
- || strprefix (str, "%gotoff_hiadj")
- || strprefix (str, "%tls_gd")
- || strprefix (str, "%tls_ldm")
- || strprefix (str, "%tls_ldo")
- || strprefix (str, "%tls_ie")
- || strprefix (str, "%tls_le")
- || strprefix (str, "%gotoff"));
- }
- /* nop fill patterns for text section. */
- static char const nop_r1[4] = { 0x3a, 0x88, 0x01, 0x00 };
- static char const nop_r2[4] = { 0x20, 0x00, 0x00, 0xc4 };
- static char const nop_r2_cdx[2] = { 0x3b, 0x00 };
- static char const *nop32 = nop_r1;
- static char const *nop16 = NULL;
- /* Handles all machine-dependent alignment needs. */
- static void
- nios2_align (int log_size, const char *pfill, symbolS *label)
- {
- int align;
- long max_alignment = 15;
- /* The front end is prone to changing segments out from under us
- temporarily when -g is in effect. */
- int switched_seg_p = (nios2_current_align_seg != now_seg);
- align = log_size;
- if (align > max_alignment)
- {
- align = max_alignment;
- as_bad (_("Alignment too large: %d. assumed"), align);
- }
- else if (align < 0)
- {
- as_warn (_("Alignment negative: 0 assumed"));
- align = 0;
- }
- if (align != 0)
- {
- if (subseg_text_p (now_seg) && align >= nios2_min_align)
- {
- /* First, make sure we're on the minimum boundary, in case
- someone has been putting .byte values the text section. */
- if (nios2_current_align < nios2_min_align || switched_seg_p)
- frag_align (nios2_min_align, 0, 0);
- /* If we might be on a 2-byte boundary, first align to a
- 4-byte boundary using the 2-byte nop as fill. */
- if (nios2_min_align == 1
- && align > nios2_min_align
- && pfill == nop32 )
- {
- gas_assert (nop16);
- frag_align_pattern (2, nop16, 2, 0);
- }
- /* Now fill in the alignment pattern. */
- if (pfill != NULL)
- frag_align_pattern (align, pfill, 4, 0);
- else
- frag_align (align, 0, 0);
- }
- else
- frag_align (align, 0, 0);
- if (!switched_seg_p)
- nios2_current_align = align;
- /* If the last label was in a different section we can't align it. */
- if (label != NULL && !switched_seg_p)
- {
- symbolS *sym;
- int label_seen = FALSE;
- struct frag *old_frag;
- valueT old_value;
- valueT new_value;
- gas_assert (S_GET_SEGMENT (label) == now_seg);
- old_frag = symbol_get_frag (label);
- old_value = S_GET_VALUE (label);
- new_value = (valueT) frag_now_fix ();
- /* It is possible to have more than one label at a particular
- address, especially if debugging is enabled, so we must
- take care to adjust all the labels at this address in this
- fragment. To save time we search from the end of the symbol
- list, backwards, since the symbols we are interested in are
- almost certainly the ones that were most recently added.
- Also to save time we stop searching once we have seen at least
- one matching label, and we encounter a label that is no longer
- in the target fragment. Note, this search is guaranteed to
- find at least one match when sym == label, so no special case
- code is necessary. */
- for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym))
- if (symbol_get_frag (sym) == old_frag
- && S_GET_VALUE (sym) == old_value)
- {
- label_seen = TRUE;
- symbol_set_frag (sym, frag_now);
- S_SET_VALUE (sym, new_value);
- }
- else if (label_seen && symbol_get_frag (sym) != old_frag)
- break;
- }
- record_alignment (now_seg, align);
- }
- }
- /** Support for self-check mode. */
- /* Mode of the assembler. */
- typedef enum
- {
- NIOS2_MODE_ASSEMBLE, /* Ordinary operation. */
- NIOS2_MODE_TEST /* Hidden mode used for self testing. */
- } NIOS2_MODE;
- static NIOS2_MODE nios2_mode = NIOS2_MODE_ASSEMBLE;
- /* This function is used to in self-checking mode
- to check the assembled instruction
- opcode should be the assembled opcode, and exp_opcode
- the parsed string representing the expected opcode. */
- static void
- nios2_check_assembly (unsigned int opcode, const char *exp_opcode)
- {
- if (nios2_mode == NIOS2_MODE_TEST)
- {
- if (exp_opcode == NULL)
- as_bad (_("expecting opcode string in self test mode"));
- else if (opcode != strtoul (exp_opcode, NULL, 16))
- as_bad (_("assembly 0x%08x, expected %s"), opcode, exp_opcode);
- }
- }
- /** Support for machine-dependent assembler directives. */
- /* Handle the .align pseudo-op. This aligns to a power of two. It
- also adjusts any current instruction label. We treat this the same
- way the MIPS port does: .align 0 turns off auto alignment. */
- static void
- s_nios2_align (int ignore ATTRIBUTE_UNUSED)
- {
- int align;
- char fill;
- const char *pfill = NULL;
- long max_alignment = 15;
- align = get_absolute_expression ();
- if (align > max_alignment)
- {
- align = max_alignment;
- as_bad (_("Alignment too large: %d. assumed"), align);
- }
- else if (align < 0)
- {
- as_warn (_("Alignment negative: 0 assumed"));
- align = 0;
- }
- if (*input_line_pointer == ',')
- {
- input_line_pointer++;
- fill = get_absolute_expression ();
- pfill = (const char *) &fill;
- }
- else if (subseg_text_p (now_seg))
- pfill = (const char *) nop32;
- else
- {
- pfill = NULL;
- nios2_last_label = NULL;
- }
- if (align != 0)
- {
- nios2_auto_align_on = 1;
- nios2_align (align, pfill, nios2_last_label);
- nios2_last_label = NULL;
- }
- else
- nios2_auto_align_on = 0;
- demand_empty_rest_of_line ();
- }
- /* Handle the .text pseudo-op. This is like the usual one, but it
- clears the saved last label and resets known alignment. */
- static void
- s_nios2_text (int i)
- {
- s_text (i);
- nios2_last_label = NULL;
- nios2_current_align = 0;
- nios2_current_align_seg = now_seg;
- }
- /* Handle the .data pseudo-op. This is like the usual one, but it
- clears the saved last label and resets known alignment. */
- static void
- s_nios2_data (int i)
- {
- s_data (i);
- nios2_last_label = NULL;
- nios2_current_align = 0;
- nios2_current_align_seg = now_seg;
- }
- /* Handle the .section pseudo-op. This is like the usual one, but it
- clears the saved last label and resets known alignment. */
- static void
- s_nios2_section (int ignore)
- {
- obj_elf_section (ignore);
- nios2_last_label = NULL;
- nios2_current_align = 0;
- nios2_current_align_seg = now_seg;
- }
- /* Explicitly unaligned cons. */
- static void
- s_nios2_ucons (int nbytes)
- {
- int hold;
- hold = nios2_auto_align_on;
- nios2_auto_align_on = 0;
- cons (nbytes);
- nios2_auto_align_on = hold;
- }
- /* Handle the .sdata directive. */
- static void
- s_nios2_sdata (int ignore ATTRIBUTE_UNUSED)
- {
- get_absolute_expression (); /* Ignored. */
- subseg_new (".sdata", 0);
- demand_empty_rest_of_line ();
- }
- /* .set sets assembler options eg noat/at and is also used
- to set symbol values (.equ, .equiv ). */
- static void
- s_nios2_set (int equiv)
- {
- char *save = input_line_pointer;
- char *directive;
- char delim = get_symbol_name (&directive);
- char *endline = input_line_pointer;
- (void) restore_line_pointer (delim);
- /* We only want to handle ".set XXX" if the
- user has tried ".set XXX, YYY" they are not
- trying a directive. This prevents
- us from polluting the name space. */
- SKIP_WHITESPACE ();
- if (is_end_of_line[(unsigned char) *input_line_pointer])
- {
- bfd_boolean done = TRUE;
- *endline = 0;
- if (!strcmp (directive, "noat"))
- nios2_as_options.noat = TRUE;
- else if (!strcmp (directive, "at"))
- nios2_as_options.noat = FALSE;
- else if (!strcmp (directive, "nobreak"))
- nios2_as_options.nobreak = TRUE;
- else if (!strcmp (directive, "break"))
- nios2_as_options.nobreak = FALSE;
- else if (!strcmp (directive, "norelax"))
- nios2_as_options.relax = relax_none;
- else if (!strcmp (directive, "relaxsection"))
- nios2_as_options.relax = relax_section;
- else if (!strcmp (directive, "relaxall"))
- nios2_as_options.relax = relax_all;
- else
- done = FALSE;
- if (done)
- {
- *endline = delim;
- demand_empty_rest_of_line ();
- return;
- }
- }
- /* If we fall through to here, either we have ".set XXX, YYY"
- or we have ".set XXX" where XXX is unknown or we have
- a syntax error. */
- input_line_pointer = save;
- s_set (equiv);
- }
- /* Machine-dependent assembler directives.
- Format of each entry is:
- { "directive", handler_func, param } */
- const pseudo_typeS md_pseudo_table[] = {
- {"align", s_nios2_align, 0},
- {"text", s_nios2_text, 0},
- {"data", s_nios2_data, 0},
- {"section", s_nios2_section, 0},
- {"section.s", s_nios2_section, 0},
- {"sect", s_nios2_section, 0},
- {"sect.s", s_nios2_section, 0},
- /* .dword and .half are included for compatibility with MIPS. */
- {"dword", cons, 8},
- {"half", cons, 2},
- /* NIOS2 native word size is 4 bytes, so we override
- the GAS default of 2. */
- {"word", cons, 4},
- /* Explicitly unaligned directives. */
- {"2byte", s_nios2_ucons, 2},
- {"4byte", s_nios2_ucons, 4},
- {"8byte", s_nios2_ucons, 8},
- {"16byte", s_nios2_ucons, 16},
- #ifdef OBJ_ELF
- {"sdata", s_nios2_sdata, 0},
- #endif
- {"set", s_nios2_set, 0},
- {NULL, NULL, 0}
- };
- /** Relaxation support. */
- /* We support two relaxation modes: a limited PC-relative mode with
- -relax-section (the default), and an absolute jump mode with -relax-all.
- Nios II PC-relative branch instructions only support 16-bit offsets.
- And, there's no good way to add a 32-bit constant to the PC without
- using two registers.
- To deal with this, for the pc-relative relaxation mode we convert
- br label
- into a series of 16-bit adds, like:
- nextpc at
- addi at, at, 32767
- ...
- addi at, at, remainder
- jmp at
- Similarly, conditional branches are converted from
- b(condition) r, s, label
- into a series like:
- b(opposite condition) r, s, skip
- nextpc at
- addi at, at, 32767
- ...
- addi at, at, remainder
- jmp at
- skip:
- The compiler can do a better job, either by converting the branch
- directly into a JMP (going through the GOT for PIC) or by allocating
- a second register for the 32-bit displacement.
- For the -relax-all relaxation mode, the conversions are
- movhi at, %hi(symbol+offset)
- ori at, %lo(symbol+offset)
- jmp at
- and
- b(opposite condition), r, s, skip
- movhi at, %hi(symbol+offset)
- ori at, %lo(symbol+offset)
- jmp at
- skip:
- respectively.
- 16-bit CDX branch instructions are relaxed first into equivalent
- 32-bit branches and then the above transformations are applied
- if necessary.
- */
- /* Arbitrarily limit the number of addis we can insert; we need to be able
- to specify the maximum growth size for each frag that contains a
- relaxable branch. There's no point in specifying a huge number here
- since that means the assembler needs to allocate that much extra
- memory for every branch, and almost no real code will ever need it.
- Plus, as already noted a better solution is to just use a jmp, or
- allocate a second register to hold a 32-bit displacement.
- FIXME: Rather than making this a constant, it could be controlled by
- a command-line argument. */
- #define RELAX_MAX_ADDI 32
- /* The fr_subtype field represents the target-specific relocation state.
- It has type relax_substateT (unsigned int). We use it to track the
- number of addis necessary, plus a bit to track whether this is a
- conditional branch and a bit for 16-bit CDX instructions.
- Regardless of the smaller RELAX_MAX_ADDI limit, we reserve 16 bits
- in the fr_subtype to encode the number of addis so that the whole
- theoretically-valid range is representable.
- For the -relax-all mode, N = 0 represents an in-range branch and N = 1
- represents a branch that needs to be relaxed. */
- #define UBRANCH (0 << 16)
- #define CBRANCH (1 << 16)
- #define CDXBRANCH (1 << 17)
- #define IS_CBRANCH(SUBTYPE) ((SUBTYPE) & CBRANCH)
- #define IS_UBRANCH(SUBTYPE) (!IS_CBRANCH (SUBTYPE))
- #define IS_CDXBRANCH(SUBTYPE) ((SUBTYPE) & CDXBRANCH)
- #define UBRANCH_SUBTYPE(N) (UBRANCH | (N))
- #define CBRANCH_SUBTYPE(N) (CBRANCH | (N))
- #define CDX_UBRANCH_SUBTYPE(N) (CDXBRANCH | UBRANCH | (N))
- #define CDX_CBRANCH_SUBTYPE(N) (CDXBRANCH | CBRANCH | (N))
- #define SUBTYPE_ADDIS(SUBTYPE) ((SUBTYPE) & 0xffff)
- /* For the -relax-section mode, unconditional branches require 2 extra i
- nstructions besides the addis, conditional branches require 3. */
- #define UBRANCH_ADDIS_TO_SIZE(N) (((N) + 2) * 4)
- #define CBRANCH_ADDIS_TO_SIZE(N) (((N) + 3) * 4)
- /* For the -relax-all mode, unconditional branches require 3 instructions
- and conditional branches require 4. */
- #define UBRANCH_JUMP_SIZE 12
- #define CBRANCH_JUMP_SIZE 16
- /* Maximum sizes of relaxation sequences. */
- #define UBRANCH_MAX_SIZE \
- (nios2_as_options.relax == relax_all \
- ? UBRANCH_JUMP_SIZE \
- : UBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI))
- #define CBRANCH_MAX_SIZE \
- (nios2_as_options.relax == relax_all \
- ? CBRANCH_JUMP_SIZE \
- : CBRANCH_ADDIS_TO_SIZE (RELAX_MAX_ADDI))
- /* Register number of AT, the assembler temporary. */
- #define AT_REGNUM 1
- /* Determine how many bytes are required to represent the sequence
- indicated by SUBTYPE. */
- static int
- nios2_relax_subtype_size (relax_substateT subtype)
- {
- int n = SUBTYPE_ADDIS (subtype);
- if (n == 0)
- /* Regular conditional/unconditional branch instruction. */
- return (IS_CDXBRANCH (subtype) ? 2 : 4);
- else if (nios2_as_options.relax == relax_all)
- return (IS_CBRANCH (subtype) ? CBRANCH_JUMP_SIZE : UBRANCH_JUMP_SIZE);
- else if (IS_CBRANCH (subtype))
- return CBRANCH_ADDIS_TO_SIZE (n);
- else
- return UBRANCH_ADDIS_TO_SIZE (n);
- }
- /* Estimate size of fragp before relaxation.
- This could also examine the offset in fragp and adjust
- fragp->fr_subtype, but we will do that in nios2_relax_frag anyway. */
- int
- md_estimate_size_before_relax (fragS *fragp, segT segment ATTRIBUTE_UNUSED)
- {
- return nios2_relax_subtype_size (fragp->fr_subtype);
- }
- /* Implement md_relax_frag, returning the change in size of the frag. */
- long
- nios2_relax_frag (segT segment, fragS *fragp, long stretch)
- {
- addressT target = fragp->fr_offset;
- relax_substateT subtype = fragp->fr_subtype;
- symbolS *symbolp = fragp->fr_symbol;
- if (symbolp)
- {
- fragS *sym_frag = symbol_get_frag (symbolp);
- offsetT offset;
- int n;
- bfd_boolean is_cdx = FALSE;
- target += S_GET_VALUE (symbolp);
- /* See comments in write.c:relax_frag about handling of stretch. */
- if (stretch != 0
- && sym_frag->relax_marker != fragp->relax_marker)
- {
- if (stretch < 0 || sym_frag->region == fragp->region)
- target += stretch;
- else if (target < fragp->fr_address)
- target = fragp->fr_next->fr_address + stretch;
- }
- /* We subtract fr_var (4 for 32-bit insns) because all pc relative
- branches are from the next instruction. */
- offset = target - fragp->fr_address - fragp->fr_fix - fragp->fr_var;
- if (IS_CDXBRANCH (subtype) && IS_UBRANCH (subtype)
- && offset >= -1024 && offset < 1024)
- /* PC-relative CDX branch with 11-bit offset. */
- is_cdx = TRUE;
- else if (IS_CDXBRANCH (subtype) && IS_CBRANCH (subtype)
- && offset >= -128 && offset < 128)
- /* PC-relative CDX branch with 8-bit offset. */
- is_cdx = TRUE;
- else if (offset >= -32768 && offset < 32768)
- /* Fits in PC-relative branch. */
- n = 0;
- else if (nios2_as_options.relax == relax_all)
- /* Convert to jump. */
- n = 1;
- else if (nios2_as_options.relax == relax_section
- && S_GET_SEGMENT (symbolp) == segment
- && S_IS_DEFINED (symbolp))
- /* Attempt a PC-relative relaxation on a branch to a defined
- symbol in the same segment. */
- {
- /* The relaxation for conditional branches is offset by 4
- bytes because we insert the inverted branch around the
- sequence. */
- if (IS_CBRANCH (subtype))
- offset = offset - 4;
- if (offset > 0)
- n = offset / 32767 + 1;
- else
- n = offset / -32768 + 1;
- /* Bail out immediately if relaxation has failed. If we try to
- defer the diagnostic to md_convert_frag, some pathological test
- cases (e.g. gcc/testsuite/gcc.c-torture/compile/20001226-1.c)
- apparently never converge. By returning 0 here we could pretend
- to the caller that nothing has changed, but that leaves things
- in an inconsistent state when we get to md_convert_frag. */
- if (n > RELAX_MAX_ADDI)
- {
- as_bad_where (fragp->fr_file, fragp->fr_line,
- _("branch offset out of range\n"));
- as_fatal (_("branch relaxation failed\n"));
- }
- }
- else
- /* We cannot handle this case, diagnose overflow later. */
- return 0;
- if (is_cdx)
- fragp->fr_subtype = subtype;
- else if (IS_CBRANCH (subtype))
- fragp->fr_subtype = CBRANCH_SUBTYPE (n);
- else
- fragp->fr_subtype = UBRANCH_SUBTYPE (n);
- return (nios2_relax_subtype_size (fragp->fr_subtype)
- - nios2_relax_subtype_size (subtype));
- }
- /* If we got here, it's probably an error. */
- return 0;
- }
- /* Complete fragp using the data from the relaxation pass. */
- void
- md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED,
- fragS *fragp)
- {
- char *buffer = fragp->fr_literal + fragp->fr_fix;
- relax_substateT subtype = fragp->fr_subtype;
- int n = SUBTYPE_ADDIS (subtype);
- addressT target = fragp->fr_offset;
- symbolS *symbolp = fragp->fr_symbol;
- offsetT offset;
- unsigned int addend_mask, addi_mask, op;
- offsetT addend, remainder;
- int i;
- bfd_boolean is_r2 = (bfd_get_mach (stdoutput) == bfd_mach_nios2r2);
- /* If this is a CDX branch we're not relaxing, just generate the fixup. */
- if (IS_CDXBRANCH (subtype))
- {
- gas_assert (is_r2);
- fix_new (fragp, fragp->fr_fix, 2, fragp->fr_symbol,
- fragp->fr_offset, 1,
- (IS_UBRANCH (subtype)
- ? BFD_RELOC_NIOS2_R2_I10_1_PCREL
- : BFD_RELOC_NIOS2_R2_T1I7_1_PCREL));
- fragp->fr_fix += 2;
- return;
- }
- /* If this is a CDX branch we are relaxing, turn it into an equivalent
- 32-bit branch and then fall through to the normal non-CDX cases. */
- if (fragp->fr_var == 2)
- {
- unsigned int opcode = md_chars_to_number (buffer, 2);
- gas_assert (is_r2);
- if (IS_CBRANCH (subtype))
- {
- unsigned int reg = nios2_r2_reg3_mappings[GET_IW_T1I7_A3 (opcode)];
- if (GET_IW_R2_OP (opcode) == R2_OP_BNEZ_N)
- opcode = MATCH_R2_BNE | SET_IW_F2I16_A (reg);
- else
- opcode = MATCH_R2_BEQ | SET_IW_F2I16_A (reg);
- }
- else
- opcode = MATCH_R2_BR;
- md_number_to_chars (buffer, opcode, 4);
- fragp->fr_var = 4;
- }
- /* If we didn't or can't relax, this is a regular branch instruction.
- We just need to generate the fixup for the symbol and offset. */
- if (n == 0)
- {
- fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol,
- fragp->fr_offset, 1, BFD_RELOC_16_PCREL);
- fragp->fr_fix += 4;
- return;
- }
- /* Replace the cbranch at fr_fix with one that has the opposite condition
- in order to jump around the block of instructions we'll be adding. */
- if (IS_CBRANCH (subtype))
- {
- unsigned int br_opcode;
- unsigned int old_op, new_op;
- int nbytes;
- /* Account for the nextpc and jmp in the pc-relative case, or the two
- load instructions and jump in the absolute case. */
- if (nios2_as_options.relax == relax_section)
- nbytes = (n + 2) * 4;
- else
- nbytes = 12;
- br_opcode = md_chars_to_number (buffer, 4);
- if (is_r2)
- {
- old_op = GET_IW_R2_OP (br_opcode);
- switch (old_op)
- {
- case R2_OP_BEQ:
- new_op = R2_OP_BNE;
- break;
- case R2_OP_BNE:
- new_op = R2_OP_BEQ;
- break;
- case R2_OP_BGE:
- new_op = R2_OP_BLT;
- break;
- case R2_OP_BGEU:
- new_op = R2_OP_BLTU;
- break;
- case R2_OP_BLT:
- new_op = R2_OP_BGE;
- break;
- case R2_OP_BLTU:
- new_op = R2_OP_BGEU;
- break;
- default:
- abort ();
- }
- br_opcode = ((br_opcode & ~IW_R2_OP_SHIFTED_MASK)
- | SET_IW_R2_OP (new_op));
- br_opcode = br_opcode | SET_IW_F2I16_IMM16 (nbytes);
- }
- else
- {
- old_op = GET_IW_R1_OP (br_opcode);
- switch (old_op)
- {
- case R1_OP_BEQ:
- new_op = R1_OP_BNE;
- break;
- case R1_OP_BNE:
- new_op = R1_OP_BEQ;
- break;
- case R1_OP_BGE:
- new_op = R1_OP_BLT;
- break;
- case R1_OP_BGEU:
- new_op = R1_OP_BLTU;
- break;
- case R1_OP_BLT:
- new_op = R1_OP_BGE;
- break;
- case R1_OP_BLTU:
- new_op = R1_OP_BGEU;
- break;
- default:
- abort ();
- }
- br_opcode = ((br_opcode & ~IW_R1_OP_SHIFTED_MASK)
- | SET_IW_R1_OP (new_op));
- br_opcode = br_opcode | SET_IW_I_IMM16 (nbytes);
- }
- md_number_to_chars (buffer, br_opcode, 4);
- fragp->fr_fix += 4;
- buffer += 4;
- }
- /* Load at for the PC-relative case. */
- if (nios2_as_options.relax == relax_section)
- {
- /* Insert the nextpc instruction. */
- if (is_r2)
- op = MATCH_R2_NEXTPC | SET_IW_F3X6L5_C (AT_REGNUM);
- else
- op = MATCH_R1_NEXTPC | SET_IW_R_C (AT_REGNUM);
- md_number_to_chars (buffer, op, 4);
- fragp->fr_fix += 4;
- buffer += 4;
- /* We need to know whether the offset is positive or negative. */
- target += S_GET_VALUE (symbolp);
- offset = target - fragp->fr_address - fragp->fr_fix;
- if (offset > 0)
- addend = 32767;
- else
- addend = -32768;
- if (is_r2)
- addend_mask = SET_IW_F2I16_IMM16 ((unsigned int)addend);
- else
- addend_mask = SET_IW_I_IMM16 ((unsigned int)addend);
- /* Insert n-1 addi instructions. */
- if (is_r2)
- addi_mask = (MATCH_R2_ADDI
- | SET_IW_F2I16_B (AT_REGNUM)
- | SET_IW_F2I16_A (AT_REGNUM));
- else
- addi_mask = (MATCH_R1_ADDI
- | SET_IW_I_B (AT_REGNUM)
- | SET_IW_I_A (AT_REGNUM));
- for (i = 0; i < n - 1; i ++)
- {
- md_number_to_chars (buffer, addi_mask | addend_mask, 4);
- fragp->fr_fix += 4;
- buffer += 4;
- }
- /* Insert the last addi instruction to hold the remainder. */
- remainder = offset - addend * (n - 1);
- gas_assert (remainder >= -32768 && remainder <= 32767);
- if (is_r2)
- addend_mask = SET_IW_F2I16_IMM16 ((unsigned int)remainder);
- else
- addend_mask = SET_IW_I_IMM16 ((unsigned int)remainder);
- md_number_to_chars (buffer, addi_mask | addend_mask, 4);
- fragp->fr_fix += 4;
- buffer += 4;
- }
- /* Load at for the absolute case. */
- else
- {
- if (is_r2)
- op = MATCH_R2_ORHI | SET_IW_F2I16_B (AT_REGNUM) | SET_IW_F2I16_A (0);
- else
- op = MATCH_R1_ORHI | SET_IW_I_B (AT_REGNUM) | SET_IW_I_A (0);
- md_number_to_chars (buffer, op, 4);
- fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset,
- 0, BFD_RELOC_NIOS2_HI16);
- fragp->fr_fix += 4;
- buffer += 4;
- if (is_r2)
- op = (MATCH_R2_ORI | SET_IW_F2I16_B (AT_REGNUM)
- | SET_IW_F2I16_A (AT_REGNUM));
- else
- op = (MATCH_R1_ORI | SET_IW_I_B (AT_REGNUM)
- | SET_IW_I_A (AT_REGNUM));
- md_number_to_chars (buffer, op, 4);
- fix_new (fragp, fragp->fr_fix, 4, fragp->fr_symbol, fragp->fr_offset,
- 0, BFD_RELOC_NIOS2_LO16);
- fragp->fr_fix += 4;
- buffer += 4;
- }
- /* Insert the jmp instruction. */
- if (is_r2)
- op = MATCH_R2_JMP | SET_IW_F3X6L5_A (AT_REGNUM);
- else
- op = MATCH_R1_JMP | SET_IW_R_A (AT_REGNUM);
- md_number_to_chars (buffer, op, 4);
- fragp->fr_fix += 4;
- buffer += 4;
- }
- /** Fixups and overflow checking. */
- /* Check a fixup for overflow. */
- static bfd_boolean
- nios2_check_overflow (valueT fixup, reloc_howto_type *howto)
- {
- /* If there is a rightshift, check that the low-order bits are
- zero before applying it. */
- if (howto->rightshift)
- {
- if ((~(~((valueT) 0) << howto->rightshift) & fixup)
- && howto->complain_on_overflow != complain_overflow_dont)
- return TRUE;
- fixup = ((signed)fixup) >> howto->rightshift;
- }
- /* Check for overflow - return TRUE if overflow, FALSE if not. */
- switch (howto->complain_on_overflow)
- {
- case complain_overflow_dont:
- break;
- case complain_overflow_bitfield:
- if ((fixup >> howto->bitsize) != 0
- && ((signed) fixup >> howto->bitsize) != -1)
- return TRUE;
- break;
- case complain_overflow_signed:
- if ((fixup & 0x80000000) > 0)
- {
- /* Check for negative overflow. */
- if ((signed) fixup < ((signed) ~0 << (howto->bitsize-1)))
- return TRUE;
- }
- else
- {
- /* Check for positive overflow. */
- if (fixup >= ((unsigned) 1 << (howto->bitsize - 1)))
- return TRUE;
- }
- break;
- case complain_overflow_unsigned:
- if ((fixup >> howto->bitsize) != 0)
- return TRUE;
- break;
- default:
- as_bad (_("error checking for overflow - broken assembler"));
- break;
- }
- return FALSE;
- }
- /* Emit diagnostic for fixup overflow. */
- static void
- nios2_diagnose_overflow (valueT fixup, reloc_howto_type *howto,
- fixS *fixP, valueT value)
- {
- if (fixP->fx_r_type == BFD_RELOC_8
- || fixP->fx_r_type == BFD_RELOC_16
- || fixP->fx_r_type == BFD_RELOC_32)
- /* These relocs are against data, not instructions. */
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("immediate value 0x%x truncated to 0x%x"),
- (unsigned int) fixup,
- (unsigned int) (~(~(valueT) 0 << howto->bitsize) & fixup));
- else
- {
- /* What opcode is the instruction? This will determine
- whether we check for overflow in immediate values
- and what error message we get. */
- const struct nios2_opcode *opcode;
- enum overflow_type overflow_msg_type;
- unsigned int range_min;
- unsigned int range_max;
- unsigned int address;
- opcode = nios2_find_opcode_hash (value, bfd_get_mach (stdoutput));
- gas_assert (opcode);
- gas_assert (fixP->fx_size == opcode->size);
- overflow_msg_type = opcode->overflow_msg;
- switch (overflow_msg_type)
- {
- case call_target_overflow:
- range_min
- = ((fixP->fx_frag->fr_address + fixP->fx_where) & 0xf0000000);
- range_max = range_min + 0x0fffffff;
- address = fixup | range_min;
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("call target address 0x%08x out of range 0x%08x to 0x%08x"),
- address, range_min, range_max);
- break;
- case branch_target_overflow:
- if (opcode->format == iw_i_type || opcode->format == iw_F2I16_type)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("branch offset %d out of range %d to %d"),
- (int)fixup, -32768, 32767);
- else
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("branch offset %d out of range"),
- (int)fixup);
- break;
- case address_offset_overflow:
- if (opcode->format == iw_i_type || opcode->format == iw_F2I16_type)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("%s offset %d out of range %d to %d"),
- opcode->name, (int)fixup, -32768, 32767);
- else
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("%s offset %d out of range"),
- opcode->name, (int)fixup);
- break;
- case signed_immed16_overflow:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("immediate value %d out of range %d to %d"),
- (int)fixup, -32768, 32767);
- break;
- case unsigned_immed16_overflow:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("immediate value %u out of range %u to %u"),
- (unsigned int)fixup, 0, 65535);
- break;
- case unsigned_immed5_overflow:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("immediate value %u out of range %u to %u"),
- (unsigned int)fixup, 0, 31);
- break;
- case signed_immed12_overflow:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("immediate value %d out of range %d to %d"),
- (int)fixup, -2048, 2047);
- break;
- case custom_opcode_overflow:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("custom instruction opcode %u out of range %u to %u"),
- (unsigned int)fixup, 0, 255);
- break;
- default:
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("overflow in immediate argument"));
- break;
- }
- }
- }
- /* Apply a fixup to the object file. */
- void
- md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
- {
- /* Assert that the fixup is one we can handle. */
- gas_assert (fixP != NULL && valP != NULL
- && (fixP->fx_r_type == BFD_RELOC_8
- || fixP->fx_r_type == BFD_RELOC_16
- || fixP->fx_r_type == BFD_RELOC_32
- || fixP->fx_r_type == BFD_RELOC_64
- || fixP->fx_r_type == BFD_RELOC_NIOS2_S16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_U16
- || fixP->fx_r_type == BFD_RELOC_16_PCREL
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26
- || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX
- || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6
- || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM8
- || fixP->fx_r_type == BFD_RELOC_NIOS2_HI16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_LO16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_HIADJ16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GPREL
- || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fixP->fx_r_type == BFD_RELOC_NIOS2_UJMP
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CJMP
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALLR
- || fixP->fx_r_type == BFD_RELOC_NIOS2_ALIGN
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF
- || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_LO
- || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_HA
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_LO
- || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_HA
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_S12
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_I10_1_PCREL
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1I7_1_PCREL
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1I7_2
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4_1
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T2I4_2
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_X1I7_2
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_X2L5
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_F1I5_2
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_L5I4X1
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1X1I6
- || fixP->fx_r_type == BFD_RELOC_NIOS2_R2_T1X1I6_2
- /* Add other relocs here as we generate them. */
- ));
- if (fixP->fx_r_type == BFD_RELOC_64)
- {
- /* We may reach here due to .8byte directives, but we never output
- BFD_RELOC_64; it must be resolved. */
- if (fixP->fx_addsy != NULL)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("cannot create 64-bit relocation"));
- else
- {
- md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
- *valP, 8);
- fixP->fx_done = 1;
- }
- return;
- }
- /* The value passed in valP can be the value of a fully
- resolved expression, or it can be the value of a partially
- resolved expression. In the former case, both fixP->fx_addsy
- and fixP->fx_subsy are NULL, and fixP->fx_offset == *valP, and
- we can fix up the instruction that fixP relates to.
- In the latter case, one or both of fixP->fx_addsy and
- fixP->fx_subsy are not NULL, and fixP->fx_offset may or may not
- equal *valP. We don't need to check for fixP->fx_subsy being null
- because the generic part of the assembler generates an error if
- it is not an absolute symbol. */
- if (fixP->fx_addsy != NULL)
- /* Partially resolved expression. */
- {
- fixP->fx_addnumber = fixP->fx_offset;
- fixP->fx_done = 0;
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_NIOS2_TLS_GD16:
- case BFD_RELOC_NIOS2_TLS_LDM16:
- case BFD_RELOC_NIOS2_TLS_LDO16:
- case BFD_RELOC_NIOS2_TLS_IE16:
- case BFD_RELOC_NIOS2_TLS_LE16:
- case BFD_RELOC_NIOS2_TLS_DTPMOD:
- case BFD_RELOC_NIOS2_TLS_DTPREL:
- case BFD_RELOC_NIOS2_TLS_TPREL:
- S_SET_THREAD_LOCAL (fixP->fx_addsy);
- break;
- default:
- break;
- }
- }
- else
- /* Fully resolved fixup. */
- {
- reloc_howto_type *howto
- = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
- if (howto == NULL)
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("relocation is not supported"));
- else
- {
- valueT fixup = *valP;
- valueT value;
- char *buf;
- /* If this is a pc-relative relocation, we need to
- subtract the current offset within the object file
- FIXME : for some reason fixP->fx_pcrel isn't 1 when it should be
- so I'm using the howto structure instead to determine this. */
- if (howto->pc_relative == 1)
- {
- fixup = (fixup - (fixP->fx_frag->fr_address + fixP->fx_where
- + fixP->fx_size));
- *valP = fixup;
- }
- /* Get the instruction or data to be fixed up. */
- buf = fixP->fx_frag->fr_literal + fixP->fx_where;
- value = md_chars_to_number (buf, fixP->fx_size);
- /* Check for overflow, emitting a diagnostic if necessary. */
- if (nios2_check_overflow (fixup, howto))
- nios2_diagnose_overflow (fixup, howto, fixP, value);
- /* Apply the right shift. */
- fixup = ((signed)fixup) >> howto->rightshift;
- /* Truncate the fixup to right size. */
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_NIOS2_HI16:
- fixup = (fixup >> 16) & 0xFFFF;
- break;
- case BFD_RELOC_NIOS2_LO16:
- fixup = fixup & 0xFFFF;
- break;
- case BFD_RELOC_NIOS2_HIADJ16:
- fixup = ((((fixup >> 16) & 0xFFFF) + ((fixup >> 15) & 0x01))
- & 0xFFFF);
- break;
- default:
- {
- int n = sizeof (fixup) * 8 - howto->bitsize;
- fixup = (fixup << n) >> n;
- break;
- }
- }
- /* Fix up the instruction. */
- value = (value & ~howto->dst_mask) | (fixup << howto->bitpos);
- md_number_to_chars (buf, value, fixP->fx_size);
- }
- fixP->fx_done = 1;
- }
- if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT)
- {
- fixP->fx_done = 0;
- if (fixP->fx_addsy
- && !S_IS_DEFINED (fixP->fx_addsy) && !S_IS_WEAK (fixP->fx_addsy))
- S_SET_WEAK (fixP->fx_addsy);
- }
- else if (fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- fixP->fx_done = 0;
- }
- /** Instruction parsing support. */
- /* General internal error routine. */
- static void
- bad_opcode (const struct nios2_opcode *op)
- {
- fprintf (stderr, _("internal error: broken opcode descriptor for `%s %s'\n"),
- op->name, op->args);
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- /* Special relocation directive strings. */
- struct nios2_special_relocS
- {
- const char *string;
- bfd_reloc_code_real_type reloc_type;
- };
- /* This table is sorted so that prefix strings are listed after the longer
- strings that include them -- e.g., %got after %got_hiadj, etc. */
- struct nios2_special_relocS nios2_special_reloc[] = {
- {"%hiadj", BFD_RELOC_NIOS2_HIADJ16},
- {"%hi", BFD_RELOC_NIOS2_HI16},
- {"%lo", BFD_RELOC_NIOS2_LO16},
- {"%gprel", BFD_RELOC_NIOS2_GPREL},
- {"%call_lo", BFD_RELOC_NIOS2_CALL_LO},
- {"%call_hiadj", BFD_RELOC_NIOS2_CALL_HA},
- {"%call", BFD_RELOC_NIOS2_CALL16},
- {"%gotoff_lo", BFD_RELOC_NIOS2_GOTOFF_LO},
- {"%gotoff_hiadj", BFD_RELOC_NIOS2_GOTOFF_HA},
- {"%gotoff", BFD_RELOC_NIOS2_GOTOFF},
- {"%got_hiadj", BFD_RELOC_NIOS2_GOT_HA},
- {"%got_lo", BFD_RELOC_NIOS2_GOT_LO},
- {"%got", BFD_RELOC_NIOS2_GOT16},
- {"%tls_gd", BFD_RELOC_NIOS2_TLS_GD16},
- {"%tls_ldm", BFD_RELOC_NIOS2_TLS_LDM16},
- {"%tls_ldo", BFD_RELOC_NIOS2_TLS_LDO16},
- {"%tls_ie", BFD_RELOC_NIOS2_TLS_IE16},
- {"%tls_le", BFD_RELOC_NIOS2_TLS_LE16},
- };
- #define NIOS2_NUM_SPECIAL_RELOCS \
- (sizeof(nios2_special_reloc)/sizeof(nios2_special_reloc[0]))
- const int nios2_num_special_relocs = NIOS2_NUM_SPECIAL_RELOCS;
- /* Creates a new nios2_insn_relocS and returns a pointer to it. */
- static nios2_insn_relocS *
- nios2_insn_reloc_new (bfd_reloc_code_real_type reloc_type, unsigned int pcrel)
- {
- nios2_insn_relocS *retval;
- retval = (nios2_insn_relocS *) malloc (sizeof (nios2_insn_relocS));
- if (retval == NULL)
- {
- as_bad (_("can't create relocation"));
- abort ();
- }
- /* Fill out the fields with default values. */
- retval->reloc_next = NULL;
- retval->reloc_type = reloc_type;
- retval->reloc_pcrel = pcrel;
- return retval;
- }
- /* Frees up memory previously allocated by nios2_insn_reloc_new(). */
- /* FIXME: this is never called; memory leak? */
- #if 0
- static void
- nios2_insn_reloc_destroy (nios2_insn_relocS *reloc)
- {
- gas_assert (reloc != NULL);
- free (reloc);
- }
- #endif
- /* Look up a register name and validate it for the given regtype.
- Return the register mapping or NULL on failure. */
- static struct nios2_reg *
- nios2_parse_reg (const char *token, unsigned long regtype)
- {
- struct nios2_reg *reg = nios2_reg_lookup (token);
- if (reg == NULL)
- {
- as_bad (_("unknown register %s"), token);
- return NULL;
- }
- /* Matched a register, but is it the wrong type? */
- if (!(regtype & reg->regtype))
- {
- if (regtype & REG_CONTROL)
- as_bad (_("expecting control register"));
- else if (reg->regtype & REG_CONTROL)
- as_bad (_("illegal use of control register"));
- else if (reg->regtype & REG_COPROCESSOR)
- as_bad (_("illegal use of coprocessor register"));
- else
- as_bad (_("invalid register %s"), token);
- return NULL;
- }
- /* Warn for explicit use of special registers. */
- if (reg->regtype & REG_NORMAL)
- {
- if (!nios2_as_options.noat && reg->index == 1)
- as_warn (_("Register at (r1) can sometimes be corrupted by "
- "assembler optimizations.\n"
- "Use .set noat to turn off those optimizations "
- "(and this warning)."));
- if (!nios2_as_options.nobreak && reg->index == 25)
- as_warn (_("The debugger will corrupt bt (r25).\n"
- "If you don't need to debug this "
- "code use .set nobreak to turn off this warning."));
- if (!nios2_as_options.nobreak && reg->index == 30)
- as_warn (_("The debugger will corrupt sstatus/ba (r30).\n"
- "If you don't need to debug this "
- "code use .set nobreak to turn off this warning."));
- }
- return reg;
- }
- /* This function parses a reglist for ldwm/stwm and push.n/pop.n
- instructions, given as a brace-enclosed register list. The tokenizer
- has replaced commas in the token with spaces.
- The return value is a bitmask of registers in the set. It also
- sets nios2_reglist_mask and nios2_reglist_dir to allow error checking
- when parsing the base register. */
- static unsigned long nios2_reglist_mask;
- static int nios2_reglist_dir;
- static unsigned long
- nios2_parse_reglist (char *token, const struct nios2_opcode *op)
- {
- unsigned long mask = 0;
- int dir = 0;
- unsigned long regtype = 0;
- int last = -1;
- const char *regname;
- nios2_reglist_mask = 0;
- nios2_reglist_dir = 0;
- if (op->match == MATCH_R2_LDWM || op->match == MATCH_R2_STWM)
- {
- regtype = REG_LDWM;
- dir = 0;
- }
- else if (op->match == MATCH_R2_PUSH_N)
- {
- regtype = REG_POP;
- dir = -1;
- }
- else if (op->match == MATCH_R2_POP_N)
- {
- regtype = REG_POP;
- dir = 1;
- }
- else
- bad_opcode (op);
- for (regname = strtok (token, "{ }");
- regname;
- regname = strtok (NULL, "{ }"))
- {
- int regno;
- struct nios2_reg *reg = nios2_parse_reg (regname, regtype);
- if (!reg)
- break;
- regno = reg->index;
- /* Make sure registers are listed in proper sequence. */
- if (last >= 0)
- {
- if (regno == last)
- {
- as_bad ("duplicate register %s\n", reg->name);
- return 0;
- }
- else if (dir == 0)
- dir = (regno < last ? -1 : 1);
- else if ((dir > 0 && regno < last)
- || (dir < 0 && regno > last)
- || (op->match == MATCH_R2_PUSH_N
- && ! ((last == 31 && regno == 28)
- || (last == 31 && regno <= 23)
- || (last == 28 && regno <= 23)
- || (regno < 23 && regno == last - 1)))
- || (op->match == MATCH_R2_POP_N
- && ! ((regno == 31 && last == 28)
- || (regno == 31 && last <= 23)
- || (regno == 28 && last <= 23)
- || (last < 23 && last == regno - 1))))
- {
- as_bad ("invalid register order");
- return 0;
- }
- }
- mask |= 1 << regno;
- last = regno;
- }
- /* Check that all ldwm/stwm regs belong to the same set. */
- if ((op->match == MATCH_R2_LDWM || op->match == MATCH_R2_STWM)
- && (mask & 0x00003ffc) && (mask & 0x90ffc000))
- {
- as_bad ("invalid register set in reglist");
- return 0;
- }
- /* Check that push.n/pop.n regs include RA. */
- if ((op->match == MATCH_R2_PUSH_N || op->match == MATCH_R2_POP_N)
- && ((mask & 0x80000000) == 0))
- {
- as_bad ("reglist must include ra (r31)");
- return 0;
- }
- /* Check that there is at least one register in the set. */
- if (!mask)
- {
- as_bad ("reglist must include at least one register");
- return 0;
- }
- /* OK, reglist passed validation. */
- nios2_reglist_mask = mask;
- nios2_reglist_dir = dir;
- return mask;
- }
- /* This function parses the base register and options used by the ldwm/stwm
- instructions. Returns the base register and sets the option arguments
- accordingly. On failure, returns NULL. */
- static struct nios2_reg *
- nios2_parse_base_register (char *str, int *direction, int *writeback, int *ret)
- {
- char *regname;
- struct nios2_reg *reg;
- *direction = 0;
- *writeback = 0;
- *ret = 0;
- /* Check for --. */
- if (strncmp (str, "--", 2) == 0)
- {
- str += 2;
- *direction -= 1;
- }
- /* Extract the base register. */
- if (*str != '(')
- {
- as_bad ("expected '(' before base register");
- return NULL;
- }
- str++;
- regname = str;
- str = strchr (str, ')');
- if (!str)
- {
- as_bad ("expected ')' after base register");
- return NULL;
- }
- *str = '\0';
- str++;
- reg = nios2_parse_reg (regname, REG_NORMAL);
- if (reg == NULL)
- return NULL;
- /* Check for ++. */
- if (strncmp (str, "++", 2) == 0)
- {
- str += 2;
- *direction += 1;
- }
- /* Ensure that either -- or ++ is specified, but not both. */
- if (*direction == 0)
- {
- as_bad ("invalid base register syntax");
- return NULL;;
- }
- /* Check for options. The tokenizer has replaced commas with spaces. */
- while (*str)
- {
- while (*str == ' ')
- str++;
- if (strncmp (str, "writeback", 9) == 0)
- {
- *writeback = 1;
- str += 9;
- }
- else if (strncmp (str, "ret", 3) == 0)
- {
- *ret = 1;
- str += 3;
- }
- else if (*str)
- {
- as_bad ("invalid option syntax");
- return NULL;
- }
- }
- return reg;
- }
- /* The various nios2_assemble_* functions call this
- function to generate an expression from a string representing an expression.
- It then tries to evaluate the expression, and if it can, returns its value.
- If not, it creates a new nios2_insn_relocS and stores the expression and
- reloc_type for future use. */
- static unsigned long
- nios2_assemble_expression (const char *exprstr,
- nios2_insn_infoS *insn,
- bfd_reloc_code_real_type orig_reloc_type,
- unsigned int pcrel)
- {
- nios2_insn_relocS *reloc;
- char *saved_line_ptr;
- unsigned long value = 0;
- int i;
- bfd_reloc_code_real_type reloc_type = orig_reloc_type;
- gas_assert (exprstr != NULL);
- gas_assert (insn != NULL);
- /* Check for relocation operators.
- Change the relocation type and advance the ptr to the start of
- the expression proper. */
- for (i = 0; i < nios2_num_special_relocs; i++)
- if (strstr (exprstr, nios2_special_reloc[i].string) != NULL)
- {
- reloc_type = nios2_special_reloc[i].reloc_type;
- exprstr += strlen (nios2_special_reloc[i].string) + 1;
- /* %lo and %hiadj have different meanings for PC-relative
- expressions. */
- if (pcrel)
- {
- if (reloc_type == BFD_RELOC_NIOS2_LO16)
- reloc_type = BFD_RELOC_NIOS2_PCREL_LO;
- if (reloc_type == BFD_RELOC_NIOS2_HIADJ16)
- reloc_type = BFD_RELOC_NIOS2_PCREL_HA;
- }
- break;
- }
- /* No relocation allowed; we must have a constant expression. */
- if (orig_reloc_type == BFD_RELOC_NONE)
- {
- expressionS exp;
- /* Parse the expression string. */
- saved_line_ptr = input_line_pointer;
- input_line_pointer = (char *) exprstr;
- expression (&exp);
- input_line_pointer = saved_line_ptr;
- /* If we don't have a constant, give an error. */
- if (reloc_type != orig_reloc_type || exp.X_op != O_constant)
- as_bad (_("expression must be constant"));
- else
- value = exp.X_add_number;
- return (unsigned long) value;
- }
- /* We potentially have a relocation. */
- reloc = nios2_insn_reloc_new (reloc_type, pcrel);
- reloc->reloc_next = insn->insn_reloc;
- insn->insn_reloc = reloc;
- /* Parse the expression string. */
- saved_line_ptr = input_line_pointer;
- input_line_pointer = (char *) exprstr;
- expression (&reloc->reloc_expression);
- input_line_pointer = saved_line_ptr;
- /* This is redundant as the fixup will put this into
- the instruction, but it is included here so that
- self-test mode (-r) works. */
- if (nios2_mode == NIOS2_MODE_TEST
- && reloc->reloc_expression.X_op == O_constant)
- value = reloc->reloc_expression.X_add_number;
- return (unsigned long) value;
- }
- /* Encode a 3-bit register number, giving an error if this is not possible. */
- static unsigned int
- nios2_assemble_reg3 (const char *token)
- {
- struct nios2_reg *reg = nios2_parse_reg (token, REG_3BIT);
- int j;
- if (reg == NULL)
- return 0;
- for (j = 0; j < nios2_num_r2_reg3_mappings; j++)
- if (nios2_r2_reg3_mappings[j] == reg->index)
- return j;
- /* Should never get here if we passed validation. */
- as_bad (_("invalid register %s"), token);
- return 0;
- }
- /* Argument assemble functions. */
- /* Control register index. */
- static void
- nios2_assemble_arg_c (const char *token, nios2_insn_infoS *insn)
- {
- struct nios2_reg *reg = nios2_parse_reg (token, REG_CONTROL);
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- if (reg == NULL)
- return;
- switch (op->format)
- {
- case iw_r_type:
- insn->insn_code |= SET_IW_R_IMM5 (reg->index);
- break;
- case iw_F3X6L5_type:
- insn->insn_code |= SET_IW_F3X6L5_IMM5 (reg->index);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Destination register. */
- static void
- nios2_assemble_arg_d (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned long regtype = REG_NORMAL;
- struct nios2_reg *reg;
- if (op->format == iw_custom_type || op->format == iw_F3X8_type)
- regtype |= REG_COPROCESSOR;
- reg = nios2_parse_reg (token, regtype);
- if (reg == NULL)
- return;
- switch (op->format)
- {
- case iw_r_type:
- insn->insn_code |= SET_IW_R_C (reg->index);
- break;
- case iw_custom_type:
- insn->insn_code |= SET_IW_CUSTOM_C (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_CUSTOM_READC (0);
- else
- insn->insn_code |= SET_IW_CUSTOM_READC (1);
- break;
- case iw_F3X6L5_type:
- case iw_F3X6_type:
- insn->insn_code |= SET_IW_F3X6L5_C (reg->index);
- break;
- case iw_F3X8_type:
- insn->insn_code |= SET_IW_F3X8_C (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_F3X8_READC (0);
- else
- insn->insn_code |= SET_IW_F3X8_READC (1);
- break;
- case iw_F2_type:
- insn->insn_code |= SET_IW_F2_B (reg->index);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Source register 1. */
- static void
- nios2_assemble_arg_s (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned long regtype = REG_NORMAL;
- struct nios2_reg *reg;
- if (op->format == iw_custom_type || op->format == iw_F3X8_type)
- regtype |= REG_COPROCESSOR;
- reg = nios2_parse_reg (token, regtype);
- if (reg == NULL)
- return;
- switch (op->format)
- {
- case iw_r_type:
- if (op->match == MATCH_R1_JMP && reg->index == 31)
- as_bad (_("r31 cannot be used with jmp; use ret instead"));
- insn->insn_code |= SET_IW_R_A (reg->index);
- break;
- case iw_i_type:
- insn->insn_code |= SET_IW_I_A (reg->index);
- break;
- case iw_custom_type:
- insn->insn_code |= SET_IW_CUSTOM_A (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_CUSTOM_READA (0);
- else
- insn->insn_code |= SET_IW_CUSTOM_READA (1);
- break;
- case iw_F2I16_type:
- insn->insn_code |= SET_IW_F2I16_A (reg->index);
- break;
- case iw_F2X4I12_type:
- insn->insn_code |= SET_IW_F2X4I12_A (reg->index);
- break;
- case iw_F1X4I12_type:
- insn->insn_code |= SET_IW_F1X4I12_A (reg->index);
- break;
- case iw_F1X4L17_type:
- insn->insn_code |= SET_IW_F1X4L17_A (reg->index);
- break;
- case iw_F3X6L5_type:
- case iw_F3X6_type:
- if (op->match == MATCH_R2_JMP && reg->index == 31)
- as_bad (_("r31 cannot be used with jmp; use ret instead"));
- insn->insn_code |= SET_IW_F3X6L5_A (reg->index);
- break;
- case iw_F2X6L10_type:
- insn->insn_code |= SET_IW_F2X6L10_A (reg->index);
- break;
- case iw_F3X8_type:
- insn->insn_code |= SET_IW_F3X8_A (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_F3X8_READA (0);
- else
- insn->insn_code |= SET_IW_F3X8_READA (1);
- break;
- case iw_F1X1_type:
- if (op->match == MATCH_R2_JMPR_N && reg->index == 31)
- as_bad (_("r31 cannot be used with jmpr.n; use ret.n instead"));
- insn->insn_code |= SET_IW_F1X1_A (reg->index);
- break;
- case iw_F1I5_type:
- /* Implicit stack pointer reference. */
- if (reg->index != 27)
- as_bad (_("invalid register %s"), token);
- break;
- case iw_F2_type:
- insn->insn_code |= SET_IW_F2_A (reg->index);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Source register 2. */
- static void
- nios2_assemble_arg_t (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned long regtype = REG_NORMAL;
- struct nios2_reg *reg;
- if (op->format == iw_custom_type || op->format == iw_F3X8_type)
- regtype |= REG_COPROCESSOR;
- reg = nios2_parse_reg (token, regtype);
- if (reg == NULL)
- return;
- switch (op->format)
- {
- case iw_r_type:
- insn->insn_code |= SET_IW_R_B (reg->index);
- break;
- case iw_i_type:
- insn->insn_code |= SET_IW_I_B (reg->index);
- break;
- case iw_custom_type:
- insn->insn_code |= SET_IW_CUSTOM_B (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_CUSTOM_READB (0);
- else
- insn->insn_code |= SET_IW_CUSTOM_READB (1);
- break;
- case iw_F2I16_type:
- insn->insn_code |= SET_IW_F2I16_B (reg->index);
- break;
- case iw_F2X4I12_type:
- insn->insn_code |= SET_IW_F2X4I12_B (reg->index);
- break;
- case iw_F3X6L5_type:
- case iw_F3X6_type:
- insn->insn_code |= SET_IW_F3X6L5_B (reg->index);
- break;
- case iw_F2X6L10_type:
- insn->insn_code |= SET_IW_F2X6L10_B (reg->index);
- break;
- case iw_F3X8_type:
- insn->insn_code |= SET_IW_F3X8_B (reg->index);
- if (reg->regtype & REG_COPROCESSOR)
- insn->insn_code |= SET_IW_F3X8_READB (0);
- else
- insn->insn_code |= SET_IW_F3X8_READB (1);
- break;
- case iw_F1I5_type:
- insn->insn_code |= SET_IW_F1I5_B (reg->index);
- break;
- case iw_F2_type:
- insn->insn_code |= SET_IW_F2_B (reg->index);
- break;
- case iw_T1X1I6_type:
- /* Implicit zero register reference. */
- if (reg->index != 0)
- as_bad (_("invalid register %s"), token);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Destination register w/3-bit encoding. */
- static void
- nios2_assemble_arg_D (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- int reg = nios2_assemble_reg3 (token);
- switch (op->format)
- {
- case iw_T1I7_type:
- insn->insn_code |= SET_IW_T1I7_A3 (reg);
- break;
- case iw_T2X1L3_type:
- insn->insn_code |= SET_IW_T2X1L3_B3 (reg);
- break;
- case iw_T2X1I3_type:
- insn->insn_code |= SET_IW_T2X1I3_B3 (reg);
- break;
- case iw_T3X1_type:
- insn->insn_code |= SET_IW_T3X1_C3 (reg);
- break;
- case iw_T2X3_type:
- /* Some instructions using this encoding take 3 register arguments,
- requiring the destination register to be the same as the first
- source register. */
- if (op->num_args == 3)
- insn->insn_code |= SET_IW_T2X3_A3 (reg);
- else
- insn->insn_code |= SET_IW_T2X3_B3 (reg);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Source register w/3-bit encoding. */
- static void
- nios2_assemble_arg_S (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- int reg = nios2_assemble_reg3 (token);
- switch (op->format)
- {
- case iw_T1I7_type:
- insn->insn_code |= SET_IW_T1I7_A3 (reg);
- break;
- case iw_T2I4_type:
- insn->insn_code |= SET_IW_T2I4_A3 (reg);
- break;
- case iw_T2X1L3_type:
- insn->insn_code |= SET_IW_T2X1L3_A3 (reg);
- break;
- case iw_T2X1I3_type:
- insn->insn_code |= SET_IW_T2X1I3_A3 (reg);
- break;
- case iw_T3X1_type:
- insn->insn_code |= SET_IW_T3X1_A3 (reg);
- break;
- case iw_T2X3_type:
- /* Some instructions using this encoding take 3 register arguments,
- requiring the destination register to be the same as the first
- source register. */
- if (op->num_args == 3)
- {
- int dreg = GET_IW_T2X3_A3 (insn->insn_code);
- if (dreg != reg)
- as_bad ("source and destination registers must be the same");
- }
- else
- insn->insn_code |= SET_IW_T2X3_A3 (reg);
- break;
- case iw_T1X1I6_type:
- insn->insn_code |= SET_IW_T1X1I6_A3 (reg);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Source register 2 w/3-bit encoding. */
- static void
- nios2_assemble_arg_T (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- int reg = nios2_assemble_reg3 (token);
- switch (op->format)
- {
- case iw_T2I4_type:
- insn->insn_code |= SET_IW_T2I4_B3 (reg);
- break;
- case iw_T3X1_type:
- insn->insn_code |= SET_IW_T3X1_B3 (reg);
- break;
- case iw_T2X3_type:
- insn->insn_code |= SET_IW_T2X3_B3 (reg);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 16-bit signed immediate. */
- static void
- nios2_assemble_arg_i (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_i_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_S16, 0);
- insn->constant_bits |= SET_IW_I_IMM16 (val);
- break;
- case iw_F2I16_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_S16, 0);
- insn->constant_bits |= SET_IW_F2I16_IMM16 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 12-bit signed immediate. */
- static void
- nios2_assemble_arg_I (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_F2X4I12_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_S12, 0);
- insn->constant_bits |= SET_IW_F2X4I12_IMM12 (val);
- break;
- case iw_F1X4I12_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_S12, 0);
- insn->constant_bits |= SET_IW_F2X4I12_IMM12 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 16-bit unsigned immediate. */
- static void
- nios2_assemble_arg_u (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_i_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_U16, 0);
- insn->constant_bits |= SET_IW_I_IMM16 (val);
- break;
- case iw_F2I16_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_U16, 0);
- insn->constant_bits |= SET_IW_F2I16_IMM16 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 7-bit unsigned immediate with 2-bit shift. */
- static void
- nios2_assemble_arg_U (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T1I7_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T1I7_2, 0);
- insn->constant_bits |= SET_IW_T1I7_IMM7 (val >> 2);
- break;
- case iw_X1I7_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_X1I7_2, 0);
- insn->constant_bits |= SET_IW_X1I7_IMM7 (val >> 2);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 5-bit unsigned immediate with 2-bit shift. */
- static void
- nios2_assemble_arg_V (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_F1I5_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_F1I5_2, 0);
- insn->constant_bits |= SET_IW_F1I5_IMM5 (val >> 2);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 4-bit unsigned immediate with 2-bit shift. */
- static void
- nios2_assemble_arg_W (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T2I4_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T2I4_2, 0);
- insn->constant_bits |= SET_IW_T2I4_IMM4 (val >> 2);
- break;
- case iw_L5I4X1_type:
- /* This argument is optional for push.n/pop.n, and defaults to
- zero if unspecified. */
- if (token == NULL)
- return;
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_L5I4X1, 0);
- insn->constant_bits |= SET_IW_L5I4X1_IMM4 (val >> 2);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 4-bit unsigned immediate with 1-bit shift. */
- static void
- nios2_assemble_arg_X (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T2I4_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T2I4_1, 0);
- insn->constant_bits |= SET_IW_T2I4_IMM4 (val >> 1);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 4-bit unsigned immediate without shift. */
- static void
- nios2_assemble_arg_Y (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T2I4_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T2I4, 0);
- insn->constant_bits |= SET_IW_T2I4_IMM4 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 16-bit signed immediate address offset. */
- static void
- nios2_assemble_arg_o (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_i_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_16_PCREL, 1);
- insn->constant_bits |= SET_IW_I_IMM16 (val);
- break;
- case iw_F2I16_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_16_PCREL, 1);
- insn->constant_bits |= SET_IW_F2I16_IMM16 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 10-bit signed address offset with 1-bit shift. */
- static void
- nios2_assemble_arg_O (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_I10_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_I10_1_PCREL, 1);
- insn->constant_bits |= SET_IW_I10_IMM10 (val >> 1);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 7-bit signed address offset with 1-bit shift. */
- static void
- nios2_assemble_arg_P (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T1I7_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T1I7_1_PCREL, 1);
- insn->constant_bits |= SET_IW_T1I7_IMM7 (val >> 1);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 5-bit unsigned immediate. */
- static void
- nios2_assemble_arg_j (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_r_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_IMM5, 0);
- insn->constant_bits |= SET_IW_R_IMM5 (val);
- break;
- case iw_F3X6L5_type:
- if (op->match == MATCH_R2_ENI)
- /* Value must be constant 0 or 1. */
- {
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- if (val != 0 && val != 1)
- as_bad ("invalid eni argument %u", val);
- insn->insn_code |= SET_IW_F3X6L5_IMM5 (val);
- }
- else
- {
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_IMM5, 0);
- insn->constant_bits |= SET_IW_F3X6L5_IMM5 (val);
- }
- break;
- case iw_F2X6L10_type:
- /* Only constant expression without relocation permitted for
- bit position. */
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- if (val > 31)
- as_bad ("invalid bit position %u", val);
- insn->insn_code |= SET_IW_F2X6L10_MSB (val);
- break;
- case iw_X2L5_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_X2L5, 0);
- insn->constant_bits |= SET_IW_X2L5_IMM5 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Second 5-bit unsigned immediate field. */
- static void
- nios2_assemble_arg_k (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_F2X6L10_type:
- /* Only constant expression without relocation permitted for
- bit position. */
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NONE, 0);
- if (val > 31)
- as_bad ("invalid bit position %u", val);
- else if (GET_IW_F2X6L10_MSB (insn->insn_code) < val)
- as_bad ("MSB must be greater than or equal to LSB");
- insn->insn_code |= SET_IW_F2X6L10_LSB (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 8-bit unsigned immediate. */
- static void
- nios2_assemble_arg_l (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_custom_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_IMM8, 0);
- insn->constant_bits |= SET_IW_CUSTOM_N (val);
- break;
- case iw_F3X8_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_IMM8, 0);
- insn->constant_bits |= SET_IW_F3X8_N (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 26-bit unsigned immediate. */
- static void
- nios2_assemble_arg_m (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_j_type:
- val = nios2_assemble_expression (token, insn,
- (nios2_as_options.noat
- ? BFD_RELOC_NIOS2_CALL26_NOAT
- : BFD_RELOC_NIOS2_CALL26),
- 0);
- insn->constant_bits |= SET_IW_J_IMM26 (val);
- break;
- case iw_L26_type:
- val = nios2_assemble_expression (token, insn,
- (nios2_as_options.noat
- ? BFD_RELOC_NIOS2_CALL26_NOAT
- : BFD_RELOC_NIOS2_CALL26),
- 0);
- insn->constant_bits |= SET_IW_L26_IMM26 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 6-bit unsigned immediate with no shifting. */
- static void
- nios2_assemble_arg_M (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T1X1I6_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T1X1I6, 0);
- insn->constant_bits |= SET_IW_T1X1I6_IMM6 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* 6-bit unsigned immediate with 2-bit shift. */
- static void
- nios2_assemble_arg_N (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- switch (op->format)
- {
- case iw_T1X1I6_type:
- val = nios2_assemble_expression (token, insn,
- BFD_RELOC_NIOS2_R2_T1X1I6_2, 0);
- insn->constant_bits |= SET_IW_T1X1I6_IMM6 (val >> 2);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Encoded enumeration for addi.n/subi.n. */
- static void
- nios2_assemble_arg_e (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- int i;
- switch (op->format)
- {
- case iw_T2X1I3_type:
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- for (i = 0; i < nios2_num_r2_asi_n_mappings; i++)
- if (val == nios2_r2_asi_n_mappings[i])
- break;
- if (i == nios2_num_r2_asi_n_mappings)
- {
- as_bad (_("Invalid constant operand %s"), token);
- return;
- }
- insn->insn_code |= SET_IW_T2X1I3_IMM3 ((unsigned)i);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Encoded enumeration for slli.n/srli.n. */
- static void
- nios2_assemble_arg_f (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- int i;
- switch (op->format)
- {
- case iw_T2X1L3_type:
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- for (i = 0; i < nios2_num_r2_shi_n_mappings; i++)
- if (val == nios2_r2_shi_n_mappings[i])
- break;
- if (i == nios2_num_r2_shi_n_mappings)
- {
- as_bad (_("Invalid constant operand %s"), token);
- return;
- }
- insn->insn_code |= SET_IW_T2X1L3_SHAMT ((unsigned)i);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Encoded enumeration for andi.n. */
- static void
- nios2_assemble_arg_g (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- int i;
- switch (op->format)
- {
- case iw_T2I4_type:
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- for (i = 0; i < nios2_num_r2_andi_n_mappings; i++)
- if (val == nios2_r2_andi_n_mappings[i])
- break;
- if (i == nios2_num_r2_andi_n_mappings)
- {
- as_bad (_("Invalid constant operand %s"), token);
- return;
- }
- insn->insn_code |= SET_IW_T2I4_IMM4 ((unsigned)i);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Encoded enumeration for movi.n. */
- static void
- nios2_assemble_arg_h (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned int val;
- int i;
- switch (op->format)
- {
- case iw_T1I7_type:
- val = nios2_assemble_expression (token, insn, BFD_RELOC_NONE, 0);
- i = (signed) val;
- if ((signed) i == -1)
- val = 127;
- else if (i == -2)
- val = 126;
- else if (i == 0xff)
- val = 125;
- else if (i < 0 || i > 125)
- {
- as_bad (_("Invalid constant operand %s"), token);
- return;
- }
- insn->insn_code |= SET_IW_T1I7_IMM7 (val);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Encoded REGMASK for ldwm/stwm or push.n/pop.n. */
- static void
- nios2_assemble_arg_R (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- unsigned long mask;
- char *buf = strdup (token);
- unsigned long reglist = nios2_parse_reglist (buf, op);
- free (buf);
- if (reglist == 0)
- return;
- switch (op->format)
- {
- case iw_F1X4L17_type:
- /* Encoding for ldwm/stwm. */
- if (reglist & 0x00003ffc)
- mask = reglist >> 2;
- else
- {
- insn->insn_code |= SET_IW_F1X4L17_RS (1);
- mask = (reglist & 0x00ffc000) >> 14;
- if (reglist & (1 << 28))
- mask |= 1 << 10;
- if (reglist & (1 << 31))
- mask |= 1 << 11;
- }
- insn->insn_code |= SET_IW_F1X4L17_REGMASK (mask);
- break;
- case iw_L5I4X1_type:
- /* Encoding for push.n/pop.n. */
- if (reglist & (1 << 28))
- insn->insn_code |= SET_IW_L5I4X1_FP (1);
- mask = reglist & 0x00ff0000;
- if (mask)
- {
- int i;
- for (i = 0; i < nios2_num_r2_reg_range_mappings; i++)
- if (nios2_r2_reg_range_mappings[i] == mask)
- break;
- if (i == nios2_num_r2_reg_range_mappings)
- {
- as_bad ("invalid reglist");
- return;
- }
- insn->insn_code |= SET_IW_L5I4X1_REGRANGE (i);
- insn->insn_code |= SET_IW_L5I4X1_CS (1);
- }
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Base register for ldwm/stwm. */
- static void
- nios2_assemble_arg_B (const char *token, nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- int direction, writeback, ret;
- char *str = strdup (token);
- struct nios2_reg *reg
- = nios2_parse_base_register (str, &direction, &writeback, &ret);
- free (str);
- if (!reg)
- return;
- switch (op->format)
- {
- case iw_F1X4L17_type:
- /* For ldwm, check to see if the base register is already inside the
- register list. */
- if (op->match == MATCH_R2_LDWM
- && (nios2_reglist_mask & (1 << reg->index)))
- {
- as_bad ("invalid base register; %s is inside the reglist", reg->name);
- return;
- }
- /* For stwm, ret option is not allowed. */
- if (op->match == MATCH_R2_STWM && ret)
- {
- as_bad ("invalid option syntax");
- return;
- }
- /* Check that the direction matches the ordering of the reglist. */
- if (nios2_reglist_dir && direction != nios2_reglist_dir)
- {
- as_bad ("reglist order does not match increment/decrement mode");
- return;
- }
- insn->insn_code |= SET_IW_F1X4L17_A (reg->index);
- if (direction > 0)
- insn->insn_code |= SET_IW_F1X4L17_ID (1);
- if (writeback)
- insn->insn_code |= SET_IW_F1X4L17_WB (1);
- if (ret)
- insn->insn_code |= SET_IW_F1X4L17_PC (1);
- break;
- default:
- bad_opcode (op);
- }
- }
- static void
- nios2_assemble_args (nios2_insn_infoS *insn)
- {
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- const char *argptr;
- unsigned int tokidx, ntok;
- /* Make sure there are enough arguments. */
- ntok = (op->pinfo & NIOS2_INSN_OPTARG) ? op->num_args - 1 : op->num_args;
- for (tokidx = 1; tokidx <= ntok; tokidx++)
- if (insn->insn_tokens[tokidx] == NULL)
- {
- as_bad ("missing argument");
- return;
- }
- for (argptr = op->args, tokidx = 1;
- *argptr && insn->insn_tokens[tokidx];
- argptr++)
- switch (*argptr)
- {
- case ',':
- case '(':
- case ')':
- break;
- case 'c':
- nios2_assemble_arg_c (insn->insn_tokens[tokidx++], insn);
- break;
- case 'd':
- nios2_assemble_arg_d (insn->insn_tokens[tokidx++], insn);
- break;
- case 's':
- nios2_assemble_arg_s (insn->insn_tokens[tokidx++], insn);
- break;
- case 't':
- nios2_assemble_arg_t (insn->insn_tokens[tokidx++], insn);
- break;
- case 'D':
- nios2_assemble_arg_D (insn->insn_tokens[tokidx++], insn);
- break;
- case 'S':
- nios2_assemble_arg_S (insn->insn_tokens[tokidx++], insn);
- break;
- case 'T':
- nios2_assemble_arg_T (insn->insn_tokens[tokidx++], insn);
- break;
- case 'i':
- nios2_assemble_arg_i (insn->insn_tokens[tokidx++], insn);
- break;
- case 'I':
- nios2_assemble_arg_I (insn->insn_tokens[tokidx++], insn);
- break;
- case 'u':
- nios2_assemble_arg_u (insn->insn_tokens[tokidx++], insn);
- break;
- case 'U':
- nios2_assemble_arg_U (insn->insn_tokens[tokidx++], insn);
- break;
- case 'V':
- nios2_assemble_arg_V (insn->insn_tokens[tokidx++], insn);
- break;
- case 'W':
- nios2_assemble_arg_W (insn->insn_tokens[tokidx++], insn);
- break;
- case 'X':
- nios2_assemble_arg_X (insn->insn_tokens[tokidx++], insn);
- break;
- case 'Y':
- nios2_assemble_arg_Y (insn->insn_tokens[tokidx++], insn);
- break;
- case 'o':
- nios2_assemble_arg_o (insn->insn_tokens[tokidx++], insn);
- break;
- case 'O':
- nios2_assemble_arg_O (insn->insn_tokens[tokidx++], insn);
- break;
- case 'P':
- nios2_assemble_arg_P (insn->insn_tokens[tokidx++], insn);
- break;
- case 'j':
- nios2_assemble_arg_j (insn->insn_tokens[tokidx++], insn);
- break;
- case 'k':
- nios2_assemble_arg_k (insn->insn_tokens[tokidx++], insn);
- break;
- case 'l':
- nios2_assemble_arg_l (insn->insn_tokens[tokidx++], insn);
- break;
- case 'm':
- nios2_assemble_arg_m (insn->insn_tokens[tokidx++], insn);
- break;
- case 'M':
- nios2_assemble_arg_M (insn->insn_tokens[tokidx++], insn);
- break;
- case 'N':
- nios2_assemble_arg_N (insn->insn_tokens[tokidx++], insn);
- break;
- case 'e':
- nios2_assemble_arg_e (insn->insn_tokens[tokidx++], insn);
- break;
- case 'f':
- nios2_assemble_arg_f (insn->insn_tokens[tokidx++], insn);
- break;
- case 'g':
- nios2_assemble_arg_g (insn->insn_tokens[tokidx++], insn);
- break;
- case 'h':
- nios2_assemble_arg_h (insn->insn_tokens[tokidx++], insn);
- break;
- case 'R':
- nios2_assemble_arg_R (insn->insn_tokens[tokidx++], insn);
- break;
- case 'B':
- nios2_assemble_arg_B (insn->insn_tokens[tokidx++], insn);
- break;
- default:
- bad_opcode (op);
- break;
- }
- /* Perform argument checking. */
- nios2_check_assembly (insn->insn_code | insn->constant_bits,
- insn->insn_tokens[tokidx]);
- }
- /* The function consume_arg takes a pointer into a string
- of instruction tokens (args) and a pointer into a string
- representing the expected sequence of tokens and separators.
- It checks whether the first argument in argstr is of the
- expected type, throwing an error if it is not, and returns
- the pointer argstr. */
- static char *
- nios2_consume_arg (char *argstr, const char *parsestr)
- {
- char *temp;
- switch (*parsestr)
- {
- case 'c':
- case 'd':
- case 's':
- case 't':
- case 'D':
- case 'S':
- case 'T':
- break;
- case 'i':
- case 'u':
- if (*argstr == '%')
- {
- if (nios2_special_relocation_p (argstr))
- {
- /* We zap the parentheses because we don't want them confused
- with separators. */
- temp = strchr (argstr, '(');
- if (temp != NULL)
- *temp = ' ';
- temp = strchr (argstr, ')');
- if (temp != NULL)
- *temp = ' ';
- }
- else
- as_bad (_("badly formed expression near %s"), argstr);
- }
- break;
- case 'm':
- case 'j':
- case 'k':
- case 'l':
- case 'I':
- case 'U':
- case 'V':
- case 'W':
- case 'X':
- case 'Y':
- case 'O':
- case 'P':
- case 'e':
- case 'f':
- case 'g':
- case 'h':
- case 'M':
- case 'N':
- /* We can't have %hi, %lo or %hiadj here. */
- if (*argstr == '%')
- as_bad (_("badly formed expression near %s"), argstr);
- break;
- case 'R':
- /* Register list for ldwm/stwm or push.n/pop.n. Replace the commas
- in the list with spaces so we don't confuse them with separators. */
- if (*argstr != '{')
- {
- as_bad ("missing '{' in register list");
- break;
- }
- for (temp = argstr + 1; *temp; temp++)
- {
- if (*temp == '}')
- break;
- else if (*temp == ',')
- *temp = ' ';
- }
- if (!*temp)
- {
- as_bad ("missing '}' in register list");
- break;
- }
- break;
- case 'B':
- /* Base register and options for ldwm/stwm. This is the final argument
- and consumes the rest of the argument string; replace commas
- with spaces so that the token splitter doesn't think they are
- separate arguments. */
- for (temp = argstr; *temp; temp++)
- if (*temp == ',')
- *temp = ' ';
- break;
- case 'o':
- case 'E':
- break;
- default:
- BAD_CASE (*parsestr);
- break;
- }
- return argstr;
- }
- /* The function consume_separator takes a pointer into a string
- of instruction tokens (args) and a pointer into a string representing
- the expected sequence of tokens and separators. It finds the first
- instance of the character pointed to by separator in argstr, and
- returns a pointer to the next element of argstr, which is the
- following token in the sequence. */
- static char *
- nios2_consume_separator (char *argstr, const char *separator)
- {
- char *p;
- /* If we have a opcode reg, expr(reg) type instruction, and
- * we are separating the expr from the (reg), we find the last
- * (, just in case the expression has parentheses. */
- if (*separator == '(')
- p = strrchr (argstr, *separator);
- else
- p = strchr (argstr, *separator);
- if (p != NULL)
- *p++ = 0;
- return p;
- }
- /* The principal argument parsing function which takes a string argstr
- representing the instruction arguments for insn, and extracts the argument
- tokens matching parsestr into parsed_args. */
- static void
- nios2_parse_args (nios2_insn_infoS *insn, char *argstr,
- const char *parsestr, char **parsed_args)
- {
- char *p;
- char *end = NULL;
- int i;
- p = argstr;
- i = 0;
- bfd_boolean terminate = FALSE;
- /* This rest of this function is it too fragile and it mostly works,
- therefore special case this one. */
- if (*parsestr == 0 && argstr != 0)
- {
- as_bad (_("too many arguments"));
- parsed_args[0] = NULL;
- return;
- }
- while (p != NULL && !terminate && i < NIOS2_MAX_INSN_TOKENS)
- {
- parsed_args[i] = nios2_consume_arg (p, parsestr);
- ++parsestr;
- while (*parsestr == '(' || *parsestr == ')' || *parsestr == ',')
- {
- char *context = p;
- p = nios2_consume_separator (p, parsestr);
- /* Check for missing separators. */
- if (!p && !(insn->insn_nios2_opcode->pinfo & NIOS2_INSN_OPTARG))
- {
- as_bad (_("expecting %c near %s"), *parsestr, context);
- break;
- }
- ++parsestr;
- }
- if (*parsestr == '\0')
- {
- /* Check that the argument string has no trailing arguments. */
- end = strpbrk (p, ",");
- if (end != NULL)
- as_bad (_("too many arguments"));
- }
- if (*parsestr == '\0' || (p != NULL && *p == '\0'))
- terminate = TRUE;
- ++i;
- }
- parsed_args[i] = NULL;
- }
- /** Support for pseudo-op parsing. These are macro-like opcodes that
- expand into real insns by suitable fiddling with the operands. */
- /* Append the string modifier to the string contained in the argument at
- parsed_args[ndx]. */
- static void
- nios2_modify_arg (char **parsed_args, const char *modifier,
- int unused ATTRIBUTE_UNUSED, int ndx)
- {
- char *tmp = parsed_args[ndx];
- parsed_args[ndx]
- = (char *) malloc (strlen (parsed_args[ndx]) + strlen (modifier) + 1);
- strcpy (parsed_args[ndx], tmp);
- strcat (parsed_args[ndx], modifier);
- }
- /* Modify parsed_args[ndx] by negating that argument. */
- static void
- nios2_negate_arg (char **parsed_args, const char *modifier ATTRIBUTE_UNUSED,
- int unused ATTRIBUTE_UNUSED, int ndx)
- {
- char *tmp = parsed_args[ndx];
- parsed_args[ndx]
- = (char *) malloc (strlen ("~(") + strlen (parsed_args[ndx]) +
- strlen (")+1") + 1);
- strcpy (parsed_args[ndx], "~(");
- strcat (parsed_args[ndx], tmp);
- strcat (parsed_args[ndx], ")+1");
- }
- /* The function nios2_swap_args swaps the pointers at indices index_1 and
- index_2 in the array parsed_args[] - this is used for operand swapping
- for comparison operations. */
- static void
- nios2_swap_args (char **parsed_args, const char *unused ATTRIBUTE_UNUSED,
- int index_1, int index_2)
- {
- char *tmp;
- gas_assert (index_1 < NIOS2_MAX_INSN_TOKENS
- && index_2 < NIOS2_MAX_INSN_TOKENS);
- tmp = parsed_args[index_1];
- parsed_args[index_1] = parsed_args[index_2];
- parsed_args[index_2] = tmp;
- }
- /* This function appends the string appnd to the array of strings in
- parsed_args num times starting at index start in the array. */
- static void
- nios2_append_arg (char **parsed_args, const char *appnd, int num,
- int start)
- {
- int i, count;
- char *tmp;
- gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS);
- if (nios2_mode == NIOS2_MODE_TEST)
- tmp = parsed_args[start];
- else
- tmp = NULL;
- for (i = start, count = num; count > 0; ++i, --count)
- parsed_args[i] = (char *) appnd;
- gas_assert (i == (start + num));
- parsed_args[i] = tmp;
- parsed_args[i + 1] = NULL;
- }
- /* This function inserts the string insert num times in the array
- parsed_args, starting at the index start. */
- static void
- nios2_insert_arg (char **parsed_args, const char *insert, int num,
- int start)
- {
- int i, count;
- gas_assert ((start + num) < NIOS2_MAX_INSN_TOKENS);
- /* Move the existing arguments up to create space. */
- for (i = NIOS2_MAX_INSN_TOKENS; i - num >= start; --i)
- parsed_args[i] = parsed_args[i - num];
- for (i = start, count = num; count > 0; ++i, --count)
- parsed_args[i] = (char *) insert;
- }
- /* Cleanup function to free malloc'ed arg strings. */
- static void
- nios2_free_arg (char **parsed_args, int num ATTRIBUTE_UNUSED, int start)
- {
- if (parsed_args[start])
- {
- free (parsed_args[start]);
- parsed_args[start] = NULL;
- }
- }
- /* This function swaps the pseudo-op for a real op. */
- static nios2_ps_insn_infoS*
- nios2_translate_pseudo_insn (nios2_insn_infoS *insn)
- {
- nios2_ps_insn_infoS *ps_insn;
- /* Find which real insn the pseudo-op transates to and
- switch the insn_info ptr to point to it. */
- ps_insn = nios2_ps_lookup (insn->insn_nios2_opcode->name);
- if (ps_insn != NULL)
- {
- insn->insn_nios2_opcode = nios2_opcode_lookup (ps_insn->insn);
- insn->insn_tokens[0] = insn->insn_nios2_opcode->name;
- /* Modify the args so they work with the real insn. */
- ps_insn->arg_modifer_func ((char **) insn->insn_tokens,
- ps_insn->arg_modifier, ps_insn->num,
- ps_insn->index);
- }
- else
- /* we cannot recover from this. */
- as_fatal (_("unrecognized pseudo-instruction %s"),
- insn->insn_nios2_opcode->name);
- return ps_insn;
- }
- /* Invoke the cleanup handler for pseudo-insn ps_insn on insn. */
- static void
- nios2_cleanup_pseudo_insn (nios2_insn_infoS *insn,
- nios2_ps_insn_infoS *ps_insn)
- {
- if (ps_insn->arg_cleanup_func)
- (ps_insn->arg_cleanup_func) ((char **) insn->insn_tokens,
- ps_insn->num, ps_insn->index);
- }
- const nios2_ps_insn_infoS nios2_ps_insn_info_structs[] = {
- /* pseudo-op, real-op, arg, arg_modifier_func, num, index, arg_cleanup_func */
- {"mov", "add", nios2_append_arg, "zero", 1, 3, NULL},
- {"movi", "addi", nios2_insert_arg, "zero", 1, 2, NULL},
- {"movhi", "orhi", nios2_insert_arg, "zero", 1, 2, NULL},
- {"movui", "ori", nios2_insert_arg, "zero", 1, 2, NULL},
- {"movia", "orhi", nios2_insert_arg, "zero", 1, 2, NULL},
- {"nop", "add", nios2_append_arg, "zero", 3, 1, NULL},
- {"bgt", "blt", nios2_swap_args, "", 1, 2, NULL},
- {"bgtu", "bltu", nios2_swap_args, "", 1, 2, NULL},
- {"ble", "bge", nios2_swap_args, "", 1, 2, NULL},
- {"bleu", "bgeu", nios2_swap_args, "", 1, 2, NULL},
- {"cmpgt", "cmplt", nios2_swap_args, "", 2, 3, NULL},
- {"cmpgtu", "cmpltu", nios2_swap_args, "", 2, 3, NULL},
- {"cmple", "cmpge", nios2_swap_args, "", 2, 3, NULL},
- {"cmpleu", "cmpgeu", nios2_swap_args, "", 2, 3, NULL},
- {"cmpgti", "cmpgei", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
- {"cmpgtui", "cmpgeui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
- {"cmplei", "cmplti", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
- {"cmpleui", "cmpltui", nios2_modify_arg, "+1", 0, 3, nios2_free_arg},
- {"subi", "addi", nios2_negate_arg, "", 0, 3, nios2_free_arg},
- {"nop.n", "mov.n", nios2_append_arg, "zero", 2, 1, NULL}
- /* Add further pseudo-ops here. */
- };
- #define NIOS2_NUM_PSEUDO_INSNS \
- ((sizeof(nios2_ps_insn_info_structs)/ \
- sizeof(nios2_ps_insn_info_structs[0])))
- const int nios2_num_ps_insn_info_structs = NIOS2_NUM_PSEUDO_INSNS;
- /** Assembler output support. */
- /* Output a normal instruction. */
- static void
- output_insn (nios2_insn_infoS *insn)
- {
- char *f;
- nios2_insn_relocS *reloc;
- f = frag_more (insn->insn_nios2_opcode->size);
- /* This allocates enough space for the instruction
- and puts it in the current frag. */
- md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size);
- /* Emit debug info. */
- dwarf2_emit_insn (insn->insn_nios2_opcode->size);
- /* Create any fixups to be acted on later. */
- for (reloc = insn->insn_reloc; reloc != NULL; reloc = reloc->reloc_next)
- fix_new_exp (frag_now, f - frag_now->fr_literal,
- insn->insn_nios2_opcode->size,
- &reloc->reloc_expression, reloc->reloc_pcrel,
- reloc->reloc_type);
- }
- /* Output an unconditional branch. */
- static void
- output_ubranch (nios2_insn_infoS *insn)
- {
- nios2_insn_relocS *reloc = insn->insn_reloc;
- /* If the reloc is NULL, there was an error assembling the branch. */
- if (reloc != NULL)
- {
- symbolS *symp = reloc->reloc_expression.X_add_symbol;
- offsetT offset = reloc->reloc_expression.X_add_number;
- char *f;
- bfd_boolean is_cdx = (insn->insn_nios2_opcode->size == 2);
- /* Tag dwarf2 debug info to the address at the start of the insn.
- We must do it before frag_var() below closes off the frag. */
- dwarf2_emit_insn (0);
- /* We create a machine dependent frag which can grow
- to accommodate the largest possible instruction sequence
- this may generate. */
- f = frag_var (rs_machine_dependent,
- UBRANCH_MAX_SIZE, insn->insn_nios2_opcode->size,
- (is_cdx ? CDX_UBRANCH_SUBTYPE (0) : UBRANCH_SUBTYPE (0)),
- symp, offset, NULL);
- md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size);
- /* We leave fixup generation to md_convert_frag. */
- }
- }
- /* Output a conditional branch. */
- static void
- output_cbranch (nios2_insn_infoS *insn)
- {
- nios2_insn_relocS *reloc = insn->insn_reloc;
- /* If the reloc is NULL, there was an error assembling the branch. */
- if (reloc != NULL)
- {
- symbolS *symp = reloc->reloc_expression.X_add_symbol;
- offsetT offset = reloc->reloc_expression.X_add_number;
- char *f;
- bfd_boolean is_cdx = (insn->insn_nios2_opcode->size == 2);
- /* Tag dwarf2 debug info to the address at the start of the insn.
- We must do it before frag_var() below closes off the frag. */
- dwarf2_emit_insn (0);
- /* We create a machine dependent frag which can grow
- to accommodate the largest possible instruction sequence
- this may generate. */
- f = frag_var (rs_machine_dependent,
- CBRANCH_MAX_SIZE, insn->insn_nios2_opcode->size,
- (is_cdx ? CDX_CBRANCH_SUBTYPE (0) : CBRANCH_SUBTYPE (0)),
- symp, offset, NULL);
- md_number_to_chars (f, insn->insn_code, insn->insn_nios2_opcode->size);
- /* We leave fixup generation to md_convert_frag. */
- }
- }
- /* Output a call sequence. Since calls are not pc-relative for NIOS2,
- but are page-relative, we cannot tell at any stage in assembly
- whether a call will be out of range since a section may be linked
- at any address. So if we are relaxing, we convert all call instructions
- to long call sequences, and rely on the linker to relax them back to
- short calls. */
- static void
- output_call (nios2_insn_infoS *insn)
- {
- /* This allocates enough space for the instruction
- and puts it in the current frag. */
- char *f = frag_more (12);
- nios2_insn_relocS *reloc = insn->insn_reloc;
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- switch (op->format)
- {
- case iw_j_type:
- md_number_to_chars (f,
- (MATCH_R1_ORHI | SET_IW_I_B (AT_REGNUM)
- | SET_IW_I_A (0)),
- 4);
- dwarf2_emit_insn (4);
- fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
- &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_HI16);
- md_number_to_chars (f + 4,
- (MATCH_R1_ORI | SET_IW_I_B (AT_REGNUM)
- | SET_IW_I_A (AT_REGNUM)),
- 4);
- dwarf2_emit_insn (4);
- fix_new_exp (frag_now, f - frag_now->fr_literal + 4, 4,
- &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_LO16);
- md_number_to_chars (f + 8, MATCH_R1_CALLR | SET_IW_R_A (AT_REGNUM), 4);
- dwarf2_emit_insn (4);
- break;
- case iw_L26_type:
- md_number_to_chars (f,
- (MATCH_R2_ORHI | SET_IW_F2I16_B (AT_REGNUM)
- | SET_IW_F2I16_A (0)),
- 4);
- dwarf2_emit_insn (4);
- fix_new_exp (frag_now, f - frag_now->fr_literal, 4,
- &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_HI16);
- md_number_to_chars (f + 4,
- (MATCH_R2_ORI | SET_IW_F2I16_B (AT_REGNUM)
- | SET_IW_F2I16_A (AT_REGNUM)),
- 4);
- dwarf2_emit_insn (4);
- fix_new_exp (frag_now, f - frag_now->fr_literal + 4, 4,
- &reloc->reloc_expression, 0, BFD_RELOC_NIOS2_LO16);
- md_number_to_chars (f + 8, MATCH_R2_CALLR | SET_IW_F3X6L5_A (AT_REGNUM),
- 4);
- dwarf2_emit_insn (4);
- break;
- default:
- bad_opcode (op);
- }
- }
- /* Output a movhi/addi pair for the movia pseudo-op. */
- static void
- output_movia (nios2_insn_infoS *insn)
- {
- /* This allocates enough space for the instruction
- and puts it in the current frag. */
- char *f = frag_more (8);
- nios2_insn_relocS *reloc = insn->insn_reloc;
- unsigned long reg, code;
- const struct nios2_opcode *op = insn->insn_nios2_opcode;
- /* If the reloc is NULL, there was an error assembling the movia. */
- if (reloc != NULL)
- {
- switch (op->format)
- {
- case iw_i_type:
- reg = GET_IW_I_B (insn->insn_code);
- code = MATCH_R1_ADDI | SET_IW_I_A (reg) | SET_IW_I_B (reg);
- break;
- case iw_F2I16_type:
- reg = GET_IW_F2I16_B (insn->insn_code);
- code = MATCH_R2_ADDI | SET_IW_F2I16_A (reg) | SET_IW_F2I16_B (reg);
- break;
- default:
- bad_opcode (op);
- }
- md_number_to_chars (f, insn->insn_code, 4);
- dwarf2_emit_insn (4);
- fix_new (frag_now, f - frag_now->fr_literal, 4,
- reloc->reloc_expression.X_add_symbol,
- reloc->reloc_expression.X_add_number, 0,
- BFD_RELOC_NIOS2_HIADJ16);
- md_number_to_chars (f + 4, code, 4);
- dwarf2_emit_insn (4);
- fix_new (frag_now, f + 4 - frag_now->fr_literal, 4,
- reloc->reloc_expression.X_add_symbol,
- reloc->reloc_expression.X_add_number, 0, BFD_RELOC_NIOS2_LO16);
- }
- }
- /** External interfaces. */
- /* Update the selected architecture based on ARCH, giving an error if
- ARCH is an invalid value. */
- static void
- nios2_use_arch (const char *arch)
- {
- if (strcmp (arch, "nios2") == 0 || strcmp (arch, "r1") == 0)
- {
- nios2_architecture |= EF_NIOS2_ARCH_R1;
- nios2_opcodes = (struct nios2_opcode *) nios2_r1_opcodes;
- nios2_num_opcodes = nios2_num_r1_opcodes;
- nop32 = nop_r1;
- nop16 = NULL;
- return;
- }
- else if (strcmp (arch, "r2") == 0)
- {
- nios2_architecture |= EF_NIOS2_ARCH_R2;
- nios2_opcodes = (struct nios2_opcode *) nios2_r2_opcodes;
- nios2_num_opcodes = nios2_num_r2_opcodes;
- nop32 = nop_r2;
- nop16 = nop_r2_cdx;
- return;
- }
- as_bad (_("unknown architecture '%s'"), arch);
- }
- /* The following functions are called by machine-independent parts of
- the assembler. */
- int
- md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
- {
- switch (c)
- {
- case 'r':
- /* Hidden option for self-test mode. */
- nios2_mode = NIOS2_MODE_TEST;
- break;
- case OPTION_RELAX_ALL:
- nios2_as_options.relax = relax_all;
- break;
- case OPTION_NORELAX:
- nios2_as_options.relax = relax_none;
- break;
- case OPTION_RELAX_SECTION:
- nios2_as_options.relax = relax_section;
- break;
- case OPTION_EB:
- target_big_endian = 1;
- break;
- case OPTION_EL:
- target_big_endian = 0;
- break;
- case OPTION_MARCH:
- nios2_use_arch (arg);
- break;
- default:
- return 0;
- break;
- }
- return 1;
- }
- /* Implement TARGET_FORMAT. We can choose to be big-endian or
- little-endian at runtime based on a switch. */
- const char *
- nios2_target_format (void)
- {
- return target_big_endian ? "elf32-bignios2" : "elf32-littlenios2";
- }
- /* Machine-dependent usage message. */
- void
- md_show_usage (FILE *stream)
- {
- fprintf (stream, " NIOS2 options:\n"
- " -relax-all replace all branch and call "
- "instructions with jmp and callr sequences\n"
- " -relax-section replace identified out of range "
- "branches with jmp sequences (default)\n"
- " -no-relax do not replace any branches or calls\n"
- " -EB force big-endian byte ordering\n"
- " -EL force little-endian byte ordering\n"
- " -march=ARCH enable instructions from architecture ARCH\n");
- }
- /* This function is called once, at assembler startup time.
- It should set up all the tables, etc. that the MD part of the
- assembler will need. */
- void
- md_begin (void)
- {
- int i;
- const char *inserted;
- switch (nios2_architecture)
- {
- default:
- case EF_NIOS2_ARCH_R1:
- bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r1);
- break;
- case EF_NIOS2_ARCH_R2:
- if (target_big_endian)
- as_fatal (_("Big-endian R2 is not supported."));
- bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r2);
- break;
- }
- /* Create and fill a hashtable for the Nios II opcodes, registers and
- arguments. */
- nios2_opcode_hash = hash_new ();
- nios2_reg_hash = hash_new ();
- nios2_ps_hash = hash_new ();
- for (i = 0; i < nios2_num_opcodes; ++i)
- {
- inserted
- = hash_insert (nios2_opcode_hash, nios2_opcodes[i].name,
- (PTR) & nios2_opcodes[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_opcodes[i].name, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- }
- for (i = 0; i < nios2_num_regs; ++i)
- {
- inserted
- = hash_insert (nios2_reg_hash, nios2_regs[i].name,
- (PTR) & nios2_regs[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_regs[i].name, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- }
- for (i = 0; i < nios2_num_ps_insn_info_structs; ++i)
- {
- inserted
- = hash_insert (nios2_ps_hash, nios2_ps_insn_info_structs[i].pseudo_insn,
- (PTR) & nios2_ps_insn_info_structs[i]);
- if (inserted != NULL)
- {
- fprintf (stderr, _("internal error: can't hash `%s': %s\n"),
- nios2_ps_insn_info_structs[i].pseudo_insn, inserted);
- /* Probably a memory allocation problem? Give up now. */
- as_fatal (_("Broken assembler. No assembly attempted."));
- }
- }
- /* Assembler option defaults. */
- nios2_as_options.noat = FALSE;
- nios2_as_options.nobreak = FALSE;
- /* Debug information is incompatible with relaxation. */
- if (debug_type != DEBUG_UNSPECIFIED)
- nios2_as_options.relax = relax_none;
- /* Initialize the alignment data. */
- nios2_current_align_seg = now_seg;
- nios2_last_label = NULL;
- nios2_current_align = 0;
- nios2_min_align = 2;
- }
- /* Assembles a single line of Nios II assembly language. */
- void
- md_assemble (char *op_str)
- {
- char *argstr;
- char *op_strdup = NULL;
- unsigned long saved_pinfo = 0;
- nios2_insn_infoS thisinsn;
- nios2_insn_infoS *insn = &thisinsn;
- /* Make sure we are aligned on an appropriate boundary. */
- if (nios2_current_align < nios2_min_align)
- nios2_align (nios2_min_align, NULL, nios2_last_label);
- else if (nios2_current_align > nios2_min_align)
- nios2_current_align = nios2_min_align;
- nios2_last_label = NULL;
- /* We don't want to clobber to op_str
- because we want to be able to use it in messages. */
- op_strdup = strdup (op_str);
- insn->insn_tokens[0] = strtok (op_strdup, " ");
- argstr = strtok (NULL, "");
- /* Assemble the opcode. */
- insn->insn_nios2_opcode = nios2_opcode_lookup (insn->insn_tokens[0]);
- insn->insn_reloc = NULL;
- if (insn->insn_nios2_opcode != NULL)
- {
- nios2_ps_insn_infoS *ps_insn = NULL;
- /* Note if we've seen a 16-bit instruction. */
- if (insn->insn_nios2_opcode->size == 2)
- nios2_min_align = 1;
- /* Set the opcode for the instruction. */
- insn->insn_code = insn->insn_nios2_opcode->match;
- insn->constant_bits = 0;
- /* Parse the arguments pointed to by argstr. */
- if (nios2_mode == NIOS2_MODE_ASSEMBLE)
- nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args,
- (char **) &insn->insn_tokens[1]);
- else
- nios2_parse_args (insn, argstr, insn->insn_nios2_opcode->args_test,
- (char **) &insn->insn_tokens[1]);
- /* We need to preserve the MOVIA macro as this is clobbered by
- translate_pseudo_insn. */
- if (insn->insn_nios2_opcode->pinfo == NIOS2_INSN_MACRO_MOVIA)
- saved_pinfo = NIOS2_INSN_MACRO_MOVIA;
- /* If the instruction is an pseudo-instruction, we want to replace it
- with its real equivalent, and then continue. */
- if ((insn->insn_nios2_opcode->pinfo & NIOS2_INSN_MACRO)
- == NIOS2_INSN_MACRO)
- ps_insn = nios2_translate_pseudo_insn (insn);
- /* Assemble the parsed arguments into the instruction word. */
- nios2_assemble_args (insn);
- /* Handle relaxation and other transformations. */
- if (nios2_as_options.relax != relax_none
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_UBRANCH)
- output_ubranch (insn);
- else if (nios2_as_options.relax != relax_none
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CBRANCH)
- output_cbranch (insn);
- else if (nios2_as_options.relax == relax_all
- && !nios2_as_options.noat
- && insn->insn_nios2_opcode->pinfo & NIOS2_INSN_CALL
- && insn->insn_reloc
- && ((insn->insn_reloc->reloc_type
- == BFD_RELOC_NIOS2_CALL26)
- || (insn->insn_reloc->reloc_type
- == BFD_RELOC_NIOS2_CALL26_NOAT)))
- output_call (insn);
- else if (saved_pinfo == NIOS2_INSN_MACRO_MOVIA)
- output_movia (insn);
- else
- output_insn (insn);
- if (ps_insn)
- nios2_cleanup_pseudo_insn (insn, ps_insn);
- }
- else
- /* Unrecognised instruction - error. */
- as_bad (_("unrecognised instruction %s"), insn->insn_tokens[0]);
- /* Don't leak memory. */
- free (op_strdup);
- }
- /* Round up section size. */
- valueT
- md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT size)
- {
- /* I think byte alignment is fine here. */
- return size;
- }
- /* Implement TC_FORCE_RELOCATION. */
- int
- nios2_force_relocation (fixS *fixp)
- {
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY
- || fixp->fx_r_type == BFD_RELOC_NIOS2_ALIGN)
- return 1;
- return generic_force_reloc (fixp);
- }
- /* Implement tc_fix_adjustable. */
- int
- nios2_fix_adjustable (fixS *fixp)
- {
- if (fixp->fx_addsy == NULL)
- return 1;
- #ifdef OBJ_ELF
- /* Prevent all adjustments to global symbols. */
- if (OUTPUT_FLAVOR == bfd_target_elf_flavour
- && (S_IS_EXTERNAL (fixp->fx_addsy) || S_IS_WEAK (fixp->fx_addsy)))
- return 0;
- #endif
- if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT
- || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
- return 0;
- /* Preserve relocations against symbols with function type. */
- if (symbol_get_bfdsym (fixp->fx_addsy)->flags & BSF_FUNCTION)
- return 0;
- /* Don't allow symbols to be discarded on GOT related relocs. */
- if (fixp->fx_r_type == BFD_RELOC_NIOS2_GOT16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_LO
- || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF_HA
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_GD16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDM16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LDO16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_IE16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPMOD
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
- || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_TPREL
- || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF
- || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_LO
- || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_HA
- || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_LO
- || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_HA
- )
- return 0;
- return 1;
- }
- /* Implement tc_frob_symbol. This is called in adjust_reloc_syms;
- it is used to remove *ABS* references from the symbol table. */
- int
- nios2_frob_symbol (symbolS *symp)
- {
- if ((OUTPUT_FLAVOR == bfd_target_elf_flavour
- && symp == section_symbol (absolute_section))
- || !S_IS_DEFINED (symp))
- return 1;
- else
- return 0;
- }
- /* The function tc_gen_reloc creates a relocation structure for the
- fixup fixp, and returns a pointer to it. This structure is passed
- to bfd_install_relocation so that it can be written to the object
- file for linking. */
- arelent *
- tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
- {
- arelent *reloc = (arelent *) xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
- *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
- reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
- reloc->addend = fixp->fx_offset; /* fixp->fx_addnumber; */
- if (fixp->fx_pcrel)
- {
- switch (fixp->fx_r_type)
- {
- case BFD_RELOC_16:
- fixp->fx_r_type = BFD_RELOC_16_PCREL;
- break;
- case BFD_RELOC_NIOS2_LO16:
- fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_LO;
- break;
- case BFD_RELOC_NIOS2_HIADJ16:
- fixp->fx_r_type = BFD_RELOC_NIOS2_PCREL_HA;
- break;
- default:
- break;
- }
- }
- reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
- if (reloc->howto == NULL)
- {
- as_bad_where (fixp->fx_file, fixp->fx_line,
- _("can't represent relocation type %s"),
- bfd_get_reloc_code_name (fixp->fx_r_type));
- /* Set howto to a garbage value so that we can keep going. */
- reloc->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32);
- gas_assert (reloc->howto != NULL);
- }
- return reloc;
- }
- long
- md_pcrel_from (fixS *fixP ATTRIBUTE_UNUSED)
- {
- return 0;
- }
- /* Called just before the assembler exits. */
- void
- md_end ()
- {
- /* FIXME - not yet implemented */
- }
- /* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
- Otherwise we have no need to default values of symbols. */
- symbolS *
- md_undefined_symbol (char *name ATTRIBUTE_UNUSED)
- {
- #ifdef OBJ_ELF
- if (name[0] == '_' && name[1] == 'G'
- && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)
- {
- if (!GOT_symbol)
- {
- if (symbol_find (name))
- as_bad ("GOT already in the symbol table");
- GOT_symbol = symbol_new (name, undefined_section,
- (valueT) 0, &zero_address_frag);
- }
- return GOT_symbol;
- }
- #endif
- return 0;
- }
- /* Implement tc_frob_label. */
- void
- nios2_frob_label (symbolS *lab)
- {
- /* Emit dwarf information. */
- dwarf2_emit_label (lab);
- /* Update the label's address with the current output pointer. */
- symbol_set_frag (lab, frag_now);
- S_SET_VALUE (lab, (valueT) frag_now_fix ());
- /* Record this label for future adjustment after we find out what
- kind of data it references, and the required alignment therewith. */
- nios2_last_label = lab;
- }
- /* Implement md_cons_align. */
- void
- nios2_cons_align (int size)
- {
- int log_size = 0;
- const char *pfill = NULL;
- while ((size >>= 1) != 0)
- ++log_size;
- if (subseg_text_p (now_seg))
- pfill = (const char *) nop32;
- else
- pfill = NULL;
- if (nios2_auto_align_on)
- nios2_align (log_size, pfill, NULL);
- nios2_last_label = NULL;
- }
- /* Map 's' to SHF_NIOS2_GPREL. */
- /* This is from the Alpha code tc-alpha.c. */
- int
- nios2_elf_section_letter (int letter, char **ptr_msg)
- {
- if (letter == 's')
- return SHF_NIOS2_GPREL;
- *ptr_msg = _("Bad .section directive: want a,s,w,x,M,S,G,T in string");
- return -1;
- }
- /* Map SHF_ALPHA_GPREL to SEC_SMALL_DATA. */
- /* This is from the Alpha code tc-alpha.c. */
- flagword
- nios2_elf_section_flags (flagword flags, int attr, int type ATTRIBUTE_UNUSED)
- {
- if (attr & SHF_NIOS2_GPREL)
- flags |= SEC_SMALL_DATA;
- return flags;
- }
- /* Implement TC_PARSE_CONS_EXPRESSION to handle %tls_ldo(...) */
- bfd_reloc_code_real_type
- nios2_cons (expressionS *exp, int size)
- {
- bfd_reloc_code_real_type nios2_tls_ldo_reloc = BFD_RELOC_NONE;
- SKIP_WHITESPACE ();
- if (input_line_pointer[0] == '%')
- {
- if (strprefix (input_line_pointer + 1, "tls_ldo"))
- {
- if (size != 4)
- as_bad (_("Illegal operands: %%tls_ldo in %d-byte data field"),
- size);
- else
- {
- input_line_pointer += 8;
- nios2_tls_ldo_reloc = BFD_RELOC_NIOS2_TLS_DTPREL;
- }
- }
- if (nios2_tls_ldo_reloc != BFD_RELOC_NONE)
- {
- SKIP_WHITESPACE ();
- if (input_line_pointer[0] != '(')
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
- else
- {
- int c;
- char *end = ++input_line_pointer;
- int npar = 0;
- for (c = *end; !is_end_of_line[c]; end++, c = *end)
- if (c == '(')
- npar++;
- else if (c == ')')
- {
- if (!npar)
- break;
- npar--;
- }
- if (c != ')')
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
- else
- {
- *end = '\0';
- expression (exp);
- *end = c;
- if (input_line_pointer != end)
- as_bad (_("Illegal operands: %%tls_ldo requires arguments in ()"));
- else
- {
- input_line_pointer++;
- SKIP_WHITESPACE ();
- c = *input_line_pointer;
- if (! is_end_of_line[c] && c != ',')
- as_bad (_("Illegal operands: garbage after %%tls_ldo()"));
- }
- }
- }
- }
- }
- if (nios2_tls_ldo_reloc == BFD_RELOC_NONE)
- expression (exp);
- return nios2_tls_ldo_reloc;
- }
- /* Implement HANDLE_ALIGN. */
- void
- nios2_handle_align (fragS *fragp)
- {
- /* If we are expecting to relax in the linker, then we must output a
- relocation to tell the linker we are aligning code. */
- if (nios2_as_options.relax == relax_all
- && (fragp->fr_type == rs_align || fragp->fr_type == rs_align_code)
- && fragp->fr_address + fragp->fr_fix > 0
- && fragp->fr_offset > 1
- && now_seg != bss_section)
- fix_new (fragp, fragp->fr_fix, 0, &abs_symbol, fragp->fr_offset, 0,
- BFD_RELOC_NIOS2_ALIGN);
- }
- /* Implement tc_regname_to_dw2regnum, to convert REGNAME to a DWARF-2
- register number. */
- int
- nios2_regname_to_dw2regnum (char *regname)
- {
- struct nios2_reg *r = nios2_reg_lookup (regname);
- if (r == NULL)
- return -1;
- return r->index;
- }
- /* Implement tc_cfi_frame_initial_instructions, to initialize the DWARF-2
- unwind information for this procedure. */
- void
- nios2_frame_initial_instructions (void)
- {
- cfi_add_CFA_def_cfa (27, 0);
- }
- #ifdef OBJ_ELF
- /* Some special processing for a Nios II ELF file. */
- void
- nios2_elf_final_processing (void)
- {
- elf_elfheader (stdoutput)->e_flags = nios2_architecture;
- }
- #endif
|