12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504 |
- /* RISC-V-specific support for ELF.
- Copyright (C) 2011-2022 Free Software Foundation, Inc.
- Contributed by Andrew Waterman (andrew@sifive.com).
- Based on TILE-Gx and MIPS targets.
- This file is part of BFD, the Binary File Descriptor library.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; see the file COPYING3. If not,
- see <http://www.gnu.org/licenses/>. */
- #include "sysdep.h"
- #include "bfd.h"
- #include "libbfd.h"
- #include "elf-bfd.h"
- #include "elf/riscv.h"
- #include "opcode/riscv.h"
- #include "libiberty.h"
- #include "elfxx-riscv.h"
- #include "safe-ctype.h"
- #define MINUS_ONE ((bfd_vma)0 - 1)
- /* Special handler for ADD/SUB relocations that allows them to be filled out
- both in the pre-linked and post-linked file. This is necessary to make
- pre-linked debug info work, as due to linker relaxations we need to emit
- relocations for the debug info. */
- static bfd_reloc_status_type riscv_elf_add_sub_reloc
- (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
- /* The relocation table used for SHT_RELA sections. */
- static reloc_howto_type howto_table[] =
- {
- /* No relocation. */
- HOWTO (R_RISCV_NONE, /* type */
- 0, /* rightshift */
- 3, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_NONE", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* 32 bit relocation. */
- HOWTO (R_RISCV_32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 64 bit relocation. */
- HOWTO (R_RISCV_64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- /* Relocation against a local symbol in a shared object. */
- HOWTO (R_RISCV_RELATIVE, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_RELATIVE", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_COPY, /* type */
- 0, /* rightshift */
- 0, /* this one is variable size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_COPY", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_JUMP_SLOT, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_JUMP_SLOT", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* Dynamic TLS relocations. */
- HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_DTPMOD32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_TLS_DTPMOD64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_DTPMOD64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_TLS_DTPREL32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_DTPREL32", /* name */
- true, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_TLS_DTPREL64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_DTPREL64", /* name */
- true, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_TLS_TPREL32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_TPREL32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- HOWTO (R_RISCV_TLS_TPREL64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_TPREL64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- /* Reserved for future relocs that the dynamic linker must understand. */
- EMPTY_HOWTO (12),
- EMPTY_HOWTO (13),
- EMPTY_HOWTO (14),
- EMPTY_HOWTO (15),
- /* 12-bit PC-relative branch offset. */
- HOWTO (R_RISCV_BRANCH, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_BRANCH", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_BTYPE_IMM (-1U), /* dst_mask */
- true), /* pcrel_offset */
- /* 20-bit PC-relative jump offset. */
- HOWTO (R_RISCV_JAL, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_JAL", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_JTYPE_IMM (-1U), /* dst_mask */
- true), /* pcrel_offset */
- /* 32-bit PC-relative function call (AUIPC/JALR). */
- HOWTO (R_RISCV_CALL, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_CALL", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
- /* dst_mask */
- true), /* pcrel_offset */
- /* Like R_RISCV_CALL, but not locally binding. */
- HOWTO (R_RISCV_CALL_PLT, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_CALL_PLT", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U) | ((bfd_vma) ENCODE_ITYPE_IMM (-1U) << 32),
- /* dst_mask */
- true), /* pcrel_offset */
- /* High 20 bits of 32-bit PC-relative GOT access. */
- HOWTO (R_RISCV_GOT_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_GOT_HI20", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 20 bits of 32-bit PC-relative TLS IE GOT access. */
- HOWTO (R_RISCV_TLS_GOT_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_GOT_HI20", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 20 bits of 32-bit PC-relative TLS GD GOT reference. */
- HOWTO (R_RISCV_TLS_GD_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TLS_GD_HI20", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 20 bits of 32-bit PC-relative reference. */
- HOWTO (R_RISCV_PCREL_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_PCREL_HI20", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- true), /* pcrel_offset */
- /* Low 12 bits of a 32-bit PC-relative load or add. */
- HOWTO (R_RISCV_PCREL_LO12_I, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_PCREL_LO12_I", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_ITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* Low 12 bits of a 32-bit PC-relative store. */
- HOWTO (R_RISCV_PCREL_LO12_S, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_PCREL_LO12_S", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_STYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 20 bits of 32-bit absolute address. */
- HOWTO (R_RISCV_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_HI20", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 12 bits of 32-bit load or add. */
- HOWTO (R_RISCV_LO12_I, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_LO12_I", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_ITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 12 bits of 32-bit store. */
- HOWTO (R_RISCV_LO12_S, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_LO12_S", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_STYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* High 20 bits of TLS LE thread pointer offset. */
- HOWTO (R_RISCV_TPREL_HI20, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_HI20", /* name */
- true, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_UTYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* Low 12 bits of TLS LE thread pointer offset for loads and adds. */
- HOWTO (R_RISCV_TPREL_LO12_I, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_LO12_I", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_ITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* Low 12 bits of TLS LE thread pointer offset for stores. */
- HOWTO (R_RISCV_TPREL_LO12_S, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_LO12_S", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_STYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* TLS LE thread pointer usage. May be relaxed. */
- HOWTO (R_RISCV_TPREL_ADD, /* type */
- 0, /* rightshift */
- 3, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_ADD", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* 8-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_ADD8, /* type */
- 0, /* rightshift */
- 0, /* size */
- 8, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_ADD8", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xff, /* dst_mask */
- false), /* pcrel_offset */
- /* 16-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_ADD16, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_ADD16", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 32-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_ADD32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_ADD32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 64-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_ADD64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_ADD64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- /* 8-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_SUB8, /* type */
- 0, /* rightshift */
- 0, /* size */
- 8, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_SUB8", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xff, /* dst_mask */
- false), /* pcrel_offset */
- /* 16-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_SUB16, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_SUB16", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 32-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_SUB32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_SUB32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 64-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_SUB64, /* type */
- 0, /* rightshift */
- 4, /* size */
- 64, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_SUB64", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- MINUS_ONE, /* dst_mask */
- false), /* pcrel_offset */
- /* GNU extension to record C++ vtable hierarchy */
- HOWTO (R_RISCV_GNU_VTINHERIT, /* type */
- 0, /* rightshift */
- 4, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- NULL, /* special_function */
- "R_RISCV_GNU_VTINHERIT", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* GNU extension to record C++ vtable member usage */
- HOWTO (R_RISCV_GNU_VTENTRY, /* type */
- 0, /* rightshift */
- 4, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- _bfd_elf_rel_vtable_reloc_fn, /* special_function */
- "R_RISCV_GNU_VTENTRY", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* Indicates an alignment statement. The addend field encodes how many
- bytes of NOPs follow the statement. The desired alignment is the
- addend rounded up to the next power of two. */
- HOWTO (R_RISCV_ALIGN, /* type */
- 0, /* rightshift */
- 3, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_ALIGN", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* 8-bit PC-relative branch offset. */
- HOWTO (R_RISCV_RVC_BRANCH, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_RVC_BRANCH", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_CBTYPE_IMM (-1U), /* dst_mask */
- true), /* pcrel_offset */
- /* 11-bit PC-relative jump offset. */
- HOWTO (R_RISCV_RVC_JUMP, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_RVC_JUMP", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_CJTYPE_IMM (-1U), /* dst_mask */
- true), /* pcrel_offset */
- /* High 6 bits of 18-bit absolute address. */
- HOWTO (R_RISCV_RVC_LUI, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_RVC_LUI", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_CITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* GP-relative load. */
- HOWTO (R_RISCV_GPREL_I, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_GPREL_I", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_ITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* GP-relative store. */
- HOWTO (R_RISCV_GPREL_S, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_GPREL_S", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_STYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* TP-relative TLS LE load. */
- HOWTO (R_RISCV_TPREL_I, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_I", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_ITYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* TP-relative TLS LE store. */
- HOWTO (R_RISCV_TPREL_S, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_TPREL_S", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- ENCODE_STYPE_IMM (-1U), /* dst_mask */
- false), /* pcrel_offset */
- /* The paired relocation may be relaxed. */
- HOWTO (R_RISCV_RELAX, /* type */
- 0, /* rightshift */
- 3, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_RELAX", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
- /* 6-bit in-place addition, for local label subtraction. */
- HOWTO (R_RISCV_SUB6, /* type */
- 0, /* rightshift */
- 0, /* size */
- 8, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- riscv_elf_add_sub_reloc, /* special_function */
- "R_RISCV_SUB6", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x3f, /* dst_mask */
- false), /* pcrel_offset */
- /* 6-bit in-place setting, for local label subtraction. */
- HOWTO (R_RISCV_SET6, /* type */
- 0, /* rightshift */
- 0, /* size */
- 8, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_SET6", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0x3f, /* dst_mask */
- false), /* pcrel_offset */
- /* 8-bit in-place setting, for local label subtraction. */
- HOWTO (R_RISCV_SET8, /* type */
- 0, /* rightshift */
- 0, /* size */
- 8, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_SET8", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xff, /* dst_mask */
- false), /* pcrel_offset */
- /* 16-bit in-place setting, for local label subtraction. */
- HOWTO (R_RISCV_SET16, /* type */
- 0, /* rightshift */
- 1, /* size */
- 16, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_SET16", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 32-bit in-place setting, for local label subtraction. */
- HOWTO (R_RISCV_SET32, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_SET32", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- /* 32-bit PC relative. */
- HOWTO (R_RISCV_32_PCREL, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- true, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_32_PCREL", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- /* Relocation against a local ifunc symbol in a shared object. */
- HOWTO (R_RISCV_IRELATIVE, /* type */
- 0, /* rightshift */
- 2, /* size */
- 32, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
- "R_RISCV_IRELATIVE", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0xffffffff, /* dst_mask */
- false), /* pcrel_offset */
- };
- /* A mapping from BFD reloc types to RISC-V ELF reloc types. */
- struct elf_reloc_map
- {
- bfd_reloc_code_real_type bfd_val;
- enum elf_riscv_reloc_type elf_val;
- };
- static const struct elf_reloc_map riscv_reloc_map[] =
- {
- { BFD_RELOC_NONE, R_RISCV_NONE },
- { BFD_RELOC_32, R_RISCV_32 },
- { BFD_RELOC_64, R_RISCV_64 },
- { BFD_RELOC_RISCV_ADD8, R_RISCV_ADD8 },
- { BFD_RELOC_RISCV_ADD16, R_RISCV_ADD16 },
- { BFD_RELOC_RISCV_ADD32, R_RISCV_ADD32 },
- { BFD_RELOC_RISCV_ADD64, R_RISCV_ADD64 },
- { BFD_RELOC_RISCV_SUB8, R_RISCV_SUB8 },
- { BFD_RELOC_RISCV_SUB16, R_RISCV_SUB16 },
- { BFD_RELOC_RISCV_SUB32, R_RISCV_SUB32 },
- { BFD_RELOC_RISCV_SUB64, R_RISCV_SUB64 },
- { BFD_RELOC_CTOR, R_RISCV_64 },
- { BFD_RELOC_12_PCREL, R_RISCV_BRANCH },
- { BFD_RELOC_RISCV_HI20, R_RISCV_HI20 },
- { BFD_RELOC_RISCV_LO12_I, R_RISCV_LO12_I },
- { BFD_RELOC_RISCV_LO12_S, R_RISCV_LO12_S },
- { BFD_RELOC_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_I },
- { BFD_RELOC_RISCV_PCREL_LO12_S, R_RISCV_PCREL_LO12_S },
- { BFD_RELOC_RISCV_CALL, R_RISCV_CALL },
- { BFD_RELOC_RISCV_CALL_PLT, R_RISCV_CALL_PLT },
- { BFD_RELOC_RISCV_PCREL_HI20, R_RISCV_PCREL_HI20 },
- { BFD_RELOC_RISCV_JMP, R_RISCV_JAL },
- { BFD_RELOC_RISCV_GOT_HI20, R_RISCV_GOT_HI20 },
- { BFD_RELOC_RISCV_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 },
- { BFD_RELOC_RISCV_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 },
- { BFD_RELOC_RISCV_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 },
- { BFD_RELOC_RISCV_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 },
- { BFD_RELOC_RISCV_TLS_TPREL32, R_RISCV_TLS_TPREL32 },
- { BFD_RELOC_RISCV_TLS_TPREL64, R_RISCV_TLS_TPREL64 },
- { BFD_RELOC_RISCV_TPREL_HI20, R_RISCV_TPREL_HI20 },
- { BFD_RELOC_RISCV_TPREL_ADD, R_RISCV_TPREL_ADD },
- { BFD_RELOC_RISCV_TPREL_LO12_S, R_RISCV_TPREL_LO12_S },
- { BFD_RELOC_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_I },
- { BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
- { BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
- { BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
- { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
- { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
- { BFD_RELOC_RISCV_RVC_LUI, R_RISCV_RVC_LUI },
- { BFD_RELOC_RISCV_GPREL_I, R_RISCV_GPREL_I },
- { BFD_RELOC_RISCV_GPREL_S, R_RISCV_GPREL_S },
- { BFD_RELOC_RISCV_TPREL_I, R_RISCV_TPREL_I },
- { BFD_RELOC_RISCV_TPREL_S, R_RISCV_TPREL_S },
- { BFD_RELOC_RISCV_RELAX, R_RISCV_RELAX },
- { BFD_RELOC_RISCV_SUB6, R_RISCV_SUB6 },
- { BFD_RELOC_RISCV_SET6, R_RISCV_SET6 },
- { BFD_RELOC_RISCV_SET8, R_RISCV_SET8 },
- { BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
- { BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
- { BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
- };
- /* Given a BFD reloc type, return a howto structure. */
- reloc_howto_type *
- riscv_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
- bfd_reloc_code_real_type code)
- {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE (riscv_reloc_map); i++)
- if (riscv_reloc_map[i].bfd_val == code)
- return &howto_table[(int) riscv_reloc_map[i].elf_val];
- bfd_set_error (bfd_error_bad_value);
- return NULL;
- }
- reloc_howto_type *
- riscv_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
- {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE (howto_table); i++)
- if (howto_table[i].name && strcasecmp (howto_table[i].name, r_name) == 0)
- return &howto_table[i];
- return NULL;
- }
- reloc_howto_type *
- riscv_elf_rtype_to_howto (bfd *abfd, unsigned int r_type)
- {
- if (r_type >= ARRAY_SIZE (howto_table))
- {
- (*_bfd_error_handler) (_("%pB: unsupported relocation type %#x"),
- abfd, r_type);
- bfd_set_error (bfd_error_bad_value);
- return NULL;
- }
- return &howto_table[r_type];
- }
- /* Special_function of RISCV_ADD and RISCV_SUB relocations. */
- static bfd_reloc_status_type
- riscv_elf_add_sub_reloc (bfd *abfd,
- arelent *reloc_entry,
- asymbol *symbol,
- void *data,
- asection *input_section,
- bfd *output_bfd,
- char **error_message ATTRIBUTE_UNUSED)
- {
- reloc_howto_type *howto = reloc_entry->howto;
- bfd_vma relocation;
- if (output_bfd != NULL
- && (symbol->flags & BSF_SECTION_SYM) == 0
- && (!reloc_entry->howto->partial_inplace || reloc_entry->addend == 0))
- {
- reloc_entry->address += input_section->output_offset;
- return bfd_reloc_ok;
- }
- if (output_bfd != NULL)
- return bfd_reloc_continue;
- relocation = symbol->value + symbol->section->output_section->vma
- + symbol->section->output_offset + reloc_entry->addend;
- bfd_size_type octets = reloc_entry->address
- * bfd_octets_per_byte (abfd, input_section);
- if (!bfd_reloc_offset_in_range (reloc_entry->howto, abfd,
- input_section, octets))
- return bfd_reloc_outofrange;
- bfd_vma old_value = bfd_get (howto->bitsize, abfd,
- data + reloc_entry->address);
- switch (howto->type)
- {
- case R_RISCV_ADD8:
- case R_RISCV_ADD16:
- case R_RISCV_ADD32:
- case R_RISCV_ADD64:
- relocation = old_value + relocation;
- break;
- case R_RISCV_SUB6:
- case R_RISCV_SUB8:
- case R_RISCV_SUB16:
- case R_RISCV_SUB32:
- case R_RISCV_SUB64:
- relocation = old_value - relocation;
- break;
- }
- bfd_put (howto->bitsize, abfd, relocation, data + reloc_entry->address);
- return bfd_reloc_ok;
- }
- /* Always add the IMPLICIT for the SUBSET. */
- static bool
- check_implicit_always (const char *implicit ATTRIBUTE_UNUSED,
- riscv_subset_t *subset ATTRIBUTE_UNUSED)
- {
- return true;
- }
- /* Add the IMPLICIT only when the version of SUBSET less than 2.1. */
- static bool
- check_implicit_for_i (const char *implicit ATTRIBUTE_UNUSED,
- riscv_subset_t *subset)
- {
- return (subset->major_version < 2
- || (subset->major_version == 2
- && subset->minor_version < 1));
- }
- /* Record all implicit information for the subsets. */
- struct riscv_implicit_subset
- {
- const char *subset_name;
- const char *implicit_name;
- /* A function to determine if we need to add the implicit subset. */
- bool (*check_func) (const char *, riscv_subset_t *);
- };
- static struct riscv_implicit_subset riscv_implicit_subsets[] =
- {
- {"e", "i", check_implicit_always},
- {"i", "zicsr", check_implicit_for_i},
- {"i", "zifencei", check_implicit_for_i},
- {"g", "i", check_implicit_always},
- {"g", "m", check_implicit_always},
- {"g", "a", check_implicit_always},
- {"g", "f", check_implicit_always},
- {"g", "d", check_implicit_always},
- {"g", "zicsr", check_implicit_always},
- {"g", "zifencei", check_implicit_always},
- {"q", "d", check_implicit_always},
- {"v", "d", check_implicit_always},
- {"v", "zve64d", check_implicit_always},
- {"v", "zvl128b", check_implicit_always},
- {"zve64d", "d", check_implicit_always},
- {"zve64d", "zve64f", check_implicit_always},
- {"zve64f", "zve32f", check_implicit_always},
- {"zve64f", "zve64x", check_implicit_always},
- {"zve64f", "zvl64b", check_implicit_always},
- {"zve32f", "f", check_implicit_always},
- {"zve32f", "zvl32b", check_implicit_always},
- {"zve32f", "zve32x", check_implicit_always},
- {"zve64x", "zve32x", check_implicit_always},
- {"zve64x", "zvl64b", check_implicit_always},
- {"zve32x", "zvl32b", check_implicit_always},
- {"zvl65536b", "zvl32768b", check_implicit_always},
- {"zvl32768b", "zvl16384b", check_implicit_always},
- {"zvl16384b", "zvl8192b", check_implicit_always},
- {"zvl8192b", "zvl4096b", check_implicit_always},
- {"zvl4096b", "zvl2048b", check_implicit_always},
- {"zvl2048b", "zvl1024b", check_implicit_always},
- {"zvl1024b", "zvl512b", check_implicit_always},
- {"zvl512b", "zvl256b", check_implicit_always},
- {"zvl256b", "zvl128b", check_implicit_always},
- {"zvl128b", "zvl64b", check_implicit_always},
- {"zvl64b", "zvl32b", check_implicit_always},
- {"d", "f", check_implicit_always},
- {"f", "zicsr", check_implicit_always},
- {"zqinx", "zdinx", check_implicit_always},
- {"zdinx", "zfinx", check_implicit_always},
- {"zk", "zkn", check_implicit_always},
- {"zk", "zkr", check_implicit_always},
- {"zk", "zkt", check_implicit_always},
- {"zkn", "zbkb", check_implicit_always},
- {"zkn", "zbkc", check_implicit_always},
- {"zkn", "zbkx", check_implicit_always},
- {"zkn", "zkne", check_implicit_always},
- {"zkn", "zknd", check_implicit_always},
- {"zkn", "zknh", check_implicit_always},
- {"zks", "zbkb", check_implicit_always},
- {"zks", "zbkc", check_implicit_always},
- {"zks", "zbkx", check_implicit_always},
- {"zks", "zksed", check_implicit_always},
- {"zks", "zksh", check_implicit_always},
- {NULL, NULL, NULL}
- };
- /* For default_enable field, decide if the extension should
- be enbaled by default. */
- #define EXT_DEFAULT 0x1
- /* List all extensions that binutils should know about. */
- struct riscv_supported_ext
- {
- const char *name;
- enum riscv_spec_class isa_spec_class;
- int major_version;
- int minor_version;
- unsigned long default_enable;
- };
- /* The standard extensions must be added in canonical order. */
- static struct riscv_supported_ext riscv_supported_std_ext[] =
- {
- {"e", ISA_SPEC_CLASS_20191213, 1, 9, 0 },
- {"e", ISA_SPEC_CLASS_20190608, 1, 9, 0 },
- {"e", ISA_SPEC_CLASS_2P2, 1, 9, 0 },
- {"i", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
- {"i", ISA_SPEC_CLASS_20190608, 2, 1, 0 },
- {"i", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- /* The g is a special case which we don't want to output it,
- but still need it when adding implicit extensions. */
- {"g", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, EXT_DEFAULT },
- {"m", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
- {"m", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
- {"m", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"a", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
- {"a", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
- {"a", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"f", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
- {"f", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
- {"f", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"d", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
- {"d", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
- {"d", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"q", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
- {"q", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
- {"q", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"c", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
- {"c", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
- {"c", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
- {"v", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {NULL, 0, 0, 0, 0}
- };
- static struct riscv_supported_ext riscv_supported_std_z_ext[] =
- {
- {"zicbom", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zicbop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zicboz", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zicsr", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
- {"zicsr", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
- {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
- {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
- {"zihintpause", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zfinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zdinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zqinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zba", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbkb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbkc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zbkx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zk", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zkn", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zknd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zkne", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zknh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zkr", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zks", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zksed", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zksh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zkt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve32x", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve32f", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve32d", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve64x", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve64f", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zve64d", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl32b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl64b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl128b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl256b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl512b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl1024b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl2048b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl4096b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl8192b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl16384b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl32768b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {"zvl65536b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {NULL, 0, 0, 0, 0}
- };
- static struct riscv_supported_ext riscv_supported_std_s_ext[] =
- {
- {"svinval", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
- {NULL, 0, 0, 0, 0}
- };
- static struct riscv_supported_ext riscv_supported_std_h_ext[] =
- {
- {NULL, 0, 0, 0, 0}
- };
- static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
- {
- {NULL, 0, 0, 0, 0}
- };
- const struct riscv_supported_ext *riscv_all_supported_ext[] =
- {
- riscv_supported_std_ext,
- riscv_supported_std_z_ext,
- riscv_supported_std_s_ext,
- riscv_supported_std_h_ext,
- riscv_supported_std_zxm_ext,
- NULL
- };
- /* ISA extension prefixed name class. Must define them in parsing order. */
- enum riscv_prefix_ext_class
- {
- RV_ISA_CLASS_Z = 1,
- RV_ISA_CLASS_S,
- RV_ISA_CLASS_H,
- RV_ISA_CLASS_ZXM,
- RV_ISA_CLASS_X,
- RV_ISA_CLASS_UNKNOWN
- };
- /* Record the strings of the prefixed extensions, and their corresponding
- classes. The more letters of the prefix string, the more forward it must
- be defined. Otherwise, the riscv_get_prefix_class will map it to the
- wrong classes. */
- struct riscv_parse_prefix_config
- {
- /* Class of the extension. */
- enum riscv_prefix_ext_class class;
- /* Prefix string for error printing and internal parser usage. */
- const char *prefix;
- };
- static const struct riscv_parse_prefix_config parse_config[] =
- {
- {RV_ISA_CLASS_ZXM, "zxm"},
- {RV_ISA_CLASS_Z, "z"},
- {RV_ISA_CLASS_S, "s"},
- {RV_ISA_CLASS_H, "h"},
- {RV_ISA_CLASS_X, "x"},
- {RV_ISA_CLASS_UNKNOWN, NULL}
- };
- /* Get the prefixed name class for the extensions, the class also
- means the order of the prefixed extensions. */
- static enum riscv_prefix_ext_class
- riscv_get_prefix_class (const char *arch)
- {
- int i = 0;
- while (parse_config[i].class != RV_ISA_CLASS_UNKNOWN)
- {
- if (strncmp (arch, parse_config[i].prefix,
- strlen (parse_config[i].prefix)) == 0)
- return parse_config[i].class;
- i++;
- }
- return RV_ISA_CLASS_UNKNOWN;
- }
- /* Check KNOWN_EXTS to see if the EXT is supported. */
- static bool
- riscv_known_prefixed_ext (const char *ext,
- struct riscv_supported_ext *known_exts)
- {
- size_t i;
- for (i = 0; known_exts[i].name != NULL; ++i)
- if (strcmp (ext, known_exts[i].name) == 0)
- return true;
- return false;
- }
- /* Check whether the prefixed extension is recognized or not. Return
- true if recognized, otehrwise return false. */
- static bool
- riscv_recognized_prefixed_ext (const char *ext)
- {
- enum riscv_prefix_ext_class class = riscv_get_prefix_class (ext);
- switch (class)
- {
- case RV_ISA_CLASS_Z:
- return riscv_known_prefixed_ext (ext, riscv_supported_std_z_ext);
- case RV_ISA_CLASS_ZXM:
- return riscv_known_prefixed_ext (ext, riscv_supported_std_zxm_ext);
- case RV_ISA_CLASS_S:
- return riscv_known_prefixed_ext (ext, riscv_supported_std_s_ext);
- case RV_ISA_CLASS_H:
- return riscv_known_prefixed_ext (ext, riscv_supported_std_h_ext);
- case RV_ISA_CLASS_X:
- /* Only the single x is unrecognized. */
- if (strcmp (ext, "x") != 0)
- return true;
- default:
- break;
- }
- return false;
- }
- /* Canonical order for single letter extensions. */
- static const char riscv_ext_canonical_order[] = "eigmafdqlcbjktpvn";
- /* Array is used to compare the orders of standard extensions quickly. */
- static int riscv_ext_order[26] = {0};
- /* Init the riscv_ext_order array. */
- static void
- riscv_init_ext_order (void)
- {
- static bool inited = false;
- if (inited)
- return;
- /* The orders of all standard extensions are positive. */
- int order = 1;
- for (const char *ext = &riscv_ext_canonical_order[0]; *ext; ++ext)
- riscv_ext_order[(*ext - 'a')] = order++;
- /* Some of the prefixed keyword are not single letter, so we set
- their prefixed orders in the riscv_compare_subsets directly,
- not through the riscv_ext_order. */
- inited = true;
- }
- /* Similar to the strcmp. It returns an integer less than, equal to,
- or greater than zero if `subset2` is found, respectively, to be less
- than, to match, or be greater than `subset1`.
- The order values,
- Zero: Preserved keywords.
- Positive number: Standard extensions.
- Negative number: Prefixed keywords. */
- int
- riscv_compare_subsets (const char *subset1, const char *subset2)
- {
- int order1 = riscv_ext_order[(*subset1 - 'a')];
- int order2 = riscv_ext_order[(*subset2 - 'a')];
- /* Compare the standard extension first. */
- if (order1 > 0 && order2 > 0)
- return order1 - order2;
- /* Set the prefixed orders to negative numbers. */
- enum riscv_prefix_ext_class class1 = riscv_get_prefix_class (subset1);
- enum riscv_prefix_ext_class class2 = riscv_get_prefix_class (subset2);
- if (class1 != RV_ISA_CLASS_UNKNOWN)
- order1 = - (int) class1;
- if (class2 != RV_ISA_CLASS_UNKNOWN)
- order2 = - (int) class2;
- if (order1 == order2)
- {
- /* Compare the standard addition z extensions. */
- if (class1 == RV_ISA_CLASS_Z)
- {
- order1 = riscv_ext_order[(*++subset1 - 'a')];
- order2 = riscv_ext_order[(*++subset2 - 'a')];
- if (order1 != order2)
- return order1 - order2;
- }
- return strcasecmp (++subset1, ++subset2);
- }
- return order2 - order1;
- }
- /* Find subset in the list. Return TRUE and set `current` to the subset
- if it is found. Otherwise, return FALSE and set `current` to the place
- where we should insert the subset. However, return FALSE with the NULL
- `current` means we should insert the subset at the head of subset list,
- if needed. */
- bool
- riscv_lookup_subset (const riscv_subset_list_t *subset_list,
- const char *subset,
- riscv_subset_t **current)
- {
- riscv_subset_t *s, *pre_s = NULL;
- /* If the subset is added in order, then just add it at the tail. */
- if (subset_list->tail != NULL
- && riscv_compare_subsets (subset_list->tail->name, subset) < 0)
- {
- *current = subset_list->tail;
- return false;
- }
- for (s = subset_list->head;
- s != NULL;
- pre_s = s, s = s->next)
- {
- int cmp = riscv_compare_subsets (s->name, subset);
- if (cmp == 0)
- {
- *current = s;
- return true;
- }
- else if (cmp > 0)
- break;
- }
- *current = pre_s;
- return false;
- }
- /* Add the extension to the subset list. Search the
- list first, and then find the right place to add. */
- void
- riscv_add_subset (riscv_subset_list_t *subset_list,
- const char *subset,
- int major,
- int minor)
- {
- riscv_subset_t *current, *new;
- if (riscv_lookup_subset (subset_list, subset, ¤t))
- return;
- new = xmalloc (sizeof *new);
- new->name = xstrdup (subset);
- new->major_version = major;
- new->minor_version = minor;
- new->next = NULL;
- if (current != NULL)
- {
- new->next = current->next;
- current->next = new;
- }
- else
- {
- new->next = subset_list->head;
- subset_list->head = new;
- }
- if (new->next == NULL)
- subset_list->tail = new;
- }
- /* Get the default versions from the riscv_supported_*ext tables. */
- static void
- riscv_get_default_ext_version (enum riscv_spec_class *default_isa_spec,
- const char *name,
- int *major_version,
- int *minor_version)
- {
- if (name == NULL
- || default_isa_spec == NULL
- || *default_isa_spec == ISA_SPEC_CLASS_NONE)
- return;
- struct riscv_supported_ext *table = NULL;
- enum riscv_prefix_ext_class class = riscv_get_prefix_class (name);
- switch (class)
- {
- case RV_ISA_CLASS_ZXM: table = riscv_supported_std_zxm_ext; break;
- case RV_ISA_CLASS_Z: table = riscv_supported_std_z_ext; break;
- case RV_ISA_CLASS_S: table = riscv_supported_std_s_ext; break;
- case RV_ISA_CLASS_H: table = riscv_supported_std_h_ext; break;
- case RV_ISA_CLASS_X:
- break;
- default:
- table = riscv_supported_std_ext;
- }
- int i = 0;
- while (table != NULL && table[i].name != NULL)
- {
- if (strcmp (table[i].name, name) == 0
- && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT
- || table[i].isa_spec_class == *default_isa_spec))
- {
- *major_version = table[i].major_version;
- *minor_version = table[i].minor_version;
- return;
- }
- i++;
- }
- }
- /* Find the default versions for the extension before adding them to
- the subset list, if their versions are RISCV_UNKNOWN_VERSION.
- Afterwards, report errors if we can not find their default versions. */
- static void
- riscv_parse_add_subset (riscv_parse_subset_t *rps,
- const char *subset,
- int major,
- int minor,
- bool implicit)
- {
- int major_version = major;
- int minor_version = minor;
- if (major_version == RISCV_UNKNOWN_VERSION
- || minor_version == RISCV_UNKNOWN_VERSION)
- riscv_get_default_ext_version (rps->isa_spec, subset,
- &major_version, &minor_version);
- /* We don't care the versions of the implicit extensions. */
- if (!implicit
- && (major_version == RISCV_UNKNOWN_VERSION
- || minor_version == RISCV_UNKNOWN_VERSION))
- {
- if (subset[0] == 'x')
- rps->error_handler
- (_("x ISA extension `%s' must be set with the versions"),
- subset);
- /* Allow old ISA spec can recognize zicsr and zifencei. */
- else if (strcmp (subset, "zicsr") != 0
- && strcmp (subset, "zifencei") != 0)
- rps->error_handler
- (_("cannot find default versions of the ISA extension `%s'"),
- subset);
- return;
- }
- riscv_add_subset (rps->subset_list, subset,
- major_version, minor_version);
- }
- /* Release subset list. */
- void
- riscv_release_subset_list (riscv_subset_list_t *subset_list)
- {
- while (subset_list->head != NULL)
- {
- riscv_subset_t *next = subset_list->head->next;
- free ((void *)subset_list->head->name);
- free (subset_list->head);
- subset_list->head = next;
- }
- subset_list->tail = NULL;
- }
- /* Parsing extension version.
- Return Value:
- Points to the end of version
- Arguments:
- `p`: Curent parsing position.
- `major_version`: Parsed major version.
- `minor_version`: Parsed minor version. */
- static const char *
- riscv_parsing_subset_version (const char *p,
- int *major_version,
- int *minor_version)
- {
- bool major_p = true;
- int version = 0;
- char np;
- *major_version = 0;
- *minor_version = 0;
- for (; *p; ++p)
- {
- if (*p == 'p')
- {
- np = *(p + 1);
- /* Might be beginning of `p` extension. */
- if (!ISDIGIT (np))
- break;
- *major_version = version;
- major_p = false;
- version = 0;
- }
- else if (ISDIGIT (*p))
- version = (version * 10) + (*p - '0');
- else
- break;
- }
- if (major_p)
- *major_version = version;
- else
- *minor_version = version;
- /* We can not find any version in string. */
- if (*major_version == 0 && *minor_version == 0)
- {
- *major_version = RISCV_UNKNOWN_VERSION;
- *minor_version = RISCV_UNKNOWN_VERSION;
- }
- return p;
- }
- /* Parsing function for standard extensions.
- Return Value:
- Points to the end of extensions.
- Arguments:
- `rps`: Hooks and status for parsing extensions.
- `arch`: Full ISA string.
- `p`: Curent parsing position. */
- static const char *
- riscv_parse_std_ext (riscv_parse_subset_t *rps,
- const char *arch,
- const char *p)
- {
- /* First letter must start with i, e or g. */
- if (*p != 'e' && *p != 'i' && *p != 'g')
- {
- rps->error_handler
- (_("%s: first ISA extension must be `e', `i' or `g'"),
- arch);
- return NULL;
- }
- while (p != NULL && *p != '\0')
- {
- /* Stop when we parsed the known prefix class. */
- enum riscv_prefix_ext_class class = riscv_get_prefix_class (p);
- if (class != RV_ISA_CLASS_UNKNOWN)
- break;
- if (*p == '_')
- {
- p++;
- continue;
- }
- bool implicit = false;
- int major = RISCV_UNKNOWN_VERSION;
- int minor = RISCV_UNKNOWN_VERSION;
- char subset[2] = {0, 0};
- subset[0] = *p;
- /* Check if the standard extension is supported. */
- if (riscv_ext_order[(subset[0] - 'a')] == 0)
- {
- rps->error_handler
- (_("%s: unknown standard ISA extension `%c'"),
- arch, subset[0]);
- return NULL;
- }
- /* Checking canonical order. */
- if (rps->subset_list->tail != NULL
- && riscv_compare_subsets (rps->subset_list->tail->name, subset) > 0)
- {
- rps->error_handler
- (_("%s: standard ISA extension `%c' is not "
- "in canonical order"), arch, subset[0]);
- return NULL;
- }
- p = riscv_parsing_subset_version (++p, &major, &minor);
- /* Added g as an implicit extension. */
- if (subset[0] == 'g')
- {
- implicit = true;
- major = RISCV_UNKNOWN_VERSION;
- minor = RISCV_UNKNOWN_VERSION;
- }
- riscv_parse_add_subset (rps, subset, major, minor, implicit);
- }
- return p;
- }
- /* Parsing function for prefixed extensions.
- Return Value:
- Points to the end of extension.
- Arguments:
- `rps`: Hooks and status for parsing extensions.
- `arch`: Full ISA string.
- `p`: Curent parsing position. */
- static const char *
- riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
- const char *arch,
- const char *p)
- {
- int major_version;
- int minor_version;
- const char *last_name;
- enum riscv_prefix_ext_class class;
- while (*p)
- {
- if (*p == '_')
- {
- p++;
- continue;
- }
- class = riscv_get_prefix_class (p);
- if (class == RV_ISA_CLASS_UNKNOWN)
- {
- rps->error_handler
- (_("%s: unknown prefix class for the ISA extension `%s'"),
- arch, p);
- return NULL;
- }
- char *subset = xstrdup (p);
- char *q = subset;
- const char *end_of_version;
- /* Extract the whole prefixed extension by '_'. */
- while (*++q != '\0' && *q != '_')
- ;
- /* Look forward to the first letter which is not <major>p<minor>. */
- bool find_any_version = false;
- bool find_minor_version = false;
- while (1)
- {
- q--;
- if (ISDIGIT (*q))
- find_any_version = true;
- else if (find_any_version
- && !find_minor_version
- && *q == 'p'
- && ISDIGIT (*(q - 1)))
- find_minor_version = true;
- else
- break;
- }
- q++;
- /* Check if the end of extension is 'p' or not. If yes, then
- the second letter from the end cannot be number. */
- if (*(q - 1) == 'p' && ISDIGIT (*(q - 2)))
- {
- *q = '\0';
- rps->error_handler
- (_("%s: invalid prefixed ISA extension `%s' ends with <number>p"),
- arch, subset);
- free (subset);
- return NULL;
- }
- end_of_version =
- riscv_parsing_subset_version (q, &major_version, &minor_version);
- *q = '\0';
- if (end_of_version == NULL)
- {
- free (subset);
- return NULL;
- }
- /* Check that the extension name is well-formed. */
- if (rps->check_unknown_prefixed_ext
- && !riscv_recognized_prefixed_ext (subset))
- {
- rps->error_handler
- (_("%s: unknown prefixed ISA extension `%s'"),
- arch, subset);
- free (subset);
- return NULL;
- }
- /* Check that the extension isn't duplicate. */
- last_name = rps->subset_list->tail->name;
- if (!strcasecmp (last_name, subset))
- {
- rps->error_handler
- (_("%s: duplicate prefixed ISA extension `%s'"),
- arch, subset);
- free (subset);
- return NULL;
- }
- /* Check that the extension is in expected order. */
- if (riscv_compare_subsets (last_name, subset) > 0)
- {
- rps->error_handler
- (_("%s: prefixed ISA extension `%s' is not in expected "
- "order. It must come before `%s'"),
- arch, subset, last_name);
- free (subset);
- return NULL;
- }
- riscv_parse_add_subset (rps, subset,
- major_version,
- minor_version, false);
- p += end_of_version - subset;
- free (subset);
- if (*p != '\0' && *p != '_')
- {
- rps->error_handler
- (_("%s: prefixed ISA extension must separate with _"),
- arch);
- return NULL;
- }
- }
- return p;
- }
- /* Add the implicit extensions. */
- static void
- riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
- {
- struct riscv_implicit_subset *t = riscv_implicit_subsets;
- for (; t->subset_name; t++)
- {
- riscv_subset_t *subset = NULL;
- if (riscv_lookup_subset (rps->subset_list, t->subset_name, &subset)
- && t->check_func (t->implicit_name, subset))
- riscv_parse_add_subset (rps, t->implicit_name,
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, true);
- }
- }
- /* Check extensions conflicts. */
- static bool
- riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
- {
- riscv_subset_t *subset = NULL;
- int xlen = *rps->xlen;
- bool no_conflict = true;
- if (riscv_lookup_subset (rps->subset_list, "e", &subset)
- && xlen > 32)
- {
- rps->error_handler
- (_("rv%d does not support the `e' extension"), xlen);
- no_conflict = false;
- }
- if (riscv_lookup_subset (rps->subset_list, "q", &subset)
- && xlen < 64)
- {
- rps->error_handler
- (_("rv%d does not support the `q' extension"), xlen);
- no_conflict = false;
- }
- if (riscv_lookup_subset (rps->subset_list, "e", &subset)
- && riscv_lookup_subset (rps->subset_list, "f", &subset))
- {
- rps->error_handler
- (_("rv32e does not support the `f' extension"));
- no_conflict = false;
- }
- if (riscv_lookup_subset (rps->subset_list, "zfinx", &subset)
- && riscv_lookup_subset (rps->subset_list, "f", &subset))
- {
- rps->error_handler
- (_("`zfinx' is conflict with the `f/d/q' extension"));
- no_conflict = false;
- }
- bool support_zve = false;
- bool support_zvl = false;
- riscv_subset_t *s = rps->subset_list->head;
- for (; s != NULL; s = s->next)
- {
- if (!support_zve
- && strncmp (s->name, "zve", 3) == 0)
- support_zve = true;
- if (!support_zvl
- && strncmp (s->name, "zvl", 3) == 0)
- support_zvl = true;
- if (support_zve && support_zvl)
- break;
- }
- if (support_zvl && !support_zve)
- {
- rps->error_handler
- (_("zvl*b extensions need to enable either `v' or `zve' extension"));
- no_conflict = false;
- }
- return no_conflict;
- }
- /* Set the default subset list according to the default_enable field
- of riscv_supported_*ext tables. */
- static void
- riscv_set_default_arch (riscv_parse_subset_t *rps)
- {
- unsigned long enable = EXT_DEFAULT;
- int i, j;
- for (i = 0; riscv_all_supported_ext[i] != NULL; i++)
- {
- const struct riscv_supported_ext *table = riscv_all_supported_ext[i];
- for (j = 0; table[j].name != NULL; j++)
- {
- bool implicit = false;
- if (strcmp (table[j].name, "g") == 0)
- implicit = true;
- if (table[j].default_enable & enable)
- riscv_parse_add_subset (rps, table[j].name,
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, implicit);
- }
- }
- }
- /* Function for parsing ISA string.
- Return Value:
- Return TRUE on success.
- Arguments:
- `rps`: Hooks and status for parsing extensions.
- `arch`: Full ISA string. */
- bool
- riscv_parse_subset (riscv_parse_subset_t *rps,
- const char *arch)
- {
- const char *p;
- /* Init the riscv_ext_order array to compare the order of extensions
- quickly. */
- riscv_init_ext_order ();
- if (arch == NULL)
- {
- riscv_set_default_arch (rps);
- riscv_parse_add_implicit_subsets (rps);
- return riscv_parse_check_conflicts (rps);
- }
- for (p = arch; *p != '\0'; p++)
- {
- if (ISUPPER (*p))
- {
- rps->error_handler
- (_("%s: ISA string cannot contain uppercase letters"),
- arch);
- return false;
- }
- }
- p = arch;
- if (startswith (p, "rv32"))
- {
- *rps->xlen = 32;
- p += 4;
- }
- else if (startswith (p, "rv64"))
- {
- *rps->xlen = 64;
- p += 4;
- }
- else
- {
- /* ISA string shouldn't be NULL or empty here. For linker,
- it might be empty when we failed to merge the ISA string
- in the riscv_merge_attributes. For assembler, we might
- give an empty string by .attribute arch, "" or -march=.
- However, We have already issued the correct error message
- in another side, so do not issue this error when the ISA
- string is empty. */
- if (strlen (arch))
- rps->error_handler (
- _("%s: ISA string must begin with rv32 or rv64"),
- arch);
- return false;
- }
- /* Parsing standard extension. */
- p = riscv_parse_std_ext (rps, arch, p);
- if (p == NULL)
- return false;
- /* Parse prefixed extensions. */
- p = riscv_parse_prefixed_ext (rps, arch, p);
- if (p == NULL)
- return false;
- /* Finally add implicit extensions according to the current
- extensions. */
- riscv_parse_add_implicit_subsets (rps);
- /* Check the conflicts. */
- return riscv_parse_check_conflicts (rps);
- }
- /* Return the number of digits for the input. */
- size_t
- riscv_estimate_digit (unsigned num)
- {
- size_t digit = 0;
- if (num == 0)
- return 1;
- for (digit = 0; num ; num /= 10)
- digit++;
- return digit;
- }
- /* Auxiliary function to estimate string length of subset list. */
- static size_t
- riscv_estimate_arch_strlen1 (const riscv_subset_t *subset)
- {
- if (subset == NULL)
- return 6; /* For rv32/rv64/rv128 and string terminator. */
- return riscv_estimate_arch_strlen1 (subset->next)
- + strlen (subset->name)
- + riscv_estimate_digit (subset->major_version)
- + 1 /* For version seperator 'p'. */
- + riscv_estimate_digit (subset->minor_version)
- + 1 /* For underscore. */;
- }
- /* Estimate the string length of this subset list. */
- static size_t
- riscv_estimate_arch_strlen (const riscv_subset_list_t *subset_list)
- {
- return riscv_estimate_arch_strlen1 (subset_list->head);
- }
- /* Auxiliary function to convert subset info to string. */
- static void
- riscv_arch_str1 (riscv_subset_t *subset,
- char *attr_str, char *buf, size_t bufsz)
- {
- const char *underline = "_";
- riscv_subset_t *subset_t = subset;
- if (subset_t == NULL)
- return;
- /* No underline between rvXX and i/e. */
- if ((strcasecmp (subset_t->name, "i") == 0)
- || (strcasecmp (subset_t->name, "e") == 0))
- underline = "";
- snprintf (buf, bufsz, "%s%s%dp%d",
- underline,
- subset_t->name,
- subset_t->major_version,
- subset_t->minor_version);
- strncat (attr_str, buf, bufsz);
- /* Skip 'i' extension after 'e', or skip extensions which
- versions are unknown. */
- while (subset_t->next
- && ((strcmp (subset_t->name, "e") == 0
- && strcmp (subset_t->next->name, "i") == 0)
- || subset_t->next->major_version == RISCV_UNKNOWN_VERSION
- || subset_t->next->minor_version == RISCV_UNKNOWN_VERSION))
- subset_t = subset_t->next;
- riscv_arch_str1 (subset_t->next, attr_str, buf, bufsz);
- }
- /* Convert subset information into string with explicit versions. */
- char *
- riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
- {
- size_t arch_str_len = riscv_estimate_arch_strlen (subset);
- char *attr_str = xmalloc (arch_str_len);
- char *buf = xmalloc (arch_str_len);
- snprintf (attr_str, arch_str_len, "rv%u", xlen);
- riscv_arch_str1 (subset->head, attr_str, buf, arch_str_len);
- free (buf);
- return attr_str;
- }
- /* Copy the subset in the subset list. */
- static struct riscv_subset_t *
- riscv_copy_subset (riscv_subset_list_t *subset_list,
- riscv_subset_t *subset)
- {
- if (subset == NULL)
- return NULL;
- riscv_subset_t *new = xmalloc (sizeof *new);
- new->name = xstrdup (subset->name);
- new->major_version = subset->major_version;
- new->minor_version = subset->minor_version;
- new->next = riscv_copy_subset (subset_list, subset->next);
- if (subset->next == NULL)
- subset_list->tail = new;
- return new;
- }
- /* Copy the subset list. */
- riscv_subset_list_t *
- riscv_copy_subset_list (riscv_subset_list_t *subset_list)
- {
- riscv_subset_list_t *new = xmalloc (sizeof *new);
- new->head = riscv_copy_subset (new, subset_list->head);
- return new;
- }
- /* Remove the SUBSET from the subset list. */
- static void
- riscv_remove_subset (riscv_subset_list_t *subset_list,
- const char *subset)
- {
- riscv_subset_t *current = subset_list->head;
- riscv_subset_t *pre = NULL;
- for (; current != NULL; pre = current, current = current->next)
- {
- if (strcmp (current->name, subset) == 0)
- {
- if (pre == NULL)
- subset_list->head = current->next;
- else
- pre->next = current->next;
- if (current->next == NULL)
- subset_list->tail = pre;
- free ((void *) current->name);
- free (current);
- break;
- }
- }
- }
- /* Add/Remove an extension to/from the subset list. This is used for
- the .option rvc or norvc, and .option arch directives. */
- bool
- riscv_update_subset (riscv_parse_subset_t *rps,
- const char *str)
- {
- const char *p = str;
- do
- {
- int major_version = RISCV_UNKNOWN_VERSION;
- int minor_version = RISCV_UNKNOWN_VERSION;
- bool removed = false;
- switch (*p)
- {
- case '+': removed = false; break;
- case '-': removed = true; break;
- default:
- riscv_release_subset_list (rps->subset_list);
- return riscv_parse_subset (rps, p);
- }
- ++p;
- char *subset = xstrdup (p);
- char *q = subset;
- const char *end_of_version;
- /* Extract the whole prefixed extension by ','. */
- while (*q != '\0' && *q != ',')
- q++;
- /* Look forward to the first letter which is not <major>p<minor>. */
- bool find_any_version = false;
- bool find_minor_version = false;
- size_t len = q - subset;
- size_t i;
- for (i = len; i > 0; i--)
- {
- q--;
- if (ISDIGIT (*q))
- find_any_version = true;
- else if (find_any_version
- && !find_minor_version
- && *q == 'p'
- && ISDIGIT (*(q - 1)))
- find_minor_version = true;
- else
- break;
- }
- if (len > 0)
- q++;
- /* Check if the end of extension is 'p' or not. If yes, then
- the second letter from the end cannot be number. */
- if (len > 1 && *(q - 1) == 'p' && ISDIGIT (*(q - 2)))
- {
- *q = '\0';
- rps->error_handler
- (_("invalid ISA extension ends with <number>p "
- "in .option arch `%s'"), str);
- free (subset);
- return false;
- }
- end_of_version =
- riscv_parsing_subset_version (q, &major_version, &minor_version);
- *q = '\0';
- if (end_of_version == NULL)
- {
- free (subset);
- return false;
- }
- if (strlen (subset) == 0
- || (strlen (subset) == 1
- && riscv_ext_order[(*subset - 'a')] == 0)
- || (strlen (subset) > 1
- && rps->check_unknown_prefixed_ext
- && !riscv_recognized_prefixed_ext (subset)))
- {
- rps->error_handler
- (_("unknown ISA extension `%s' in .option arch `%s'"),
- subset, str);
- free (subset);
- return false;
- }
- if (strcmp (subset, "i") == 0
- || strcmp (subset, "e") == 0
- || strcmp (subset, "g") == 0)
- {
- rps->error_handler
- (_("cannot + or - base extension `%s' in .option "
- "arch `%s'"), subset, str);
- free (subset);
- return false;
- }
- if (removed)
- riscv_remove_subset (rps->subset_list, subset);
- else
- riscv_parse_add_subset (rps, subset, major_version, minor_version, true);
- p += end_of_version - subset;
- free (subset);
- }
- while (*p++ == ',');
- riscv_parse_add_implicit_subsets (rps);
- return riscv_parse_check_conflicts (rps);
- }
- /* Check if the FEATURE subset is supported or not in the subset list.
- Return true if it is supported; Otherwise, return false. */
- bool
- riscv_subset_supports (riscv_parse_subset_t *rps,
- const char *feature)
- {
- struct riscv_subset_t *subset;
- return riscv_lookup_subset (rps->subset_list, feature, &subset);
- }
- /* Each instuction is belonged to an instruction class INSN_CLASS_*.
- Call riscv_subset_supports to make sure if the instuction is valid. */
- bool
- riscv_multi_subset_supports (riscv_parse_subset_t *rps,
- enum riscv_insn_class insn_class)
- {
- switch (insn_class)
- {
- case INSN_CLASS_I:
- return riscv_subset_supports (rps, "i");
- case INSN_CLASS_ZICBOM:
- return riscv_subset_supports (rps, "zicbom");
- case INSN_CLASS_ZICBOP:
- return riscv_subset_supports (rps, "zicbop");
- case INSN_CLASS_ZICBOZ:
- return riscv_subset_supports (rps, "zicboz");
- case INSN_CLASS_ZICSR:
- return riscv_subset_supports (rps, "zicsr");
- case INSN_CLASS_ZIFENCEI:
- return riscv_subset_supports (rps, "zifencei");
- case INSN_CLASS_ZIHINTPAUSE:
- return riscv_subset_supports (rps, "zihintpause");
- case INSN_CLASS_M:
- return riscv_subset_supports (rps, "m");
- case INSN_CLASS_A:
- return riscv_subset_supports (rps, "a");
- case INSN_CLASS_F:
- return riscv_subset_supports (rps, "f");
- case INSN_CLASS_D:
- return riscv_subset_supports (rps, "d");
- case INSN_CLASS_Q:
- return riscv_subset_supports (rps, "q");
- case INSN_CLASS_C:
- return riscv_subset_supports (rps, "c");
- case INSN_CLASS_F_AND_C:
- return (riscv_subset_supports (rps, "f")
- && riscv_subset_supports (rps, "c"));
- case INSN_CLASS_D_AND_C:
- return (riscv_subset_supports (rps, "d")
- && riscv_subset_supports (rps, "c"));
- case INSN_CLASS_F_OR_ZFINX:
- return (riscv_subset_supports (rps, "f")
- || riscv_subset_supports (rps, "zfinx"));
- case INSN_CLASS_D_OR_ZDINX:
- return (riscv_subset_supports (rps, "d")
- || riscv_subset_supports (rps, "zdinx"));
- case INSN_CLASS_Q_OR_ZQINX:
- return (riscv_subset_supports (rps, "q")
- || riscv_subset_supports (rps, "zqinx"));
- case INSN_CLASS_ZBA:
- return riscv_subset_supports (rps, "zba");
- case INSN_CLASS_ZBB:
- return riscv_subset_supports (rps, "zbb");
- case INSN_CLASS_ZBC:
- return riscv_subset_supports (rps, "zbc");
- case INSN_CLASS_ZBS:
- return riscv_subset_supports (rps, "zbs");
- case INSN_CLASS_ZBKB:
- return riscv_subset_supports (rps, "zbkb");
- case INSN_CLASS_ZBKC:
- return riscv_subset_supports (rps, "zbkc");
- case INSN_CLASS_ZBKX:
- return riscv_subset_supports (rps, "zbkx");
- case INSN_CLASS_ZBB_OR_ZBKB:
- return (riscv_subset_supports (rps, "zbb")
- || riscv_subset_supports (rps, "zbkb"));
- case INSN_CLASS_ZBC_OR_ZBKC:
- return (riscv_subset_supports (rps, "zbc")
- || riscv_subset_supports (rps, "zbkc"));
- case INSN_CLASS_ZKND:
- return riscv_subset_supports (rps, "zknd");
- case INSN_CLASS_ZKNE:
- return riscv_subset_supports (rps, "zkne");
- case INSN_CLASS_ZKNH:
- return riscv_subset_supports (rps, "zknh");
- case INSN_CLASS_ZKND_OR_ZKNE:
- return (riscv_subset_supports (rps, "zknd")
- || riscv_subset_supports (rps, "zkne"));
- case INSN_CLASS_ZKSED:
- return riscv_subset_supports (rps, "zksed");
- case INSN_CLASS_ZKSH:
- return riscv_subset_supports (rps, "zksh");
- case INSN_CLASS_V:
- return (riscv_subset_supports (rps, "v")
- || riscv_subset_supports (rps, "zve64x")
- || riscv_subset_supports (rps, "zve32x"));
- case INSN_CLASS_ZVEF:
- return (riscv_subset_supports (rps, "v")
- || riscv_subset_supports (rps, "zve64d")
- || riscv_subset_supports (rps, "zve64f")
- || riscv_subset_supports (rps, "zve32f"));
- case INSN_CLASS_SVINVAL:
- return riscv_subset_supports (rps, "svinval");
- default:
- rps->error_handler
- (_("internal: unreachable INSN_CLASS_*"));
- return false;
- }
- }
- /* Each instuction is belonged to an instruction class INSN_CLASS_*.
- Call riscv_subset_supports_ext to determine the missing extension. */
- const char *
- riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
- enum riscv_insn_class insn_class)
- {
- switch (insn_class)
- {
- case INSN_CLASS_I:
- return "i";
- case INSN_CLASS_ZICSR:
- return "zicsr";
- case INSN_CLASS_ZIFENCEI:
- return "zifencei";
- case INSN_CLASS_ZIHINTPAUSE:
- return "zihintpause";
- case INSN_CLASS_M:
- return "m";
- case INSN_CLASS_A:
- return "a";
- case INSN_CLASS_F:
- return "f";
- case INSN_CLASS_D:
- return "d";
- case INSN_CLASS_Q:
- return "q";
- case INSN_CLASS_C:
- return "c";
- case INSN_CLASS_F_AND_C:
- if (!riscv_subset_supports (rps, "f")
- && !riscv_subset_supports (rps, "c"))
- return "f' and `c";
- else if (!riscv_subset_supports (rps, "f"))
- return "f";
- else
- return "c";
- case INSN_CLASS_D_AND_C:
- if (!riscv_subset_supports (rps, "d")
- && !riscv_subset_supports (rps, "c"))
- return "d' and `c";
- else if (!riscv_subset_supports (rps, "d"))
- return "d";
- else
- return "c";
- case INSN_CLASS_F_OR_ZFINX:
- return "f' or `zfinx";
- case INSN_CLASS_D_OR_ZDINX:
- return "d' or `zdinx";
- case INSN_CLASS_Q_OR_ZQINX:
- return "q' or `zqinx";
- case INSN_CLASS_ZBA:
- return "zba";
- case INSN_CLASS_ZBB:
- return "zbb";
- case INSN_CLASS_ZBC:
- return "zbc";
- case INSN_CLASS_ZBS:
- return "zbs";
- case INSN_CLASS_ZBKB:
- return "zbkb";
- case INSN_CLASS_ZBKC:
- return "zbkc";
- case INSN_CLASS_ZBKX:
- return "zbkx";
- case INSN_CLASS_ZBB_OR_ZBKB:
- return "zbb' or `zbkb";
- case INSN_CLASS_ZBC_OR_ZBKC:
- return "zbc' or `zbkc";
- case INSN_CLASS_ZKND:
- return "zknd";
- case INSN_CLASS_ZKNE:
- return "zkne";
- case INSN_CLASS_ZKNH:
- return "zknh";
- case INSN_CLASS_ZKND_OR_ZKNE:
- return "zknd' or `zkne";
- case INSN_CLASS_ZKSED:
- return "zksed";
- case INSN_CLASS_ZKSH:
- return "zksh";
- case INSN_CLASS_V:
- return "v' or `zve64x' or `zve32x";
- case INSN_CLASS_ZVEF:
- return "v' or `zve64d' or `zve64f' or `zve32f";
- case INSN_CLASS_SVINVAL:
- return "svinval";
- default:
- rps->error_handler
- (_("internal: unreachable INSN_CLASS_*"));
- return NULL;
- }
- }
|