12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419 |
- // script.cc -- handle linker scripts for gold.
- // Copyright (C) 2006-2015 Free Software Foundation, Inc.
- // Written by Ian Lance Taylor <iant@google.com>.
- // This file is part of gold.
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- // MA 02110-1301, USA.
- #include "gold.h"
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <fnmatch.h>
- #include <string>
- #include <vector>
- #include "filenames.h"
- #include "elfcpp.h"
- #include "demangle.h"
- #include "dirsearch.h"
- #include "options.h"
- #include "fileread.h"
- #include "workqueue.h"
- #include "readsyms.h"
- #include "parameters.h"
- #include "layout.h"
- #include "symtab.h"
- #include "target-select.h"
- #include "script.h"
- #include "script-c.h"
- #include "incremental.h"
- namespace gold
- {
- // A token read from a script file. We don't implement keywords here;
- // all keywords are simply represented as a string.
- class Token
- {
- public:
- // Token classification.
- enum Classification
- {
- // Token is invalid.
- TOKEN_INVALID,
- // Token indicates end of input.
- TOKEN_EOF,
- // Token is a string of characters.
- TOKEN_STRING,
- // Token is a quoted string of characters.
- TOKEN_QUOTED_STRING,
- // Token is an operator.
- TOKEN_OPERATOR,
- // Token is a number (an integer).
- TOKEN_INTEGER
- };
- // We need an empty constructor so that we can put this STL objects.
- Token()
- : classification_(TOKEN_INVALID), value_(NULL), value_length_(0),
- opcode_(0), lineno_(0), charpos_(0)
- { }
- // A general token with no value.
- Token(Classification classification, int lineno, int charpos)
- : classification_(classification), value_(NULL), value_length_(0),
- opcode_(0), lineno_(lineno), charpos_(charpos)
- {
- gold_assert(classification == TOKEN_INVALID
- || classification == TOKEN_EOF);
- }
- // A general token with a value.
- Token(Classification classification, const char* value, size_t length,
- int lineno, int charpos)
- : classification_(classification), value_(value), value_length_(length),
- opcode_(0), lineno_(lineno), charpos_(charpos)
- {
- gold_assert(classification != TOKEN_INVALID
- && classification != TOKEN_EOF);
- }
- // A token representing an operator.
- Token(int opcode, int lineno, int charpos)
- : classification_(TOKEN_OPERATOR), value_(NULL), value_length_(0),
- opcode_(opcode), lineno_(lineno), charpos_(charpos)
- { }
- // Return whether the token is invalid.
- bool
- is_invalid() const
- { return this->classification_ == TOKEN_INVALID; }
- // Return whether this is an EOF token.
- bool
- is_eof() const
- { return this->classification_ == TOKEN_EOF; }
- // Return the token classification.
- Classification
- classification() const
- { return this->classification_; }
- // Return the line number at which the token starts.
- int
- lineno() const
- { return this->lineno_; }
- // Return the character position at this the token starts.
- int
- charpos() const
- { return this->charpos_; }
- // Get the value of a token.
- const char*
- string_value(size_t* length) const
- {
- gold_assert(this->classification_ == TOKEN_STRING
- || this->classification_ == TOKEN_QUOTED_STRING);
- *length = this->value_length_;
- return this->value_;
- }
- int
- operator_value() const
- {
- gold_assert(this->classification_ == TOKEN_OPERATOR);
- return this->opcode_;
- }
- uint64_t
- integer_value() const;
- private:
- // The token classification.
- Classification classification_;
- // The token value, for TOKEN_STRING or TOKEN_QUOTED_STRING or
- // TOKEN_INTEGER.
- const char* value_;
- // The length of the token value.
- size_t value_length_;
- // The token value, for TOKEN_OPERATOR.
- int opcode_;
- // The line number where this token started (one based).
- int lineno_;
- // The character position within the line where this token started
- // (one based).
- int charpos_;
- };
- // Return the value of a TOKEN_INTEGER.
- uint64_t
- Token::integer_value() const
- {
- gold_assert(this->classification_ == TOKEN_INTEGER);
- size_t len = this->value_length_;
- uint64_t multiplier = 1;
- char last = this->value_[len - 1];
- if (last == 'm' || last == 'M')
- {
- multiplier = 1024 * 1024;
- --len;
- }
- else if (last == 'k' || last == 'K')
- {
- multiplier = 1024;
- --len;
- }
- char *end;
- uint64_t ret = strtoull(this->value_, &end, 0);
- gold_assert(static_cast<size_t>(end - this->value_) == len);
- return ret * multiplier;
- }
- // This class handles lexing a file into a sequence of tokens.
- class Lex
- {
- public:
- // We unfortunately have to support different lexing modes, because
- // when reading different parts of a linker script we need to parse
- // things differently.
- enum Mode
- {
- // Reading an ordinary linker script.
- LINKER_SCRIPT,
- // Reading an expression in a linker script.
- EXPRESSION,
- // Reading a version script.
- VERSION_SCRIPT,
- // Reading a --dynamic-list file.
- DYNAMIC_LIST
- };
- Lex(const char* input_string, size_t input_length, int parsing_token)
- : input_string_(input_string), input_length_(input_length),
- current_(input_string), mode_(LINKER_SCRIPT),
- first_token_(parsing_token), token_(),
- lineno_(1), linestart_(input_string)
- { }
- // Read a file into a string.
- static void
- read_file(Input_file*, std::string*);
- // Return the next token.
- const Token*
- next_token();
- // Return the current lexing mode.
- Lex::Mode
- mode() const
- { return this->mode_; }
- // Set the lexing mode.
- void
- set_mode(Mode mode)
- { this->mode_ = mode; }
- private:
- Lex(const Lex&);
- Lex& operator=(const Lex&);
- // Make a general token with no value at the current location.
- Token
- make_token(Token::Classification c, const char* start) const
- { return Token(c, this->lineno_, start - this->linestart_ + 1); }
- // Make a general token with a value at the current location.
- Token
- make_token(Token::Classification c, const char* v, size_t len,
- const char* start)
- const
- { return Token(c, v, len, this->lineno_, start - this->linestart_ + 1); }
- // Make an operator token at the current location.
- Token
- make_token(int opcode, const char* start) const
- { return Token(opcode, this->lineno_, start - this->linestart_ + 1); }
- // Make an invalid token at the current location.
- Token
- make_invalid_token(const char* start)
- { return this->make_token(Token::TOKEN_INVALID, start); }
- // Make an EOF token at the current location.
- Token
- make_eof_token(const char* start)
- { return this->make_token(Token::TOKEN_EOF, start); }
- // Return whether C can be the first character in a name. C2 is the
- // next character, since we sometimes need that.
- inline bool
- can_start_name(char c, char c2);
- // If C can appear in a name which has already started, return a
- // pointer to a character later in the token or just past
- // it. Otherwise, return NULL.
- inline const char*
- can_continue_name(const char* c);
- // Return whether C, C2, C3 can start a hex number.
- inline bool
- can_start_hex(char c, char c2, char c3);
- // If C can appear in a hex number which has already started, return
- // a pointer to a character later in the token or just past
- // it. Otherwise, return NULL.
- inline const char*
- can_continue_hex(const char* c);
- // Return whether C can start a non-hex number.
- static inline bool
- can_start_number(char c);
- // If C can appear in a decimal number which has already started,
- // return a pointer to a character later in the token or just past
- // it. Otherwise, return NULL.
- inline const char*
- can_continue_number(const char* c)
- { return Lex::can_start_number(*c) ? c + 1 : NULL; }
- // If C1 C2 C3 form a valid three character operator, return the
- // opcode. Otherwise return 0.
- static inline int
- three_char_operator(char c1, char c2, char c3);
- // If C1 C2 form a valid two character operator, return the opcode.
- // Otherwise return 0.
- static inline int
- two_char_operator(char c1, char c2);
- // If C1 is a valid one character operator, return the opcode.
- // Otherwise return 0.
- static inline int
- one_char_operator(char c1);
- // Read the next token.
- Token
- get_token(const char**);
- // Skip a C style /* */ comment. Return false if the comment did
- // not end.
- bool
- skip_c_comment(const char**);
- // Skip a line # comment. Return false if there was no newline.
- bool
- skip_line_comment(const char**);
- // Build a token CLASSIFICATION from all characters that match
- // CAN_CONTINUE_FN. The token starts at START. Start matching from
- // MATCH. Set *PP to the character following the token.
- inline Token
- gather_token(Token::Classification,
- const char* (Lex::*can_continue_fn)(const char*),
- const char* start, const char* match, const char** pp);
- // Build a token from a quoted string.
- Token
- gather_quoted_string(const char** pp);
- // The string we are tokenizing.
- const char* input_string_;
- // The length of the string.
- size_t input_length_;
- // The current offset into the string.
- const char* current_;
- // The current lexing mode.
- Mode mode_;
- // The code to use for the first token. This is set to 0 after it
- // is used.
- int first_token_;
- // The current token.
- Token token_;
- // The current line number.
- int lineno_;
- // The start of the current line in the string.
- const char* linestart_;
- };
- // Read the whole file into memory. We don't expect linker scripts to
- // be large, so we just use a std::string as a buffer. We ignore the
- // data we've already read, so that we read aligned buffers.
- void
- Lex::read_file(Input_file* input_file, std::string* contents)
- {
- off_t filesize = input_file->file().filesize();
- contents->clear();
- contents->reserve(filesize);
- off_t off = 0;
- unsigned char buf[BUFSIZ];
- while (off < filesize)
- {
- off_t get = BUFSIZ;
- if (get > filesize - off)
- get = filesize - off;
- input_file->file().read(off, get, buf);
- contents->append(reinterpret_cast<char*>(&buf[0]), get);
- off += get;
- }
- }
- // Return whether C can be the start of a name, if the next character
- // is C2. A name can being with a letter, underscore, period, or
- // dollar sign. Because a name can be a file name, we also permit
- // forward slash, backslash, and tilde. Tilde is the tricky case
- // here; GNU ld also uses it as a bitwise not operator. It is only
- // recognized as the operator if it is not immediately followed by
- // some character which can appear in a symbol. That is, when we
- // don't know that we are looking at an expression, "~0" is a file
- // name, and "~ 0" is an expression using bitwise not. We are
- // compatible.
- inline bool
- Lex::can_start_name(char c, char c2)
- {
- switch (c)
- {
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case '_': case '.': case '$':
- return true;
- case '/': case '\\':
- return this->mode_ == LINKER_SCRIPT;
- case '~':
- return this->mode_ == LINKER_SCRIPT && can_continue_name(&c2);
- case '*': case '[':
- return (this->mode_ == VERSION_SCRIPT
- || this->mode_ == DYNAMIC_LIST
- || (this->mode_ == LINKER_SCRIPT
- && can_continue_name(&c2)));
- default:
- return false;
- }
- }
- // Return whether C can continue a name which has already started.
- // Subsequent characters in a name are the same as the leading
- // characters, plus digits and "=+-:[],?*". So in general the linker
- // script language requires spaces around operators, unless we know
- // that we are parsing an expression.
- inline const char*
- Lex::can_continue_name(const char* c)
- {
- switch (*c)
- {
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
- case 'M': case 'N': case 'O': case 'Q': case 'P': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'q': case 'p': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case '_': case '.': case '$':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return c + 1;
- // TODO(csilvers): why not allow ~ in names for version-scripts?
- case '/': case '\\': case '~':
- case '=': case '+':
- case ',':
- if (this->mode_ == LINKER_SCRIPT)
- return c + 1;
- return NULL;
- case '[': case ']': case '*': case '?': case '-':
- if (this->mode_ == LINKER_SCRIPT || this->mode_ == VERSION_SCRIPT
- || this->mode_ == DYNAMIC_LIST)
- return c + 1;
- return NULL;
- // TODO(csilvers): why allow this? ^ is meaningless in version scripts.
- case '^':
- if (this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
- return c + 1;
- return NULL;
- case ':':
- if (this->mode_ == LINKER_SCRIPT)
- return c + 1;
- else if ((this->mode_ == VERSION_SCRIPT || this->mode_ == DYNAMIC_LIST)
- && (c[1] == ':'))
- {
- // A name can have '::' in it, as that's a c++ namespace
- // separator. But a single colon is not part of a name.
- return c + 2;
- }
- return NULL;
- default:
- return NULL;
- }
- }
- // For a number we accept 0x followed by hex digits, or any sequence
- // of digits. The old linker accepts leading '$' for hex, and
- // trailing HXBOD. Those are for MRI compatibility and we don't
- // accept them.
- // Return whether C1 C2 C3 can start a hex number.
- inline bool
- Lex::can_start_hex(char c1, char c2, char c3)
- {
- if (c1 == '0' && (c2 == 'x' || c2 == 'X'))
- return this->can_continue_hex(&c3);
- return false;
- }
- // Return whether C can appear in a hex number.
- inline const char*
- Lex::can_continue_hex(const char* c)
- {
- switch (*c)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- return c + 1;
- default:
- return NULL;
- }
- }
- // Return whether C can start a non-hex number.
- inline bool
- Lex::can_start_number(char c)
- {
- switch (c)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- return true;
- default:
- return false;
- }
- }
- // If C1 C2 C3 form a valid three character operator, return the
- // opcode (defined in the yyscript.h file generated from yyscript.y).
- // Otherwise return 0.
- inline int
- Lex::three_char_operator(char c1, char c2, char c3)
- {
- switch (c1)
- {
- case '<':
- if (c2 == '<' && c3 == '=')
- return LSHIFTEQ;
- break;
- case '>':
- if (c2 == '>' && c3 == '=')
- return RSHIFTEQ;
- break;
- default:
- break;
- }
- return 0;
- }
- // If C1 C2 form a valid two character operator, return the opcode
- // (defined in the yyscript.h file generated from yyscript.y).
- // Otherwise return 0.
- inline int
- Lex::two_char_operator(char c1, char c2)
- {
- switch (c1)
- {
- case '=':
- if (c2 == '=')
- return EQ;
- break;
- case '!':
- if (c2 == '=')
- return NE;
- break;
- case '+':
- if (c2 == '=')
- return PLUSEQ;
- break;
- case '-':
- if (c2 == '=')
- return MINUSEQ;
- break;
- case '*':
- if (c2 == '=')
- return MULTEQ;
- break;
- case '/':
- if (c2 == '=')
- return DIVEQ;
- break;
- case '|':
- if (c2 == '=')
- return OREQ;
- if (c2 == '|')
- return OROR;
- break;
- case '&':
- if (c2 == '=')
- return ANDEQ;
- if (c2 == '&')
- return ANDAND;
- break;
- case '>':
- if (c2 == '=')
- return GE;
- if (c2 == '>')
- return RSHIFT;
- break;
- case '<':
- if (c2 == '=')
- return LE;
- if (c2 == '<')
- return LSHIFT;
- break;
- default:
- break;
- }
- return 0;
- }
- // If C1 is a valid operator, return the opcode. Otherwise return 0.
- inline int
- Lex::one_char_operator(char c1)
- {
- switch (c1)
- {
- case '+':
- case '-':
- case '*':
- case '/':
- case '%':
- case '!':
- case '&':
- case '|':
- case '^':
- case '~':
- case '<':
- case '>':
- case '=':
- case '?':
- case ',':
- case '(':
- case ')':
- case '{':
- case '}':
- case '[':
- case ']':
- case ':':
- case ';':
- return c1;
- default:
- return 0;
- }
- }
- // Skip a C style comment. *PP points to just after the "/*". Return
- // false if the comment did not end.
- bool
- Lex::skip_c_comment(const char** pp)
- {
- const char* p = *pp;
- while (p[0] != '*' || p[1] != '/')
- {
- if (*p == '\0')
- {
- *pp = p;
- return false;
- }
- if (*p == '\n')
- {
- ++this->lineno_;
- this->linestart_ = p + 1;
- }
- ++p;
- }
- *pp = p + 2;
- return true;
- }
- // Skip a line # comment. Return false if there was no newline.
- bool
- Lex::skip_line_comment(const char** pp)
- {
- const char* p = *pp;
- size_t skip = strcspn(p, "\n");
- if (p[skip] == '\0')
- {
- *pp = p + skip;
- return false;
- }
- p += skip + 1;
- ++this->lineno_;
- this->linestart_ = p;
- *pp = p;
- return true;
- }
- // Build a token CLASSIFICATION from all characters that match
- // CAN_CONTINUE_FN. Update *PP.
- inline Token
- Lex::gather_token(Token::Classification classification,
- const char* (Lex::*can_continue_fn)(const char*),
- const char* start,
- const char* match,
- const char** pp)
- {
- const char* new_match = NULL;
- while ((new_match = (this->*can_continue_fn)(match)) != NULL)
- match = new_match;
- // A special case: integers may be followed by a single M or K,
- // case-insensitive.
- if (classification == Token::TOKEN_INTEGER
- && (*match == 'm' || *match == 'M' || *match == 'k' || *match == 'K'))
- ++match;
- *pp = match;
- return this->make_token(classification, start, match - start, start);
- }
- // Build a token from a quoted string.
- Token
- Lex::gather_quoted_string(const char** pp)
- {
- const char* start = *pp;
- const char* p = start;
- ++p;
- size_t skip = strcspn(p, "\"\n");
- if (p[skip] != '"')
- return this->make_invalid_token(start);
- *pp = p + skip + 1;
- return this->make_token(Token::TOKEN_QUOTED_STRING, p, skip, start);
- }
- // Return the next token at *PP. Update *PP. General guideline: we
- // require linker scripts to be simple ASCII. No unicode linker
- // scripts. In particular we can assume that any '\0' is the end of
- // the input.
- Token
- Lex::get_token(const char** pp)
- {
- const char* p = *pp;
- while (true)
- {
- if (*p == '\0')
- {
- *pp = p;
- return this->make_eof_token(p);
- }
- // Skip whitespace quickly.
- while (*p == ' ' || *p == '\t' || *p == '\r')
- ++p;
- if (*p == '\n')
- {
- ++p;
- ++this->lineno_;
- this->linestart_ = p;
- continue;
- }
- // Skip C style comments.
- if (p[0] == '/' && p[1] == '*')
- {
- int lineno = this->lineno_;
- int charpos = p - this->linestart_ + 1;
- *pp = p + 2;
- if (!this->skip_c_comment(pp))
- return Token(Token::TOKEN_INVALID, lineno, charpos);
- p = *pp;
- continue;
- }
- // Skip line comments.
- if (*p == '#')
- {
- *pp = p + 1;
- if (!this->skip_line_comment(pp))
- return this->make_eof_token(p);
- p = *pp;
- continue;
- }
- // Check for a name.
- if (this->can_start_name(p[0], p[1]))
- return this->gather_token(Token::TOKEN_STRING,
- &Lex::can_continue_name,
- p, p + 1, pp);
- // We accept any arbitrary name in double quotes, as long as it
- // does not cross a line boundary.
- if (*p == '"')
- {
- *pp = p;
- return this->gather_quoted_string(pp);
- }
- // Check for a number.
- if (this->can_start_hex(p[0], p[1], p[2]))
- return this->gather_token(Token::TOKEN_INTEGER,
- &Lex::can_continue_hex,
- p, p + 3, pp);
- if (Lex::can_start_number(p[0]))
- return this->gather_token(Token::TOKEN_INTEGER,
- &Lex::can_continue_number,
- p, p + 1, pp);
- // Check for operators.
- int opcode = Lex::three_char_operator(p[0], p[1], p[2]);
- if (opcode != 0)
- {
- *pp = p + 3;
- return this->make_token(opcode, p);
- }
- opcode = Lex::two_char_operator(p[0], p[1]);
- if (opcode != 0)
- {
- *pp = p + 2;
- return this->make_token(opcode, p);
- }
- opcode = Lex::one_char_operator(p[0]);
- if (opcode != 0)
- {
- *pp = p + 1;
- return this->make_token(opcode, p);
- }
- return this->make_token(Token::TOKEN_INVALID, p);
- }
- }
- // Return the next token.
- const Token*
- Lex::next_token()
- {
- // The first token is special.
- if (this->first_token_ != 0)
- {
- this->token_ = Token(this->first_token_, 0, 0);
- this->first_token_ = 0;
- return &this->token_;
- }
- this->token_ = this->get_token(&this->current_);
- // Don't let an early null byte fool us into thinking that we've
- // reached the end of the file.
- if (this->token_.is_eof()
- && (static_cast<size_t>(this->current_ - this->input_string_)
- < this->input_length_))
- this->token_ = this->make_invalid_token(this->current_);
- return &this->token_;
- }
- // class Symbol_assignment.
- // Add the symbol to the symbol table. This makes sure the symbol is
- // there and defined. The actual value is stored later. We can't
- // determine the actual value at this point, because we can't
- // necessarily evaluate the expression until all ordinary symbols have
- // been finalized.
- // The GNU linker lets symbol assignments in the linker script
- // silently override defined symbols in object files. We are
- // compatible. FIXME: Should we issue a warning?
- void
- Symbol_assignment::add_to_table(Symbol_table* symtab)
- {
- elfcpp::STV vis = this->hidden_ ? elfcpp::STV_HIDDEN : elfcpp::STV_DEFAULT;
- this->sym_ = symtab->define_as_constant(this->name_.c_str(),
- NULL, // version
- (this->is_defsym_
- ? Symbol_table::DEFSYM
- : Symbol_table::SCRIPT),
- 0, // value
- 0, // size
- elfcpp::STT_NOTYPE,
- elfcpp::STB_GLOBAL,
- vis,
- 0, // nonvis
- this->provide_,
- true); // force_override
- }
- // Finalize a symbol value.
- void
- Symbol_assignment::finalize(Symbol_table* symtab, const Layout* layout)
- {
- this->finalize_maybe_dot(symtab, layout, false, 0, NULL);
- }
- // Finalize a symbol value which can refer to the dot symbol.
- void
- Symbol_assignment::finalize_with_dot(Symbol_table* symtab,
- const Layout* layout,
- uint64_t dot_value,
- Output_section* dot_section)
- {
- this->finalize_maybe_dot(symtab, layout, true, dot_value, dot_section);
- }
- // Finalize a symbol value, internal version.
- void
- Symbol_assignment::finalize_maybe_dot(Symbol_table* symtab,
- const Layout* layout,
- bool is_dot_available,
- uint64_t dot_value,
- Output_section* dot_section)
- {
- // If we were only supposed to provide this symbol, the sym_ field
- // will be NULL if the symbol was not referenced.
- if (this->sym_ == NULL)
- {
- gold_assert(this->provide_);
- return;
- }
- if (parameters->target().get_size() == 32)
- {
- #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
- this->sized_finalize<32>(symtab, layout, is_dot_available, dot_value,
- dot_section);
- #else
- gold_unreachable();
- #endif
- }
- else if (parameters->target().get_size() == 64)
- {
- #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
- this->sized_finalize<64>(symtab, layout, is_dot_available, dot_value,
- dot_section);
- #else
- gold_unreachable();
- #endif
- }
- else
- gold_unreachable();
- }
- template<int size>
- void
- Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
- bool is_dot_available, uint64_t dot_value,
- Output_section* dot_section)
- {
- Output_section* section;
- elfcpp::STT type = elfcpp::STT_NOTYPE;
- elfcpp::STV vis = elfcpp::STV_DEFAULT;
- unsigned char nonvis = 0;
- uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, true,
- is_dot_available,
- dot_value, dot_section,
- §ion, NULL, &type,
- &vis, &nonvis, false, NULL);
- Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
- ssym->set_value(final_val);
- ssym->set_type(type);
- ssym->set_visibility(vis);
- ssym->set_nonvis(nonvis);
- if (section != NULL)
- ssym->set_output_section(section);
- }
- // Set the symbol value if the expression yields an absolute value or
- // a value relative to DOT_SECTION.
- void
- Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
- bool is_dot_available, uint64_t dot_value,
- Output_section* dot_section)
- {
- if (this->sym_ == NULL)
- return;
- Output_section* val_section;
- bool is_valid;
- uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
- is_dot_available, dot_value,
- dot_section, &val_section, NULL,
- NULL, NULL, NULL, false, &is_valid);
- if (!is_valid || (val_section != NULL && val_section != dot_section))
- return;
- if (parameters->target().get_size() == 32)
- {
- #if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG)
- Sized_symbol<32>* ssym = symtab->get_sized_symbol<32>(this->sym_);
- ssym->set_value(val);
- #else
- gold_unreachable();
- #endif
- }
- else if (parameters->target().get_size() == 64)
- {
- #if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG)
- Sized_symbol<64>* ssym = symtab->get_sized_symbol<64>(this->sym_);
- ssym->set_value(val);
- #else
- gold_unreachable();
- #endif
- }
- else
- gold_unreachable();
- if (val_section != NULL)
- this->sym_->set_output_section(val_section);
- }
- // Print for debugging.
- void
- Symbol_assignment::print(FILE* f) const
- {
- if (this->provide_ && this->hidden_)
- fprintf(f, "PROVIDE_HIDDEN(");
- else if (this->provide_)
- fprintf(f, "PROVIDE(");
- else if (this->hidden_)
- gold_unreachable();
- fprintf(f, "%s = ", this->name_.c_str());
- this->val_->print(f);
- if (this->provide_ || this->hidden_)
- fprintf(f, ")");
- fprintf(f, "\n");
- }
- // Class Script_assertion.
- // Check the assertion.
- void
- Script_assertion::check(const Symbol_table* symtab, const Layout* layout)
- {
- if (!this->check_->eval(symtab, layout, true))
- gold_error("%s", this->message_.c_str());
- }
- // Print for debugging.
- void
- Script_assertion::print(FILE* f) const
- {
- fprintf(f, "ASSERT(");
- this->check_->print(f);
- fprintf(f, ", \"%s\")\n", this->message_.c_str());
- }
- // Class Script_options.
- Script_options::Script_options()
- : entry_(), symbol_assignments_(), symbol_definitions_(),
- symbol_references_(), version_script_info_(), script_sections_()
- {
- }
- // Returns true if NAME is on the list of symbol assignments waiting
- // to be processed.
- bool
- Script_options::is_pending_assignment(const char* name)
- {
- for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
- p != this->symbol_assignments_.end();
- ++p)
- if ((*p)->name() == name)
- return true;
- return false;
- }
- // Add a symbol to be defined.
- void
- Script_options::add_symbol_assignment(const char* name, size_t length,
- bool is_defsym, Expression* value,
- bool provide, bool hidden)
- {
- if (length != 1 || name[0] != '.')
- {
- if (this->script_sections_.in_sections_clause())
- {
- gold_assert(!is_defsym);
- this->script_sections_.add_symbol_assignment(name, length, value,
- provide, hidden);
- }
- else
- {
- Symbol_assignment* p = new Symbol_assignment(name, length, is_defsym,
- value, provide, hidden);
- this->symbol_assignments_.push_back(p);
- }
- if (!provide)
- {
- std::string n(name, length);
- this->symbol_definitions_.insert(n);
- this->symbol_references_.erase(n);
- }
- }
- else
- {
- if (provide || hidden)
- gold_error(_("invalid use of PROVIDE for dot symbol"));
- // The GNU linker permits assignments to dot outside of SECTIONS
- // clauses and treats them as occurring inside, so we don't
- // check in_sections_clause here.
- this->script_sections_.add_dot_assignment(value);
- }
- }
- // Add a reference to a symbol.
- void
- Script_options::add_symbol_reference(const char* name, size_t length)
- {
- if (length != 1 || name[0] != '.')
- {
- std::string n(name, length);
- if (this->symbol_definitions_.find(n) == this->symbol_definitions_.end())
- this->symbol_references_.insert(n);
- }
- }
- // Add an assertion.
- void
- Script_options::add_assertion(Expression* check, const char* message,
- size_t messagelen)
- {
- if (this->script_sections_.in_sections_clause())
- this->script_sections_.add_assertion(check, message, messagelen);
- else
- {
- Script_assertion* p = new Script_assertion(check, message, messagelen);
- this->assertions_.push_back(p);
- }
- }
- // Create sections required by any linker scripts.
- void
- Script_options::create_script_sections(Layout* layout)
- {
- if (this->saw_sections_clause())
- this->script_sections_.create_sections(layout);
- }
- // Add any symbols we are defining to the symbol table.
- void
- Script_options::add_symbols_to_table(Symbol_table* symtab)
- {
- for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
- p != this->symbol_assignments_.end();
- ++p)
- (*p)->add_to_table(symtab);
- this->script_sections_.add_symbols_to_table(symtab);
- }
- // Finalize symbol values. Also check assertions.
- void
- Script_options::finalize_symbols(Symbol_table* symtab, const Layout* layout)
- {
- // We finalize the symbols defined in SECTIONS first, because they
- // are the ones which may have changed. This way if symbol outside
- // SECTIONS are defined in terms of symbols inside SECTIONS, they
- // will get the right value.
- this->script_sections_.finalize_symbols(symtab, layout);
- for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
- p != this->symbol_assignments_.end();
- ++p)
- (*p)->finalize(symtab, layout);
- for (Assertions::iterator p = this->assertions_.begin();
- p != this->assertions_.end();
- ++p)
- (*p)->check(symtab, layout);
- }
- // Set section addresses. We set all the symbols which have absolute
- // values. Then we let the SECTIONS clause do its thing. This
- // returns the segment which holds the file header and segment
- // headers, if any.
- Output_segment*
- Script_options::set_section_addresses(Symbol_table* symtab, Layout* layout)
- {
- for (Symbol_assignments::iterator p = this->symbol_assignments_.begin();
- p != this->symbol_assignments_.end();
- ++p)
- (*p)->set_if_absolute(symtab, layout, false, 0, NULL);
- return this->script_sections_.set_section_addresses(symtab, layout);
- }
- // This class holds data passed through the parser to the lexer and to
- // the parser support functions. This avoids global variables. We
- // can't use global variables because we need not be called by a
- // singleton thread.
- class Parser_closure
- {
- public:
- Parser_closure(const char* filename,
- const Position_dependent_options& posdep_options,
- bool parsing_defsym, bool in_group, bool is_in_sysroot,
- Command_line* command_line,
- Script_options* script_options,
- Lex* lex,
- bool skip_on_incompatible_target,
- Script_info* script_info)
- : filename_(filename), posdep_options_(posdep_options),
- parsing_defsym_(parsing_defsym), in_group_(in_group),
- is_in_sysroot_(is_in_sysroot),
- skip_on_incompatible_target_(skip_on_incompatible_target),
- found_incompatible_target_(false),
- command_line_(command_line), script_options_(script_options),
- version_script_info_(script_options->version_script_info()),
- lex_(lex), lineno_(0), charpos_(0), lex_mode_stack_(), inputs_(NULL),
- script_info_(script_info)
- {
- // We start out processing C symbols in the default lex mode.
- this->language_stack_.push_back(Version_script_info::LANGUAGE_C);
- this->lex_mode_stack_.push_back(lex->mode());
- }
- // Return the file name.
- const char*
- filename() const
- { return this->filename_; }
- // Return the position dependent options. The caller may modify
- // this.
- Position_dependent_options&
- position_dependent_options()
- { return this->posdep_options_; }
- // Whether we are parsing a --defsym.
- bool
- parsing_defsym() const
- { return this->parsing_defsym_; }
- // Return whether this script is being run in a group.
- bool
- in_group() const
- { return this->in_group_; }
- // Return whether this script was found using a directory in the
- // sysroot.
- bool
- is_in_sysroot() const
- { return this->is_in_sysroot_; }
- // Whether to skip to the next file with the same name if we find an
- // incompatible target in an OUTPUT_FORMAT statement.
- bool
- skip_on_incompatible_target() const
- { return this->skip_on_incompatible_target_; }
- // Stop skipping to the next file on an incompatible target. This
- // is called when we make some unrevocable change to the data
- // structures.
- void
- clear_skip_on_incompatible_target()
- { this->skip_on_incompatible_target_ = false; }
- // Whether we found an incompatible target in an OUTPUT_FORMAT
- // statement.
- bool
- found_incompatible_target() const
- { return this->found_incompatible_target_; }
- // Note that we found an incompatible target.
- void
- set_found_incompatible_target()
- { this->found_incompatible_target_ = true; }
- // Returns the Command_line structure passed in at constructor time.
- // This value may be NULL. The caller may modify this, which modifies
- // the passed-in Command_line object (not a copy).
- Command_line*
- command_line()
- { return this->command_line_; }
- // Return the options which may be set by a script.
- Script_options*
- script_options()
- { return this->script_options_; }
- // Return the object in which version script information should be stored.
- Version_script_info*
- version_script()
- { return this->version_script_info_; }
- // Return the next token, and advance.
- const Token*
- next_token()
- {
- const Token* token = this->lex_->next_token();
- this->lineno_ = token->lineno();
- this->charpos_ = token->charpos();
- return token;
- }
- // Set a new lexer mode, pushing the current one.
- void
- push_lex_mode(Lex::Mode mode)
- {
- this->lex_mode_stack_.push_back(this->lex_->mode());
- this->lex_->set_mode(mode);
- }
- // Pop the lexer mode.
- void
- pop_lex_mode()
- {
- gold_assert(!this->lex_mode_stack_.empty());
- this->lex_->set_mode(this->lex_mode_stack_.back());
- this->lex_mode_stack_.pop_back();
- }
- // Return the current lexer mode.
- Lex::Mode
- lex_mode() const
- { return this->lex_mode_stack_.back(); }
- // Return the line number of the last token.
- int
- lineno() const
- { return this->lineno_; }
- // Return the character position in the line of the last token.
- int
- charpos() const
- { return this->charpos_; }
- // Return the list of input files, creating it if necessary. This
- // is a space leak--we never free the INPUTS_ pointer.
- Input_arguments*
- inputs()
- {
- if (this->inputs_ == NULL)
- this->inputs_ = new Input_arguments();
- return this->inputs_;
- }
- // Return whether we saw any input files.
- bool
- saw_inputs() const
- { return this->inputs_ != NULL && !this->inputs_->empty(); }
- // Return the current language being processed in a version script
- // (eg, "C++"). The empty string represents unmangled C names.
- Version_script_info::Language
- get_current_language() const
- { return this->language_stack_.back(); }
- // Push a language onto the stack when entering an extern block.
- void
- push_language(Version_script_info::Language lang)
- { this->language_stack_.push_back(lang); }
- // Pop a language off of the stack when exiting an extern block.
- void
- pop_language()
- {
- gold_assert(!this->language_stack_.empty());
- this->language_stack_.pop_back();
- }
- // Return a pointer to the incremental info.
- Script_info*
- script_info()
- { return this->script_info_; }
- private:
- // The name of the file we are reading.
- const char* filename_;
- // The position dependent options.
- Position_dependent_options posdep_options_;
- // True if we are parsing a --defsym.
- bool parsing_defsym_;
- // Whether we are currently in a --start-group/--end-group.
- bool in_group_;
- // Whether the script was found in a sysrooted directory.
- bool is_in_sysroot_;
- // If this is true, then if we find an OUTPUT_FORMAT with an
- // incompatible target, then we tell the parser to abort so that we
- // can search for the next file with the same name.
- bool skip_on_incompatible_target_;
- // True if we found an OUTPUT_FORMAT with an incompatible target.
- bool found_incompatible_target_;
- // May be NULL if the user chooses not to pass one in.
- Command_line* command_line_;
- // Options which may be set from any linker script.
- Script_options* script_options_;
- // Information parsed from a version script.
- Version_script_info* version_script_info_;
- // The lexer.
- Lex* lex_;
- // The line number of the last token returned by next_token.
- int lineno_;
- // The column number of the last token returned by next_token.
- int charpos_;
- // A stack of lexer modes.
- std::vector<Lex::Mode> lex_mode_stack_;
- // A stack of which extern/language block we're inside. Can be C++,
- // java, or empty for C.
- std::vector<Version_script_info::Language> language_stack_;
- // New input files found to add to the link.
- Input_arguments* inputs_;
- // Pointer to incremental linking info.
- Script_info* script_info_;
- };
- // FILE was found as an argument on the command line. Try to read it
- // as a script. Return true if the file was handled.
- bool
- read_input_script(Workqueue* workqueue, Symbol_table* symtab, Layout* layout,
- Dirsearch* dirsearch, int dirindex,
- Input_objects* input_objects, Mapfile* mapfile,
- Input_group* input_group,
- const Input_argument* input_argument,
- Input_file* input_file, Task_token* next_blocker,
- bool* used_next_blocker)
- {
- *used_next_blocker = false;
- std::string input_string;
- Lex::read_file(input_file, &input_string);
- Lex lex(input_string.c_str(), input_string.length(), PARSING_LINKER_SCRIPT);
- Script_info* script_info = NULL;
- if (layout->incremental_inputs() != NULL)
- {
- const std::string& filename = input_file->filename();
- Timespec mtime = input_file->file().get_mtime();
- unsigned int arg_serial = input_argument->file().arg_serial();
- script_info = new Script_info(filename);
- layout->incremental_inputs()->report_script(script_info, arg_serial,
- mtime);
- }
- Parser_closure closure(input_file->filename().c_str(),
- input_argument->file().options(),
- false,
- input_group != NULL,
- input_file->is_in_sysroot(),
- NULL,
- layout->script_options(),
- &lex,
- input_file->will_search_for(),
- script_info);
- bool old_saw_sections_clause =
- layout->script_options()->saw_sections_clause();
- if (yyparse(&closure) != 0)
- {
- if (closure.found_incompatible_target())
- {
- Read_symbols::incompatible_warning(input_argument, input_file);
- Read_symbols::requeue(workqueue, input_objects, symtab, layout,
- dirsearch, dirindex, mapfile, input_argument,
- input_group, next_blocker);
- return true;
- }
- return false;
- }
- if (!old_saw_sections_clause
- && layout->script_options()->saw_sections_clause()
- && layout->have_added_input_section())
- gold_error(_("%s: SECTIONS seen after other input files; try -T/--script"),
- input_file->filename().c_str());
- if (!closure.saw_inputs())
- return true;
- Task_token* this_blocker = NULL;
- for (Input_arguments::const_iterator p = closure.inputs()->begin();
- p != closure.inputs()->end();
- ++p)
- {
- Task_token* nb;
- if (p + 1 == closure.inputs()->end())
- nb = next_blocker;
- else
- {
- nb = new Task_token(true);
- nb->add_blocker();
- }
- workqueue->queue_soon(new Read_symbols(input_objects, symtab,
- layout, dirsearch, 0, mapfile, &*p,
- input_group, NULL, this_blocker, nb));
- this_blocker = nb;
- }
- *used_next_blocker = true;
- return true;
- }
- // Helper function for read_version_script(), read_commandline_script() and
- // script_include_directive(). Processes the given file in the mode indicated
- // by first_token and lex_mode.
- static bool
- read_script_file(const char* filename, Command_line* cmdline,
- Script_options* script_options,
- int first_token, Lex::Mode lex_mode)
- {
- Dirsearch dirsearch;
- std::string name = filename;
- // If filename is a relative filename, search for it manually using "." +
- // cmdline->options()->library_path() -- not dirsearch.
- if (!IS_ABSOLUTE_PATH(filename))
- {
- const General_options::Dir_list& search_path =
- cmdline->options().library_path();
- name = Dirsearch::find_file_in_dir_list(name, search_path, ".");
- }
- // The file locking code wants to record a Task, but we haven't
- // started the workqueue yet. This is only for debugging purposes,
- // so we invent a fake value.
- const Task* task = reinterpret_cast<const Task*>(-1);
- // We don't want this file to be opened in binary mode.
- Position_dependent_options posdep = cmdline->position_dependent_options();
- if (posdep.format_enum() == General_options::OBJECT_FORMAT_BINARY)
- posdep.set_format_enum(General_options::OBJECT_FORMAT_ELF);
- Input_file_argument input_argument(name.c_str(),
- Input_file_argument::INPUT_FILE_TYPE_FILE,
- "", false, posdep);
- Input_file input_file(&input_argument);
- int dummy = 0;
- if (!input_file.open(dirsearch, task, &dummy))
- return false;
- std::string input_string;
- Lex::read_file(&input_file, &input_string);
- Lex lex(input_string.c_str(), input_string.length(), first_token);
- lex.set_mode(lex_mode);
- Parser_closure closure(filename,
- cmdline->position_dependent_options(),
- first_token == Lex::DYNAMIC_LIST,
- false,
- input_file.is_in_sysroot(),
- cmdline,
- script_options,
- &lex,
- false,
- NULL);
- if (yyparse(&closure) != 0)
- {
- input_file.file().unlock(task);
- return false;
- }
- input_file.file().unlock(task);
- gold_assert(!closure.saw_inputs());
- return true;
- }
- // FILENAME was found as an argument to --script (-T).
- // Read it as a script, and execute its contents immediately.
- bool
- read_commandline_script(const char* filename, Command_line* cmdline)
- {
- return read_script_file(filename, cmdline, &cmdline->script_options(),
- PARSING_LINKER_SCRIPT, Lex::LINKER_SCRIPT);
- }
- // FILENAME was found as an argument to --version-script. Read it as
- // a version script, and store its contents in
- // cmdline->script_options()->version_script_info().
- bool
- read_version_script(const char* filename, Command_line* cmdline)
- {
- return read_script_file(filename, cmdline, &cmdline->script_options(),
- PARSING_VERSION_SCRIPT, Lex::VERSION_SCRIPT);
- }
- // FILENAME was found as an argument to --dynamic-list. Read it as a
- // list of symbols, and store its contents in DYNAMIC_LIST.
- bool
- read_dynamic_list(const char* filename, Command_line* cmdline,
- Script_options* dynamic_list)
- {
- return read_script_file(filename, cmdline, dynamic_list,
- PARSING_DYNAMIC_LIST, Lex::DYNAMIC_LIST);
- }
- // Implement the --defsym option on the command line. Return true if
- // all is well.
- bool
- Script_options::define_symbol(const char* definition)
- {
- Lex lex(definition, strlen(definition), PARSING_DEFSYM);
- lex.set_mode(Lex::EXPRESSION);
- // Dummy value.
- Position_dependent_options posdep_options;
- Parser_closure closure("command line", posdep_options, true,
- false, false, NULL, this, &lex, false, NULL);
- if (yyparse(&closure) != 0)
- return false;
- gold_assert(!closure.saw_inputs());
- return true;
- }
- // Print the script to F for debugging.
- void
- Script_options::print(FILE* f) const
- {
- fprintf(f, "%s: Dumping linker script\n", program_name);
- if (!this->entry_.empty())
- fprintf(f, "ENTRY(%s)\n", this->entry_.c_str());
- for (Symbol_assignments::const_iterator p =
- this->symbol_assignments_.begin();
- p != this->symbol_assignments_.end();
- ++p)
- (*p)->print(f);
- for (Assertions::const_iterator p = this->assertions_.begin();
- p != this->assertions_.end();
- ++p)
- (*p)->print(f);
- this->script_sections_.print(f);
- this->version_script_info_.print(f);
- }
- // Manage mapping from keywords to the codes expected by the bison
- // parser. We construct one global object for each lex mode with
- // keywords.
- class Keyword_to_parsecode
- {
- public:
- // The structure which maps keywords to parsecodes.
- struct Keyword_parsecode
- {
- // Keyword.
- const char* keyword;
- // Corresponding parsecode.
- int parsecode;
- };
- Keyword_to_parsecode(const Keyword_parsecode* keywords,
- int keyword_count)
- : keyword_parsecodes_(keywords), keyword_count_(keyword_count)
- { }
- // Return the parsecode corresponding KEYWORD, or 0 if it is not a
- // keyword.
- int
- keyword_to_parsecode(const char* keyword, size_t len) const;
- private:
- const Keyword_parsecode* keyword_parsecodes_;
- const int keyword_count_;
- };
- // Mapping from keyword string to keyword parsecode. This array must
- // be kept in sorted order. Parsecodes are looked up using bsearch.
- // This array must correspond to the list of parsecodes in yyscript.y.
- static const Keyword_to_parsecode::Keyword_parsecode
- script_keyword_parsecodes[] =
- {
- { "ABSOLUTE", ABSOLUTE },
- { "ADDR", ADDR },
- { "ALIGN", ALIGN_K },
- { "ALIGNOF", ALIGNOF },
- { "ASSERT", ASSERT_K },
- { "AS_NEEDED", AS_NEEDED },
- { "AT", AT },
- { "BIND", BIND },
- { "BLOCK", BLOCK },
- { "BYTE", BYTE },
- { "CONSTANT", CONSTANT },
- { "CONSTRUCTORS", CONSTRUCTORS },
- { "COPY", COPY },
- { "CREATE_OBJECT_SYMBOLS", CREATE_OBJECT_SYMBOLS },
- { "DATA_SEGMENT_ALIGN", DATA_SEGMENT_ALIGN },
- { "DATA_SEGMENT_END", DATA_SEGMENT_END },
- { "DATA_SEGMENT_RELRO_END", DATA_SEGMENT_RELRO_END },
- { "DEFINED", DEFINED },
- { "DSECT", DSECT },
- { "ENTRY", ENTRY },
- { "EXCLUDE_FILE", EXCLUDE_FILE },
- { "EXTERN", EXTERN },
- { "FILL", FILL },
- { "FLOAT", FLOAT },
- { "FORCE_COMMON_ALLOCATION", FORCE_COMMON_ALLOCATION },
- { "GROUP", GROUP },
- { "HLL", HLL },
- { "INCLUDE", INCLUDE },
- { "INFO", INFO },
- { "INHIBIT_COMMON_ALLOCATION", INHIBIT_COMMON_ALLOCATION },
- { "INPUT", INPUT },
- { "KEEP", KEEP },
- { "LENGTH", LENGTH },
- { "LOADADDR", LOADADDR },
- { "LONG", LONG },
- { "MAP", MAP },
- { "MAX", MAX_K },
- { "MEMORY", MEMORY },
- { "MIN", MIN_K },
- { "NEXT", NEXT },
- { "NOCROSSREFS", NOCROSSREFS },
- { "NOFLOAT", NOFLOAT },
- { "NOLOAD", NOLOAD },
- { "ONLY_IF_RO", ONLY_IF_RO },
- { "ONLY_IF_RW", ONLY_IF_RW },
- { "OPTION", OPTION },
- { "ORIGIN", ORIGIN },
- { "OUTPUT", OUTPUT },
- { "OUTPUT_ARCH", OUTPUT_ARCH },
- { "OUTPUT_FORMAT", OUTPUT_FORMAT },
- { "OVERLAY", OVERLAY },
- { "PHDRS", PHDRS },
- { "PROVIDE", PROVIDE },
- { "PROVIDE_HIDDEN", PROVIDE_HIDDEN },
- { "QUAD", QUAD },
- { "SEARCH_DIR", SEARCH_DIR },
- { "SECTIONS", SECTIONS },
- { "SEGMENT_START", SEGMENT_START },
- { "SHORT", SHORT },
- { "SIZEOF", SIZEOF },
- { "SIZEOF_HEADERS", SIZEOF_HEADERS },
- { "SORT", SORT_BY_NAME },
- { "SORT_BY_ALIGNMENT", SORT_BY_ALIGNMENT },
- { "SORT_BY_NAME", SORT_BY_NAME },
- { "SPECIAL", SPECIAL },
- { "SQUAD", SQUAD },
- { "STARTUP", STARTUP },
- { "SUBALIGN", SUBALIGN },
- { "SYSLIB", SYSLIB },
- { "TARGET", TARGET_K },
- { "TRUNCATE", TRUNCATE },
- { "VERSION", VERSIONK },
- { "global", GLOBAL },
- { "l", LENGTH },
- { "len", LENGTH },
- { "local", LOCAL },
- { "o", ORIGIN },
- { "org", ORIGIN },
- { "sizeof_headers", SIZEOF_HEADERS },
- };
- static const Keyword_to_parsecode
- script_keywords(&script_keyword_parsecodes[0],
- (sizeof(script_keyword_parsecodes)
- / sizeof(script_keyword_parsecodes[0])));
- static const Keyword_to_parsecode::Keyword_parsecode
- version_script_keyword_parsecodes[] =
- {
- { "extern", EXTERN },
- { "global", GLOBAL },
- { "local", LOCAL },
- };
- static const Keyword_to_parsecode
- version_script_keywords(&version_script_keyword_parsecodes[0],
- (sizeof(version_script_keyword_parsecodes)
- / sizeof(version_script_keyword_parsecodes[0])));
- static const Keyword_to_parsecode::Keyword_parsecode
- dynamic_list_keyword_parsecodes[] =
- {
- { "extern", EXTERN },
- };
- static const Keyword_to_parsecode
- dynamic_list_keywords(&dynamic_list_keyword_parsecodes[0],
- (sizeof(dynamic_list_keyword_parsecodes)
- / sizeof(dynamic_list_keyword_parsecodes[0])));
- // Comparison function passed to bsearch.
- extern "C"
- {
- struct Ktt_key
- {
- const char* str;
- size_t len;
- };
- static int
- ktt_compare(const void* keyv, const void* kttv)
- {
- const Ktt_key* key = static_cast<const Ktt_key*>(keyv);
- const Keyword_to_parsecode::Keyword_parsecode* ktt =
- static_cast<const Keyword_to_parsecode::Keyword_parsecode*>(kttv);
- int i = strncmp(key->str, ktt->keyword, key->len);
- if (i != 0)
- return i;
- if (ktt->keyword[key->len] != '\0')
- return -1;
- return 0;
- }
- } // End extern "C".
- int
- Keyword_to_parsecode::keyword_to_parsecode(const char* keyword,
- size_t len) const
- {
- Ktt_key key;
- key.str = keyword;
- key.len = len;
- void* kttv = bsearch(&key,
- this->keyword_parsecodes_,
- this->keyword_count_,
- sizeof(this->keyword_parsecodes_[0]),
- ktt_compare);
- if (kttv == NULL)
- return 0;
- Keyword_parsecode* ktt = static_cast<Keyword_parsecode*>(kttv);
- return ktt->parsecode;
- }
- // The following structs are used within the VersionInfo class as well
- // as in the bison helper functions. They store the information
- // parsed from the version script.
- // A single version expression.
- // For example, pattern="std::map*" and language="C++".
- struct Version_expression
- {
- Version_expression(const std::string& a_pattern,
- Version_script_info::Language a_language,
- bool a_exact_match)
- : pattern(a_pattern), language(a_language), exact_match(a_exact_match),
- was_matched_by_symbol(false)
- { }
- std::string pattern;
- Version_script_info::Language language;
- // If false, we use glob() to match pattern. If true, we use strcmp().
- bool exact_match;
- // True if --no-undefined-version is in effect and we found this
- // version in get_symbol_version. We use mutable because this
- // struct is generally not modifiable after it has been created.
- mutable bool was_matched_by_symbol;
- };
- // A list of expressions.
- struct Version_expression_list
- {
- std::vector<struct Version_expression> expressions;
- };
- // A list of which versions upon which another version depends.
- // Strings should be from the Stringpool.
- struct Version_dependency_list
- {
- std::vector<std::string> dependencies;
- };
- // The total definition of a version. It includes the tag for the
- // version, its global and local expressions, and any dependencies.
- struct Version_tree
- {
- Version_tree()
- : tag(), global(NULL), local(NULL), dependencies(NULL)
- { }
- std::string tag;
- const struct Version_expression_list* global;
- const struct Version_expression_list* local;
- const struct Version_dependency_list* dependencies;
- };
- // Helper class that calls cplus_demangle when needed and takes care of freeing
- // the result.
- class Lazy_demangler
- {
- public:
- Lazy_demangler(const char* symbol, int options)
- : symbol_(symbol), options_(options), demangled_(NULL), did_demangle_(false)
- { }
- ~Lazy_demangler()
- { free(this->demangled_); }
- // Return the demangled name. The actual demangling happens on the first call,
- // and the result is later cached.
- inline char*
- get();
- private:
- // The symbol to demangle.
- const char* symbol_;
- // Option flags to pass to cplus_demagle.
- const int options_;
- // The cached demangled value, or NULL if demangling didn't happen yet or
- // failed.
- char* demangled_;
- // Whether we already called cplus_demangle
- bool did_demangle_;
- };
- // Return the demangled name. The actual demangling happens on the first call,
- // and the result is later cached. Returns NULL if the symbol cannot be
- // demangled.
- inline char*
- Lazy_demangler::get()
- {
- if (!this->did_demangle_)
- {
- this->demangled_ = cplus_demangle(this->symbol_, this->options_);
- this->did_demangle_ = true;
- }
- return this->demangled_;
- }
- // Class Version_script_info.
- Version_script_info::Version_script_info()
- : dependency_lists_(), expression_lists_(), version_trees_(), globs_(),
- default_version_(NULL), default_is_global_(false), is_finalized_(false)
- {
- for (int i = 0; i < LANGUAGE_COUNT; ++i)
- this->exact_[i] = NULL;
- }
- Version_script_info::~Version_script_info()
- {
- }
- // Forget all the known version script information.
- void
- Version_script_info::clear()
- {
- for (size_t k = 0; k < this->dependency_lists_.size(); ++k)
- delete this->dependency_lists_[k];
- this->dependency_lists_.clear();
- for (size_t k = 0; k < this->version_trees_.size(); ++k)
- delete this->version_trees_[k];
- this->version_trees_.clear();
- for (size_t k = 0; k < this->expression_lists_.size(); ++k)
- delete this->expression_lists_[k];
- this->expression_lists_.clear();
- }
- // Finalize the version script information.
- void
- Version_script_info::finalize()
- {
- if (!this->is_finalized_)
- {
- this->build_lookup_tables();
- this->is_finalized_ = true;
- }
- }
- // Return all the versions.
- std::vector<std::string>
- Version_script_info::get_versions() const
- {
- std::vector<std::string> ret;
- for (size_t j = 0; j < this->version_trees_.size(); ++j)
- if (!this->version_trees_[j]->tag.empty())
- ret.push_back(this->version_trees_[j]->tag);
- return ret;
- }
- // Return the dependencies of VERSION.
- std::vector<std::string>
- Version_script_info::get_dependencies(const char* version) const
- {
- std::vector<std::string> ret;
- for (size_t j = 0; j < this->version_trees_.size(); ++j)
- if (this->version_trees_[j]->tag == version)
- {
- const struct Version_dependency_list* deps =
- this->version_trees_[j]->dependencies;
- if (deps != NULL)
- for (size_t k = 0; k < deps->dependencies.size(); ++k)
- ret.push_back(deps->dependencies[k]);
- return ret;
- }
- return ret;
- }
- // A version script essentially maps a symbol name to a version tag
- // and an indication of whether symbol is global or local within that
- // version tag. Each symbol maps to at most one version tag.
- // Unfortunately, in practice, version scripts are ambiguous, and list
- // symbols multiple times. Thus, we have to document the matching
- // process.
- // This is a description of what the GNU linker does as of 2010-01-11.
- // It walks through the version tags in the order in which they appear
- // in the version script. For each tag, it first walks through the
- // global patterns for that tag, then the local patterns. When
- // looking at a single pattern, it first applies any language specific
- // demangling as specified for the pattern, and then matches the
- // resulting symbol name to the pattern. If it finds an exact match
- // for a literal pattern (a pattern enclosed in quotes or with no
- // wildcard characters), then that is the match that it uses. If
- // finds a match with a wildcard pattern, then it saves it and
- // continues searching. Wildcard patterns that are exactly "*" are
- // saved separately.
- // If no exact match with a literal pattern is ever found, then if a
- // wildcard match with a global pattern was found it is used,
- // otherwise if a wildcard match with a local pattern was found it is
- // used.
- // This is the result:
- // * If there is an exact match, then we use the first tag in the
- // version script where it matches.
- // + If the exact match in that tag is global, it is used.
- // + Otherwise the exact match in that tag is local, and is used.
- // * Otherwise, if there is any match with a global wildcard pattern:
- // + If there is any match with a wildcard pattern which is not
- // "*", then we use the tag in which the *last* such pattern
- // appears.
- // + Otherwise, we matched "*". If there is no match with a local
- // wildcard pattern which is not "*", then we use the *last*
- // match with a global "*". Otherwise, continue.
- // * Otherwise, if there is any match with a local wildcard pattern:
- // + If there is any match with a wildcard pattern which is not
- // "*", then we use the tag in which the *last* such pattern
- // appears.
- // + Otherwise, we matched "*", and we use the tag in which the
- // *last* such match occurred.
- // There is an additional wrinkle. When the GNU linker finds a symbol
- // with a version defined in an object file due to a .symver
- // directive, it looks up that symbol name in that version tag. If it
- // finds it, it matches the symbol name against the patterns for that
- // version. If there is no match with a global pattern, but there is
- // a match with a local pattern, then the GNU linker marks the symbol
- // as local.
- // We want gold to be generally compatible, but we also want gold to
- // be fast. These are the rules that gold implements:
- // * If there is an exact match for the mangled name, we use it.
- // + If there is more than one exact match, we give a warning, and
- // we use the first tag in the script which matches.
- // + If a symbol has an exact match as both global and local for
- // the same version tag, we give an error.
- // * Otherwise, we look for an extern C++ or an extern Java exact
- // match. If we find an exact match, we use it.
- // + If there is more than one exact match, we give a warning, and
- // we use the first tag in the script which matches.
- // + If a symbol has an exact match as both global and local for
- // the same version tag, we give an error.
- // * Otherwise, we look through the wildcard patterns, ignoring "*"
- // patterns. We look through the version tags in reverse order.
- // For each version tag, we look through the global patterns and
- // then the local patterns. We use the first match we find (i.e.,
- // the last matching version tag in the file).
- // * Otherwise, we use the "*" pattern if there is one. We give an
- // error if there are multiple "*" patterns.
- // At least for now, gold does not look up the version tag for a
- // symbol version found in an object file to see if it should be
- // forced local. There are other ways to force a symbol to be local,
- // and I don't understand why this one is useful.
- // Build a set of fast lookup tables for a version script.
- void
- Version_script_info::build_lookup_tables()
- {
- size_t size = this->version_trees_.size();
- for (size_t j = 0; j < size; ++j)
- {
- const Version_tree* v = this->version_trees_[j];
- this->build_expression_list_lookup(v->local, v, false);
- this->build_expression_list_lookup(v->global, v, true);
- }
- }
- // If a pattern has backlashes but no unquoted wildcard characters,
- // then we apply backslash unquoting and look for an exact match.
- // Otherwise we treat it as a wildcard pattern. This function returns
- // true for a wildcard pattern. Otherwise, it does backslash
- // unquoting on *PATTERN and returns false. If this returns true,
- // *PATTERN may have been partially unquoted.
- bool
- Version_script_info::unquote(std::string* pattern) const
- {
- bool saw_backslash = false;
- size_t len = pattern->length();
- size_t j = 0;
- for (size_t i = 0; i < len; ++i)
- {
- if (saw_backslash)
- saw_backslash = false;
- else
- {
- switch ((*pattern)[i])
- {
- case '?': case '[': case '*':
- return true;
- case '\\':
- saw_backslash = true;
- continue;
- default:
- break;
- }
- }
- if (i != j)
- (*pattern)[j] = (*pattern)[i];
- ++j;
- }
- return false;
- }
- // Add an exact match for MATCH to *PE. The result of the match is
- // V/IS_GLOBAL.
- void
- Version_script_info::add_exact_match(const std::string& match,
- const Version_tree* v, bool is_global,
- const Version_expression* ve,
- Exact* pe)
- {
- std::pair<Exact::iterator, bool> ins =
- pe->insert(std::make_pair(match, Version_tree_match(v, is_global, ve)));
- if (ins.second)
- {
- // This is the first time we have seen this match.
- return;
- }
- Version_tree_match& vtm(ins.first->second);
- if (vtm.real->tag != v->tag)
- {
- // This is an ambiguous match. We still return the
- // first version that we found in the script, but we
- // record the new version to issue a warning if we
- // wind up looking up this symbol.
- if (vtm.ambiguous == NULL)
- vtm.ambiguous = v;
- }
- else if (is_global != vtm.is_global)
- {
- // We have a match for both the global and local entries for a
- // version tag. That's got to be wrong.
- gold_error(_("'%s' appears as both a global and a local symbol "
- "for version '%s' in script"),
- match.c_str(), v->tag.c_str());
- }
- }
- // Build fast lookup information for EXPLIST and store it in LOOKUP.
- // All matches go to V, and IS_GLOBAL is true if they are global
- // matches.
- void
- Version_script_info::build_expression_list_lookup(
- const Version_expression_list* explist,
- const Version_tree* v,
- bool is_global)
- {
- if (explist == NULL)
- return;
- size_t size = explist->expressions.size();
- for (size_t i = 0; i < size; ++i)
- {
- const Version_expression& exp(explist->expressions[i]);
- if (exp.pattern.length() == 1 && exp.pattern[0] == '*')
- {
- if (this->default_version_ != NULL
- && this->default_version_->tag != v->tag)
- gold_warning(_("wildcard match appears in both version '%s' "
- "and '%s' in script"),
- this->default_version_->tag.c_str(), v->tag.c_str());
- else if (this->default_version_ != NULL
- && this->default_is_global_ != is_global)
- gold_error(_("wildcard match appears as both global and local "
- "in version '%s' in script"),
- v->tag.c_str());
- this->default_version_ = v;
- this->default_is_global_ = is_global;
- continue;
- }
- std::string pattern = exp.pattern;
- if (!exp.exact_match)
- {
- if (this->unquote(&pattern))
- {
- this->globs_.push_back(Glob(&exp, v, is_global));
- continue;
- }
- }
- if (this->exact_[exp.language] == NULL)
- this->exact_[exp.language] = new Exact();
- this->add_exact_match(pattern, v, is_global, &exp,
- this->exact_[exp.language]);
- }
- }
- // Return the name to match given a name, a language code, and two
- // lazy demanglers.
- const char*
- Version_script_info::get_name_to_match(const char* name,
- int language,
- Lazy_demangler* cpp_demangler,
- Lazy_demangler* java_demangler) const
- {
- switch (language)
- {
- case LANGUAGE_C:
- return name;
- case LANGUAGE_CXX:
- return cpp_demangler->get();
- case LANGUAGE_JAVA:
- return java_demangler->get();
- default:
- gold_unreachable();
- }
- }
- // Look up SYMBOL_NAME in the list of versions. Return true if the
- // symbol is found, false if not. If the symbol is found, then if
- // PVERSION is not NULL, set *PVERSION to the version tag, and if
- // P_IS_GLOBAL is not NULL, set *P_IS_GLOBAL according to whether the
- // symbol is global or not.
- bool
- Version_script_info::get_symbol_version(const char* symbol_name,
- std::string* pversion,
- bool* p_is_global) const
- {
- Lazy_demangler cpp_demangled_name(symbol_name, DMGL_ANSI | DMGL_PARAMS);
- Lazy_demangler java_demangled_name(symbol_name,
- DMGL_ANSI | DMGL_PARAMS | DMGL_JAVA);
- gold_assert(this->is_finalized_);
- for (int i = 0; i < LANGUAGE_COUNT; ++i)
- {
- Exact* exact = this->exact_[i];
- if (exact == NULL)
- continue;
- const char* name_to_match = this->get_name_to_match(symbol_name, i,
- &cpp_demangled_name,
- &java_demangled_name);
- if (name_to_match == NULL)
- {
- // If the name can not be demangled, the GNU linker goes
- // ahead and tries to match it anyhow. That does not
- // make sense to me and I have not implemented it.
- continue;
- }
- Exact::const_iterator pe = exact->find(name_to_match);
- if (pe != exact->end())
- {
- const Version_tree_match& vtm(pe->second);
- if (vtm.ambiguous != NULL)
- gold_warning(_("using '%s' as version for '%s' which is also "
- "named in version '%s' in script"),
- vtm.real->tag.c_str(), name_to_match,
- vtm.ambiguous->tag.c_str());
- if (pversion != NULL)
- *pversion = vtm.real->tag;
- if (p_is_global != NULL)
- *p_is_global = vtm.is_global;
- // If we are using --no-undefined-version, and this is a
- // global symbol, we have to record that we have found this
- // symbol, so that we don't warn about it. We have to do
- // this now, because otherwise we have no way to get from a
- // non-C language back to the demangled name that we
- // matched.
- if (p_is_global != NULL && vtm.is_global)
- vtm.expression->was_matched_by_symbol = true;
- return true;
- }
- }
- // Look through the glob patterns in reverse order.
- for (Globs::const_reverse_iterator p = this->globs_.rbegin();
- p != this->globs_.rend();
- ++p)
- {
- int language = p->expression->language;
- const char* name_to_match = this->get_name_to_match(symbol_name,
- language,
- &cpp_demangled_name,
- &java_demangled_name);
- if (name_to_match == NULL)
- continue;
- if (fnmatch(p->expression->pattern.c_str(), name_to_match,
- FNM_NOESCAPE) == 0)
- {
- if (pversion != NULL)
- *pversion = p->version->tag;
- if (p_is_global != NULL)
- *p_is_global = p->is_global;
- return true;
- }
- }
- // Finally, there may be a wildcard.
- if (this->default_version_ != NULL)
- {
- if (pversion != NULL)
- *pversion = this->default_version_->tag;
- if (p_is_global != NULL)
- *p_is_global = this->default_is_global_;
- return true;
- }
- return false;
- }
- // Give an error if any exact symbol names (not wildcards) appear in a
- // version script, but there is no such symbol.
- void
- Version_script_info::check_unmatched_names(const Symbol_table* symtab) const
- {
- for (size_t i = 0; i < this->version_trees_.size(); ++i)
- {
- const Version_tree* vt = this->version_trees_[i];
- if (vt->global == NULL)
- continue;
- for (size_t j = 0; j < vt->global->expressions.size(); ++j)
- {
- const Version_expression& expression(vt->global->expressions[j]);
- // Ignore cases where we used the version because we saw a
- // symbol that we looked up. Note that
- // WAS_MATCHED_BY_SYMBOL will be true even if the symbol was
- // not a definition. That's OK as in that case we most
- // likely gave an undefined symbol error anyhow.
- if (expression.was_matched_by_symbol)
- continue;
- // Just ignore names which are in languages other than C.
- // We have no way to look them up in the symbol table.
- if (expression.language != LANGUAGE_C)
- continue;
- // Remove backslash quoting, and ignore wildcard patterns.
- std::string pattern = expression.pattern;
- if (!expression.exact_match)
- {
- if (this->unquote(&pattern))
- continue;
- }
- if (symtab->lookup(pattern.c_str(), vt->tag.c_str()) == NULL)
- gold_error(_("version script assignment of %s to symbol %s "
- "failed: symbol not defined"),
- vt->tag.c_str(), pattern.c_str());
- }
- }
- }
- struct Version_dependency_list*
- Version_script_info::allocate_dependency_list()
- {
- dependency_lists_.push_back(new Version_dependency_list);
- return dependency_lists_.back();
- }
- struct Version_expression_list*
- Version_script_info::allocate_expression_list()
- {
- expression_lists_.push_back(new Version_expression_list);
- return expression_lists_.back();
- }
- struct Version_tree*
- Version_script_info::allocate_version_tree()
- {
- version_trees_.push_back(new Version_tree);
- return version_trees_.back();
- }
- // Print for debugging.
- void
- Version_script_info::print(FILE* f) const
- {
- if (this->empty())
- return;
- fprintf(f, "VERSION {");
- for (size_t i = 0; i < this->version_trees_.size(); ++i)
- {
- const Version_tree* vt = this->version_trees_[i];
- if (vt->tag.empty())
- fprintf(f, " {\n");
- else
- fprintf(f, " %s {\n", vt->tag.c_str());
- if (vt->global != NULL)
- {
- fprintf(f, " global :\n");
- this->print_expression_list(f, vt->global);
- }
- if (vt->local != NULL)
- {
- fprintf(f, " local :\n");
- this->print_expression_list(f, vt->local);
- }
- fprintf(f, " }");
- if (vt->dependencies != NULL)
- {
- const Version_dependency_list* deps = vt->dependencies;
- for (size_t j = 0; j < deps->dependencies.size(); ++j)
- {
- if (j < deps->dependencies.size() - 1)
- fprintf(f, "\n");
- fprintf(f, " %s", deps->dependencies[j].c_str());
- }
- }
- fprintf(f, ";\n");
- }
- fprintf(f, "}\n");
- }
- void
- Version_script_info::print_expression_list(
- FILE* f,
- const Version_expression_list* vel) const
- {
- Version_script_info::Language current_language = LANGUAGE_C;
- for (size_t i = 0; i < vel->expressions.size(); ++i)
- {
- const Version_expression& ve(vel->expressions[i]);
- if (ve.language != current_language)
- {
- if (current_language != LANGUAGE_C)
- fprintf(f, " }\n");
- switch (ve.language)
- {
- case LANGUAGE_C:
- break;
- case LANGUAGE_CXX:
- fprintf(f, " extern \"C++\" {\n");
- break;
- case LANGUAGE_JAVA:
- fprintf(f, " extern \"Java\" {\n");
- break;
- default:
- gold_unreachable();
- }
- current_language = ve.language;
- }
- fprintf(f, " ");
- if (current_language != LANGUAGE_C)
- fprintf(f, " ");
- if (ve.exact_match)
- fprintf(f, "\"");
- fprintf(f, "%s", ve.pattern.c_str());
- if (ve.exact_match)
- fprintf(f, "\"");
- fprintf(f, "\n");
- }
- if (current_language != LANGUAGE_C)
- fprintf(f, " }\n");
- }
- } // End namespace gold.
- // The remaining functions are extern "C", so it's clearer to not put
- // them in namespace gold.
- using namespace gold;
- // This function is called by the bison parser to return the next
- // token.
- extern "C" int
- yylex(YYSTYPE* lvalp, void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- const Token* token = closure->next_token();
- switch (token->classification())
- {
- default:
- gold_unreachable();
- case Token::TOKEN_INVALID:
- yyerror(closurev, "invalid character");
- return 0;
- case Token::TOKEN_EOF:
- return 0;
- case Token::TOKEN_STRING:
- {
- // This is either a keyword or a STRING.
- size_t len;
- const char* str = token->string_value(&len);
- int parsecode = 0;
- switch (closure->lex_mode())
- {
- case Lex::LINKER_SCRIPT:
- parsecode = script_keywords.keyword_to_parsecode(str, len);
- break;
- case Lex::VERSION_SCRIPT:
- parsecode = version_script_keywords.keyword_to_parsecode(str, len);
- break;
- case Lex::DYNAMIC_LIST:
- parsecode = dynamic_list_keywords.keyword_to_parsecode(str, len);
- break;
- default:
- break;
- }
- if (parsecode != 0)
- return parsecode;
- lvalp->string.value = str;
- lvalp->string.length = len;
- return STRING;
- }
- case Token::TOKEN_QUOTED_STRING:
- lvalp->string.value = token->string_value(&lvalp->string.length);
- return QUOTED_STRING;
- case Token::TOKEN_OPERATOR:
- return token->operator_value();
- case Token::TOKEN_INTEGER:
- lvalp->integer = token->integer_value();
- return INTEGER;
- }
- }
- // This function is called by the bison parser to report an error.
- extern "C" void
- yyerror(void* closurev, const char* message)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- gold_error(_("%s:%d:%d: %s"), closure->filename(), closure->lineno(),
- closure->charpos(), message);
- }
- // Called by the bison parser to add an external symbol to the link.
- extern "C" void
- script_add_extern(void* closurev, const char* name, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->add_symbol_reference(name, length);
- }
- // Called by the bison parser to add a file to the link.
- extern "C" void
- script_add_file(void* closurev, const char* name, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- // If this is an absolute path, and we found the script in the
- // sysroot, then we want to prepend the sysroot to the file name.
- // For example, this is how we handle a cross link to the x86_64
- // libc.so, which refers to /lib/libc.so.6.
- std::string name_string(name, length);
- const char* extra_search_path = ".";
- std::string script_directory;
- if (IS_ABSOLUTE_PATH(name_string.c_str()))
- {
- if (closure->is_in_sysroot())
- {
- const std::string& sysroot(parameters->options().sysroot());
- gold_assert(!sysroot.empty());
- name_string = sysroot + name_string;
- }
- }
- else
- {
- // In addition to checking the normal library search path, we
- // also want to check in the script-directory.
- const char* slash = strrchr(closure->filename(), '/');
- if (slash != NULL)
- {
- script_directory.assign(closure->filename(),
- slash - closure->filename() + 1);
- extra_search_path = script_directory.c_str();
- }
- }
- Input_file_argument file(name_string.c_str(),
- Input_file_argument::INPUT_FILE_TYPE_FILE,
- extra_search_path, false,
- closure->position_dependent_options());
- Input_argument& arg = closure->inputs()->add_file(file);
- arg.set_script_info(closure->script_info());
- }
- // Called by the bison parser to add a library to the link.
- extern "C" void
- script_add_library(void* closurev, const char* name, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- std::string name_string(name, length);
- if (name_string[0] != 'l')
- gold_error(_("library name must be prefixed with -l"));
-
- Input_file_argument file(name_string.c_str() + 1,
- Input_file_argument::INPUT_FILE_TYPE_LIBRARY,
- "", false,
- closure->position_dependent_options());
- Input_argument& arg = closure->inputs()->add_file(file);
- arg.set_script_info(closure->script_info());
- }
- // Called by the bison parser to start a group. If we are already in
- // a group, that means that this script was invoked within a
- // --start-group --end-group sequence on the command line, or that
- // this script was found in a GROUP of another script. In that case,
- // we simply continue the existing group, rather than starting a new
- // one. It is possible to construct a case in which this will do
- // something other than what would happen if we did a recursive group,
- // but it's hard to imagine why the different behaviour would be
- // useful for a real program. Avoiding recursive groups is simpler
- // and more efficient.
- extern "C" void
- script_start_group(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (!closure->in_group())
- closure->inputs()->start_group();
- }
- // Called by the bison parser at the end of a group.
- extern "C" void
- script_end_group(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (!closure->in_group())
- closure->inputs()->end_group();
- }
- // Called by the bison parser to start an AS_NEEDED list.
- extern "C" void
- script_start_as_needed(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->position_dependent_options().set_as_needed(true);
- }
- // Called by the bison parser at the end of an AS_NEEDED list.
- extern "C" void
- script_end_as_needed(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->position_dependent_options().set_as_needed(false);
- }
- // Called by the bison parser to set the entry symbol.
- extern "C" void
- script_set_entry(void* closurev, const char* entry, size_t length)
- {
- // We'll parse this exactly the same as --entry=ENTRY on the commandline
- // TODO(csilvers): FIXME -- call set_entry directly.
- std::string arg("--entry=");
- arg.append(entry, length);
- script_parse_option(closurev, arg.c_str(), arg.size());
- }
- // Called by the bison parser to set whether to define common symbols.
- extern "C" void
- script_set_common_allocation(void* closurev, int set)
- {
- const char* arg = set != 0 ? "--define-common" : "--no-define-common";
- script_parse_option(closurev, arg, strlen(arg));
- }
- // Called by the bison parser to refer to a symbol.
- extern "C" Expression*
- script_symbol(void* closurev, const char* name, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (length != 1 || name[0] != '.')
- closure->script_options()->add_symbol_reference(name, length);
- return script_exp_string(name, length);
- }
- // Called by the bison parser to define a symbol.
- extern "C" void
- script_set_symbol(void* closurev, const char* name, size_t length,
- Expression* value, int providei, int hiddeni)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- const bool provide = providei != 0;
- const bool hidden = hiddeni != 0;
- closure->script_options()->add_symbol_assignment(name, length,
- closure->parsing_defsym(),
- value, provide, hidden);
- closure->clear_skip_on_incompatible_target();
- }
- // Called by the bison parser to add an assertion.
- extern "C" void
- script_add_assertion(void* closurev, Expression* check, const char* message,
- size_t messagelen)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->add_assertion(check, message, messagelen);
- closure->clear_skip_on_incompatible_target();
- }
- // Called by the bison parser to parse an OPTION.
- extern "C" void
- script_parse_option(void* closurev, const char* option, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- // We treat the option as a single command-line option, even if
- // it has internal whitespace.
- if (closure->command_line() == NULL)
- {
- // There are some options that we could handle here--e.g.,
- // -lLIBRARY. Should we bother?
- gold_warning(_("%s:%d:%d: ignoring command OPTION; OPTION is only valid"
- " for scripts specified via -T/--script"),
- closure->filename(), closure->lineno(), closure->charpos());
- }
- else
- {
- bool past_a_double_dash_option = false;
- const char* mutable_option = strndup(option, length);
- gold_assert(mutable_option != NULL);
- closure->command_line()->process_one_option(1, &mutable_option, 0,
- &past_a_double_dash_option);
- // The General_options class will quite possibly store a pointer
- // into mutable_option, so we can't free it. In cases the class
- // does not store such a pointer, this is a memory leak. Alas. :(
- }
- closure->clear_skip_on_incompatible_target();
- }
- // Called by the bison parser to handle OUTPUT_FORMAT. OUTPUT_FORMAT
- // takes either one or three arguments. In the three argument case,
- // the format depends on the endianness option, which we don't
- // currently support (FIXME). If we see an OUTPUT_FORMAT for the
- // wrong format, then we want to search for a new file. Returning 0
- // here will cause the parser to immediately abort.
- extern "C" int
- script_check_output_format(void* closurev,
- const char* default_name, size_t default_length,
- const char*, size_t, const char*, size_t)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- std::string name(default_name, default_length);
- Target* target = select_target_by_bfd_name(name.c_str());
- if (target == NULL || !parameters->is_compatible_target(target))
- {
- if (closure->skip_on_incompatible_target())
- {
- closure->set_found_incompatible_target();
- return 0;
- }
- // FIXME: Should we warn about the unknown target?
- }
- return 1;
- }
- // Called by the bison parser to handle TARGET.
- extern "C" void
- script_set_target(void* closurev, const char* target, size_t len)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- std::string s(target, len);
- General_options::Object_format format_enum;
- format_enum = General_options::string_to_object_format(s.c_str());
- closure->position_dependent_options().set_format_enum(format_enum);
- }
- // Called by the bison parser to handle SEARCH_DIR. This is handled
- // exactly like a -L option.
- extern "C" void
- script_add_search_dir(void* closurev, const char* option, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (closure->command_line() == NULL)
- gold_warning(_("%s:%d:%d: ignoring SEARCH_DIR; SEARCH_DIR is only valid"
- " for scripts specified via -T/--script"),
- closure->filename(), closure->lineno(), closure->charpos());
- else if (!closure->command_line()->options().nostdlib())
- {
- std::string s = "-L" + std::string(option, length);
- script_parse_option(closurev, s.c_str(), s.size());
- }
- }
- /* Called by the bison parser to push the lexer into expression
- mode. */
- extern "C" void
- script_push_lex_into_expression_mode(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->push_lex_mode(Lex::EXPRESSION);
- }
- /* Called by the bison parser to push the lexer into version
- mode. */
- extern "C" void
- script_push_lex_into_version_mode(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (closure->version_script()->is_finalized())
- gold_error(_("%s:%d:%d: invalid use of VERSION in input file"),
- closure->filename(), closure->lineno(), closure->charpos());
- closure->push_lex_mode(Lex::VERSION_SCRIPT);
- }
- /* Called by the bison parser to pop the lexer mode. */
- extern "C" void
- script_pop_lex_mode(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->pop_lex_mode();
- }
- // Register an entire version node. For example:
- //
- // GLIBC_2.1 {
- // global: foo;
- // } GLIBC_2.0;
- //
- // - tag is "GLIBC_2.1"
- // - tree contains the information "global: foo"
- // - deps contains "GLIBC_2.0"
- extern "C" void
- script_register_vers_node(void*,
- const char* tag,
- int taglen,
- struct Version_tree* tree,
- struct Version_dependency_list* deps)
- {
- gold_assert(tree != NULL);
- tree->dependencies = deps;
- if (tag != NULL)
- tree->tag = std::string(tag, taglen);
- }
- // Add a dependencies to the list of existing dependencies, if any,
- // and return the expanded list.
- extern "C" struct Version_dependency_list*
- script_add_vers_depend(void* closurev,
- struct Version_dependency_list* all_deps,
- const char* depend_to_add, int deplen)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (all_deps == NULL)
- all_deps = closure->version_script()->allocate_dependency_list();
- all_deps->dependencies.push_back(std::string(depend_to_add, deplen));
- return all_deps;
- }
- // Add a pattern expression to an existing list of expressions, if any.
- extern "C" struct Version_expression_list*
- script_new_vers_pattern(void* closurev,
- struct Version_expression_list* expressions,
- const char* pattern, int patlen, int exact_match)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (expressions == NULL)
- expressions = closure->version_script()->allocate_expression_list();
- expressions->expressions.push_back(
- Version_expression(std::string(pattern, patlen),
- closure->get_current_language(),
- static_cast<bool>(exact_match)));
- return expressions;
- }
- // Attaches b to the end of a, and clears b. So a = a + b and b = {}.
- extern "C" struct Version_expression_list*
- script_merge_expressions(struct Version_expression_list* a,
- struct Version_expression_list* b)
- {
- a->expressions.insert(a->expressions.end(),
- b->expressions.begin(), b->expressions.end());
- // We could delete b and remove it from expressions_lists_, but
- // that's a lot of work. This works just as well.
- b->expressions.clear();
- return a;
- }
- // Combine the global and local expressions into a a Version_tree.
- extern "C" struct Version_tree*
- script_new_vers_node(void* closurev,
- struct Version_expression_list* global,
- struct Version_expression_list* local)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- Version_tree* tree = closure->version_script()->allocate_version_tree();
- tree->global = global;
- tree->local = local;
- return tree;
- }
- // Handle a transition in language, such as at the
- // start or end of 'extern "C++"'
- extern "C" void
- version_script_push_lang(void* closurev, const char* lang, int langlen)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- std::string language(lang, langlen);
- Version_script_info::Language code;
- if (language.empty() || language == "C")
- code = Version_script_info::LANGUAGE_C;
- else if (language == "C++")
- code = Version_script_info::LANGUAGE_CXX;
- else if (language == "Java")
- code = Version_script_info::LANGUAGE_JAVA;
- else
- {
- char* buf = new char[langlen + 100];
- snprintf(buf, langlen + 100,
- _("unrecognized version script language '%s'"),
- language.c_str());
- yyerror(closurev, buf);
- delete[] buf;
- code = Version_script_info::LANGUAGE_C;
- }
- closure->push_language(code);
- }
- extern "C" void
- version_script_pop_lang(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->pop_language();
- }
- // Called by the bison parser to start a SECTIONS clause.
- extern "C" void
- script_start_sections(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->script_sections()->start_sections();
- closure->clear_skip_on_incompatible_target();
- }
- // Called by the bison parser to finish a SECTIONS clause.
- extern "C" void
- script_finish_sections(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->script_sections()->finish_sections();
- }
- // Start processing entries for an output section.
- extern "C" void
- script_start_output_section(void* closurev, const char* name, size_t namelen,
- const struct Parser_output_section_header* header)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->script_sections()->start_output_section(name,
- namelen,
- header);
- }
- // Finish processing entries for an output section.
- extern "C" void
- script_finish_output_section(void* closurev,
- const struct Parser_output_section_trailer* trail)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->script_sections()->finish_output_section(trail);
- }
- // Add a data item (e.g., "WORD (0)") to the current output section.
- extern "C" void
- script_add_data(void* closurev, int data_token, Expression* val)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- int size;
- bool is_signed = true;
- switch (data_token)
- {
- case QUAD:
- size = 8;
- is_signed = false;
- break;
- case SQUAD:
- size = 8;
- break;
- case LONG:
- size = 4;
- break;
- case SHORT:
- size = 2;
- break;
- case BYTE:
- size = 1;
- break;
- default:
- gold_unreachable();
- }
- closure->script_options()->script_sections()->add_data(size, is_signed, val);
- }
- // Add a clause setting the fill value to the current output section.
- extern "C" void
- script_add_fill(void* closurev, Expression* val)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- closure->script_options()->script_sections()->add_fill(val);
- }
- // Add a new input section specification to the current output
- // section.
- extern "C" void
- script_add_input_section(void* closurev,
- const struct Input_section_spec* spec,
- int keepi)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- bool keep = keepi != 0;
- closure->script_options()->script_sections()->add_input_section(spec, keep);
- }
- // When we see DATA_SEGMENT_ALIGN we record that following output
- // sections may be relro.
- extern "C" void
- script_data_segment_align(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (!closure->script_options()->saw_sections_clause())
- gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
- closure->filename(), closure->lineno(), closure->charpos());
- else
- closure->script_options()->script_sections()->data_segment_align();
- }
- // When we see DATA_SEGMENT_RELRO_END we know that all output sections
- // since DATA_SEGMENT_ALIGN should be relro.
- extern "C" void
- script_data_segment_relro_end(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (!closure->script_options()->saw_sections_clause())
- gold_error(_("%s:%d:%d: DATA_SEGMENT_ALIGN not in SECTIONS clause"),
- closure->filename(), closure->lineno(), closure->charpos());
- else
- closure->script_options()->script_sections()->data_segment_relro_end();
- }
- // Create a new list of string/sort pairs.
- extern "C" String_sort_list_ptr
- script_new_string_sort_list(const struct Wildcard_section* string_sort)
- {
- return new String_sort_list(1, *string_sort);
- }
- // Add an entry to a list of string/sort pairs. The way the parser
- // works permits us to simply modify the first parameter, rather than
- // copy the vector.
- extern "C" String_sort_list_ptr
- script_string_sort_list_add(String_sort_list_ptr pv,
- const struct Wildcard_section* string_sort)
- {
- if (pv == NULL)
- return script_new_string_sort_list(string_sort);
- else
- {
- pv->push_back(*string_sort);
- return pv;
- }
- }
- // Create a new list of strings.
- extern "C" String_list_ptr
- script_new_string_list(const char* str, size_t len)
- {
- return new String_list(1, std::string(str, len));
- }
- // Add an element to a list of strings. The way the parser works
- // permits us to simply modify the first parameter, rather than copy
- // the vector.
- extern "C" String_list_ptr
- script_string_list_push_back(String_list_ptr pv, const char* str, size_t len)
- {
- if (pv == NULL)
- return script_new_string_list(str, len);
- else
- {
- pv->push_back(std::string(str, len));
- return pv;
- }
- }
- // Concatenate two string lists. Either or both may be NULL. The way
- // the parser works permits us to modify the parameters, rather than
- // copy the vector.
- extern "C" String_list_ptr
- script_string_list_append(String_list_ptr pv1, String_list_ptr pv2)
- {
- if (pv1 == NULL)
- return pv2;
- if (pv2 == NULL)
- return pv1;
- pv1->insert(pv1->end(), pv2->begin(), pv2->end());
- return pv1;
- }
- // Add a new program header.
- extern "C" void
- script_add_phdr(void* closurev, const char* name, size_t namelen,
- unsigned int type, const Phdr_info* info)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- bool includes_filehdr = info->includes_filehdr != 0;
- bool includes_phdrs = info->includes_phdrs != 0;
- bool is_flags_valid = info->is_flags_valid != 0;
- Script_sections* ss = closure->script_options()->script_sections();
- ss->add_phdr(name, namelen, type, includes_filehdr, includes_phdrs,
- is_flags_valid, info->flags, info->load_address);
- closure->clear_skip_on_incompatible_target();
- }
- // Convert a program header string to a type.
- #define PHDR_TYPE(NAME) { #NAME, sizeof(#NAME) - 1, elfcpp::NAME }
- static struct
- {
- const char* name;
- size_t namelen;
- unsigned int val;
- } phdr_type_names[] =
- {
- PHDR_TYPE(PT_NULL),
- PHDR_TYPE(PT_LOAD),
- PHDR_TYPE(PT_DYNAMIC),
- PHDR_TYPE(PT_INTERP),
- PHDR_TYPE(PT_NOTE),
- PHDR_TYPE(PT_SHLIB),
- PHDR_TYPE(PT_PHDR),
- PHDR_TYPE(PT_TLS),
- PHDR_TYPE(PT_GNU_EH_FRAME),
- PHDR_TYPE(PT_GNU_STACK),
- PHDR_TYPE(PT_GNU_RELRO)
- };
- extern "C" unsigned int
- script_phdr_string_to_type(void* closurev, const char* name, size_t namelen)
- {
- for (unsigned int i = 0;
- i < sizeof(phdr_type_names) / sizeof(phdr_type_names[0]);
- ++i)
- if (namelen == phdr_type_names[i].namelen
- && strncmp(name, phdr_type_names[i].name, namelen) == 0)
- return phdr_type_names[i].val;
- yyerror(closurev, _("unknown PHDR type (try integer)"));
- return elfcpp::PT_NULL;
- }
- extern "C" void
- script_saw_segment_start_expression(void* closurev)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- Script_sections* ss = closure->script_options()->script_sections();
- ss->set_saw_segment_start_expression(true);
- }
- extern "C" void
- script_set_section_region(void* closurev, const char* name, size_t namelen,
- int set_vma)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- if (!closure->script_options()->saw_sections_clause())
- {
- gold_error(_("%s:%d:%d: MEMORY region '%.*s' referred to outside of "
- "SECTIONS clause"),
- closure->filename(), closure->lineno(), closure->charpos(),
- static_cast<int>(namelen), name);
- return;
- }
- Script_sections* ss = closure->script_options()->script_sections();
- Memory_region* mr = ss->find_memory_region(name, namelen);
- if (mr == NULL)
- {
- gold_error(_("%s:%d:%d: MEMORY region '%.*s' not declared"),
- closure->filename(), closure->lineno(), closure->charpos(),
- static_cast<int>(namelen), name);
- return;
- }
- ss->set_memory_region(mr, set_vma);
- }
- extern "C" void
- script_add_memory(void* closurev, const char* name, size_t namelen,
- unsigned int attrs, Expression* origin, Expression* length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- Script_sections* ss = closure->script_options()->script_sections();
- ss->add_memory_region(name, namelen, attrs, origin, length);
- }
- extern "C" unsigned int
- script_parse_memory_attr(void* closurev, const char* attrs, size_t attrlen,
- int invert)
- {
- int attributes = 0;
- while (attrlen--)
- switch (*attrs++)
- {
- case 'R':
- case 'r':
- attributes |= MEM_READABLE; break;
- case 'W':
- case 'w':
- attributes |= MEM_READABLE | MEM_WRITEABLE; break;
- case 'X':
- case 'x':
- attributes |= MEM_EXECUTABLE; break;
- case 'A':
- case 'a':
- attributes |= MEM_ALLOCATABLE; break;
- case 'I':
- case 'i':
- case 'L':
- case 'l':
- attributes |= MEM_INITIALIZED; break;
- default:
- yyerror(closurev, _("unknown MEMORY attribute"));
- }
- if (invert)
- attributes = (~ attributes) & MEM_ATTR_MASK;
- return attributes;
- }
- extern "C" void
- script_include_directive(int first_token, void* closurev,
- const char* filename, size_t length)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- std::string name(filename, length);
- Command_line* cmdline = closure->command_line();
- read_script_file(name.c_str(), cmdline, &cmdline->script_options(),
- first_token, Lex::LINKER_SCRIPT);
- }
- // Functions for memory regions.
- extern "C" Expression*
- script_exp_function_origin(void* closurev, const char* name, size_t namelen)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- Script_sections* ss = closure->script_options()->script_sections();
- Expression* origin = ss->find_memory_region_origin(name, namelen);
- if (origin == NULL)
- {
- gold_error(_("undefined memory region '%s' referenced "
- "in ORIGIN expression"),
- name);
- // Create a dummy expression to prevent crashes later on.
- origin = script_exp_integer(0);
- }
- return origin;
- }
- extern "C" Expression*
- script_exp_function_length(void* closurev, const char* name, size_t namelen)
- {
- Parser_closure* closure = static_cast<Parser_closure*>(closurev);
- Script_sections* ss = closure->script_options()->script_sections();
- Expression* length = ss->find_memory_region_length(name, namelen);
- if (length == NULL)
- {
- gold_error(_("undefined memory region '%s' referenced "
- "in LENGTH expression"),
- name);
- // Create a dummy expression to prevent crashes later on.
- length = script_exp_integer(0);
- }
- return length;
- }
|