JFIFXX    $.' ",#(7),01444'9=82<.342  2!!22222222222222222222222222222222222222222222222222"4 ,PG"Z_4˷kjزZ,F+_z,© zh6٨icfu#ډb_N?wQ5-~I8TK<5oIv-k_U_~bMdӜUHh?]EwQk{_}qFW7HTՑYF?_'ϔ_Ջt=||I 6έ"D/[k9Y8ds|\Ҿp6Ҵ].6znopM[mei$[soᘨ˸ nɜG-ĨUycP3.DBli;hjx7Z^NhN3u{:jx힞#M&jL P@_ P&o89@Sz6t7#Oߋ s}YfTlmrZ)'Nk۞pw\Tȯ?8`Oi{wﭹW[r Q4F׊3m&L=h3z~#\l :F,j@ ʱwQT8"kJO6֚l}R>ډK]y&p}b;N1mr$|7>e@BTM*-iHgD) Em|ؘbҗaҾt4oG*oCNrPQ@z,|?W[0:n,jWiEW$~/hp\?{(0+Y8rΟ+>S-SVN;}s?. w9˟<Mq4Wv'{)01mBVW[8/< %wT^5b)iM pgN&ݝVO~qu9 !J27$O-! :%H ـyΠM=t{!S oK8txA& j0 vF Y|y ~6@c1vOpIg4lODL Rcj_uX63?nkWyf;^*B @~a`Eu+6L.ü>}y}_O6͐:YrGXkGl^w~㒶syIu! W XN7BVO!X2wvGRfT#t/?%8^WaTGcLMI(J1~8?aT ]ASE(*E} 2#I/׍qz^t̔bYz4xt){ OH+(EA&NXTo"XC')}Jzp ~5}^+6wcQ|LpdH}(.|kc4^"Z?ȕ a<L!039C EuCFEwç ;n?*oB8bʝ'#RqfM}7]s2tcS{\icTx;\7KPʇ Z O-~c>"?PEO8@8GQgaՎ󁶠䧘_%#r>1zaebqcPѵn#L =׀t L7`VA{C:ge@w1 Xp3c3ġpM"'-@n4fGB3DJ8[JoߐgK)ƛ$ 83+ 6ʻ SkI*KZlT _`?KQKdB`s}>`*>,*@JdoF*弝O}ks]yߘc1GV<=776qPTtXԀ!9*44Tހ3XΛex46YD  BdemDa\_l,G/֌7Y](xTt^%GE4}bTڹ;Y)BQu>J/J ⮶.XԄjݳ+Ed r5_D1 o Bx΢#<W8R6@gM. drD>(otU@x=~v2 ӣdoBd3eO6㣷ݜ66YQz`S{\P~z m5{J/L1xO\ZFu>ck#&:`$ai>2ΔloF[hlEܺΠk:)` $[69kOw\|8}ބ:񶐕IA1/=2[,!.}gN#ub ~݊}34qdELc$"[qU硬g^%B zrpJru%v\h1Yne`ǥ:gpQM~^Xi `S:V29.PV?Bk AEvw%_9CQwKekPؠ\;Io d{ ߞoc1eP\ `E=@KIRYK2NPlLɀ)&eB+ь( JTx_?EZ }@ 6U뙢طzdWIn` D噥[uV"G&Ú2g}&m?ċ"Om# {ON"SXNeysQ@FnVgdX~nj]J58up~.`r\O,ư0oS _Ml4kv\JSdxSW<AeIX$Iw:Sy›R9Q[,5;@]%u@ *rolbI  +%m:͇ZVủθau,RW33 dJeTYE.Mϧ-oj3+yy^cVO9NV\nd1 !͕_)av;թMlWR1)ElP;yوÏu 3k5Pr6<⒲l!˞*u־n!l:UNW %Chx8vL'X@*)̮ˍ D-M+JUkvK+x8cY?Ԡ~3mo|u@[XeYC\Kpx8oCC&N~3-H MXsu<`~"WL$8ξ3a)|:@m\^`@ҷ)5p+6p%i)P Mngc#0AruzRL+xSS?ʮ}()#tmˇ!0}}y$6Lt;$ʳ{^6{v6ķܰgVcnn ~zx«,2u?cE+ȘH؎%Za)X>uWTzNyosFQƤ$*&LLXL)1" LeOɟ9=:tZcŽY?ӭVwv~,Yrۗ|yGaFC.+ v1fήJ]STBn5sW}y$~z'c 8  ,! pVNSNNqy8z˱A4*'2n<s^ǧ˭PJޮɏUGLJ*#i}K%,)[z21z ?Nin1?TIR#m-1lA`fT5+ܐcq՝ʐ,3f2Uեmab#ŠdQy>\)SLYw#.ʑf ,"+w~N'cO3FN<)j&,- љ֊_zSTǦw>?nU仆Ve0$CdrP m׈eXmVu L.bֹ [Դaզ*\y8Է:Ez\0KqC b̘cөQ=0YsNS.3.Oo:#v7[#߫ 5܎LEr49nCOWlG^0k%;YߝZǓ:S#|}y,/kLd TA(AI$+I3;Y*Z}|ӧOdv..#:nf>>ȶITX 8y"dR|)0=n46ⲑ+ra ~]R̲c?6(q;5% |uj~z8R=XIV=|{vGj\gcqz؋%Mߍ1y#@f^^>N#x#۹6Y~?dfPO{P4Vu1E1J *|%JN`eWuzk M6q t[ gGvWIGu_ft5j"Y:Tɐ*; e54q$C2d} _SL#mYpO.C;cHi#֩%+) ӍƲVSYźg |tj38r|V1#;.SQA[S#`n+$$I P\[@s(EDzP])8G#0B[ىXIIq<9~[Z멜Z⊔IWU&A>P~#dp]9 "cP Md?٥Ifتuk/F9c*9Ǎ:ØFzn*@|Iށ9N3{'['ͬҲ4#}!V Fu,,mTIkv C7vB6kT91*l '~ƞFlU'M ][ΩũJ_{iIn$L jOdxkza۪#EClx˘oVɞljr)/,߬hL#^Lф,íMƁe̩NBLiLq}(q6IçJ$WE$:=#(KBzђ xlx?>Պ+>W,Ly!_DŌlQ![ SJ1ƐY}b,+Loxɓ)=yoh@꥟/Iѭ=Py9 ۍYӘe+pJnϱ?V\SO%(t =?MR[Șd/ nlB7j !;ӥ/[-A>dNsLj ,ɪv=1c.SQO3UƀܽE̻9GϷD7(}Ävӌ\y_0[w <΍>a_[0+LF.޺f>oNTq;y\bՃyjH<|q-eɏ_?_9+PHp$[uxK wMwNی'$Y2=qKBP~Yul:[<F12O5=d]Ysw:ϮEj,_QXz`H1,#II dwrP˂@ZJVy$\y{}^~[:NߌUOdؾe${p>G3cĖlʌ ת[`ϱ-WdgIig2 }s ؤ(%#sS@~3XnRG~\jc3vӍLM[JBTs3}jNʖW;7ç?=XF=-=qߚ#='c7ڑWI(O+=:uxqe2zi+kuGR0&eniT^J~\jyp'dtGsO39* b#Ɋ p[BwsT>d4ۧsnvnU_~,vƜJ1s QIz)(lv8MU=;56Gs#KMP=LvyGd}VwWBF'à ?MHUg2 !p7Qjڴ=ju JnA suMeƆҔ!)'8Ϣٔޝ(Vpצ֖d=ICJǠ{qkԭ߸i@Ku|p=..*+xz[Aqġ#s2aƊRR)*HRsi~a &fMP-KL@ZXy'x{}Zm+:)) IJ-iu ܒH'L(7yGӜq j 6ߌg1go,kرtY?W,pefOQS!K۟cҒA|սj>=⬒˧L[ ߿2JaB~Ru:Q] 0H~]7ƼI(}cq 'ήETq?fabӥvr )o-Q_'ᴎoK;Vo%~OK *bf:-ťIR`B5!RB@ï u ̯e\_U_ gES3QTaxU<~c?*#]MW,[8Oax]1bC|踤Plw5V%){t<d50iXSUm:Z┵i"1^B-PhJ&)O*DcWvM)}Pܗ-q\mmζZ-l@}aE6F@&Sg@ݚM ȹ 4#p\HdYDoH"\..RBHz_/5˘6KhJRPmƶim3,#ccoqa)*PtRmk7xDE\Y閣_X<~)c[[BP6YqS0%_;Àv~| VS؇ 'O0F0\U-d@7SJ*z3nyPOm~P3|Yʉr#CSN@ ƮRN)r"C:: #qbY. 6[2K2uǦHYRQMV G$Q+.>nNHq^ qmMVD+-#*U̒ p욳u:IBmPV@Or[b= 1UE_NmyKbNOU}the`|6֮P>\2PVIDiPO;9rmAHGWS]J*_G+kP2KaZH'KxWMZ%OYDRc+o?qGhmdSoh\D|:WUAQc yTq~^H/#pCZTI1ӏT4"ČZ}`w#*,ʹ 0i課Om*da^gJ݅{le9uF#Tֲ̲ٞC"qߍ ոޑo#XZTp@ o8(jdxw],f`~|,s^f1t|m򸄭/ctr5s79Q4H1꠲BB@l9@C+wpxu£Yc9?`@#omHs2)=2.ljg9$YS%*LRY7Z,*=䷘$armoϰUW.|rufIGwtZwo~5 YյhO+=8fF)W7L9lM̘·Y֘YLf큹pRF99.A "wz=E\Z'a 2Ǚ#;'}G*l^"q+2FQ hjkŦ${ޮ-T٭cf|3#~RJt$b(R(rdx >U b&9,>%E\ Άe$'q't*אެb-|dSBOO$R+H)܎K1m`;J2Y~9Og8=vqD`K[F)k[1m޼cn]skz$@)!I x՝"v9=ZA=`Ɠi :E)`7vI}dYI_ o:obo 3Q&D&2= Ά;>hy.*ⅥSӬ+q&j|UƧ}J0WW< ۋS)jQRjƯrN)Gű4Ѷ(S)Ǣ8iW52No˓ ۍ%5brOnL;n\G=^UdI8$&h'+(cȁ߫klS^cƗjԌEꭔgFȒ@}O*;evWVYJ\]X'5ղkFb 6Ro՜mi Ni>J?lPmU}>_Z&KKqrIDՉ~q3fL:Se>E-G{L6pe,8QIhaXaUA'ʂs+טIjP-y8ۈZ?J$WP Rs]|l(ԓsƊio(S0Y 8T97.WiLc~dxcE|2!XKƘਫ਼$((6~|d9u+qd^389Y6L.I?iIq9)O/뚅OXXVZF[یgQLK1RҖr@v#XlFНyS87kF!AsM^rkpjPDyS$Nqnxҍ!Uf!ehi2m`YI9r6 TFC}/y^Η5d'9A-J>{_l+`A['յϛ#w:݅%X}&PStQ"-\縵/$ƗhXb*yBS;Wջ_mcvt?2}1;qSdd~u:2k52R~z+|HE!)Ǟl7`0<,2*Hl-x^'_TVgZA'j ^2ΪN7t?w x1fIzC-ȖK^q;-WDvT78Z hK(P:Q- 8nZ܃e貾<1YT<,"6{/ ?͟|1:#gW>$dJdB=jf[%rE^il:BxSּ1հ,=*7 fcG#q eh?27,!7x6nLC4x},GeǝtC.vS F43zz\;QYC,6~;RYS/6|25vTimlv& nRh^ejRLGf? ۉҬܦƩ|Ȱ>3!viʯ>vオX3e_1zKȗ\qHS,EW[㺨uch⍸O}a>q6n6N6qN ! 1AQaq0@"2BRb#Pr3C`Scst$4D%Td ?Na3mCwxAmqmm$4n淿t'C"wzU=D\R+wp+YT&պ@ƃ3ޯ?AﶂaŘ@-Q=9Dռѻ@MVP܅G5fY6# ?0UQ,IX(6ڵ[DIMNލc&υj\XR|,4 jThAe^db#$]wOӪ1y%LYm뭛CUƃߜ}Cy1XνmF8jI]HۺиE@Ii;r8ӭVFՇ| &?3|xBMuSGe=Ӕ#BE5GY!z_eqр/W>|-Ci߇t1ޯќdR3ug=0 5[?#͏qcfH{ ?u=??ǯ}ZzhmΔBFTWPxs}G93 )gGR<>r h$'nchPBjJҧH -N1N?~}-q!=_2hcMlvY%UE@|vM2.Y[|y"EïKZF,ɯ?,q?vM 80jx";9vk+ ֧ ȺU?%vcVmA6Qg^MA}3nl QRNl8kkn'(M7m9وq%ޟ*h$Zk"$9: ?U8Sl,,|ɒxH(ѷGn/Q4PG%Ա8N! &7;eKM749R/%lc>x;>C:th?aKXbheᜋ^$Iհ hr7%F$EFdt5+(M6tÜUU|zW=aTsTgdqPQb'm1{|YXNb P~F^F:k6"j! Ir`1&-$Bevk:y#ywI0x=D4tUPZHڠ底taP6b>xaQ# WeFŮNjpJ* mQN*I-*ȩFg3 5Vʊɮa5FO@{NX?H]31Ri_uѕ 0 F~:60p͈SqX#a5>`o&+<2D: ڝ$nP*)N|yEjF5ټeihyZ >kbHavh-#!Po=@k̆IEN@}Ll?jO߭ʞQ|A07xwt!xfI2?Z<ץTcUj]陎Ltl }5ϓ$,Omˊ;@OjEj(ا,LXLOЦ90O .anA7j4 W_ٓzWjcBy՗+EM)dNg6y1_xp$Lv:9"zpʙ$^JԼ*ϭo=xLj6Ju82AH3$ٕ@=Vv]'qEz;I˼)=ɯx /W(Vp$ mu񶤑OqˎTr㠚xsrGCbypG1ߠw e8$⿄/M{*}W]˷.CK\ުx/$WPwr |i&}{X >$-l?-zglΆ(FhvS*b߲ڡn,|)mrH[a3ר[13o_U3TC$(=)0kgP u^=4 WYCҸ:vQרXàtkm,t*^,}D* "(I9R>``[~Q]#afi6l86:,ssN6j"A4IuQ6E,GnHzSHOuk5$I4ؤQ9@CwpBGv[]uOv0I4\yQѸ~>Z8Taqޣ;za/SI:ܫ_|>=Z8:SUIJ"IY8%b8H:QO6;7ISJҌAά3>cE+&jf$eC+z;V rʺmyeaQf&6ND.:NTvm<- uǝ\MvZYNNT-A>jr!SnO 13Ns%3D@`ܟ 1^c< aɽ̲Xë#w|ycW=9I*H8p^(4՗karOcWtO\ƍR8'KIQ?5>[}yUײ -h=% qThG2)"ו3]!kB*pFDlA,eEiHfPs5H:Փ~H0DتDIhF3c2E9H5zԑʚiX=:mxghd(v׊9iSOd@0ڽ:p5h-t&Xqӕ,ie|7A2O%PEhtjY1wЃ!  ࢽMy7\a@ţJ 4ȻF@o̒?4wx)]P~u57X 9^ܩU;Iꭆ 5 eK27({|Y׎ V\"Z1 Z}(Ǝ"1S_vE30>p; ΝD%xW?W?vo^Vidr[/&>~`9Why;R ;;ɮT?r$g1KACcKl:'3 cﳯ*"t8~l)m+U,z`(>yJ?h>]vЍG*{`;y]IT ;cNUfo¾h/$|NS1S"HVT4uhǜ]v;5͠x'C\SBplh}N ABx%ޭl/Twʽ]D=Kžr㻠l4SO?=k M: cCa#ha)ѐxcsgPiG{+xQI= zԫ+ 8"kñj=|c yCF/*9жh{ ?4o kmQNx;Y4膚aw?6>e]Qr:g,i"ԩA*M7qB?ӕFhV25r[7 Y }LR}*sg+xr2U=*'WSZDW]WǞ<叓{$9Ou4y90-1'*D`c^o?(9uݐ'PI& fJݮ:wSjfP1F:X H9dԯ˝[_54 }*;@ܨ ðynT?ןd#4rGͨH1|-#MrS3G3).᧏3vz֑r$G"`j 1tx0<ƆWh6y6,œGagAyb)hDß_mü gG;evݝnQ C-*oyaMI><]obD":GA-\%LT8c)+y76oQ#*{(F⽕y=rW\p۩cA^e6KʐcVf5$'->ՉN"F"UQ@fGb~#&M=8טJNu9D[̤so~ G9TtW^g5y$bY'سǴ=U-2 #MCt(i lj@Q 5̣i*OsxKf}\M{EV{υƇ);HIfeLȣr2>WIȂ6ik 5YOxȺ>Yf5'|H+98pjn.OyjY~iw'l;s2Y:'lgꥴ)o#'SaaKZ m}`169n"xI *+ }FP"l45'ZgE8?[X7(.Q-*ތL@̲v.5[=t\+CNܛ,gSQnH}*FG16&:t4ُ"Ạ$b |#rsaT ]ӽDP7ո0y)e$ٕvIh'QEAm*HRI=: 4牢) %_iNݧl] NtGHL ɱg<1V,J~ٹ"KQ 9HS9?@kr;we݁]I!{ @G["`J:n]{cAEVʆ#U96j#Ym\qe4hB7Cdv\MNgmAyQL4uLjj9#44tl^}LnR!t±]rh6ٍ>yҏNfU  Fm@8}/ujb9he:AyծwGpΧh5l}3p468)Udc;Us/֔YX1O2uqs`hwgr~{ RmhN؎*q 42*th>#E#HvOq}6e\,Wk#Xb>p}դ3T5†6[@Py*n|'f֧>lư΂̺SU'*qp_SM 'c6m ySʨ;MrƋmKxo,GmPAG:iw9}M(^V$ǒѽ9| aJSQarB;}ٻ֢2%Uc#gNaݕ'v[OY'3L3;,p]@S{lsX'cjwk'a.}}& dP*bK=ɍ!;3ngΊUߴmt'*{,=SzfD Ako~Gaoq_mi}#mPXhύmxǍ΂巿zfQc|kc?WY$_Lvl߶c`?ljݲˏ!V6UЂ(A4y)HpZ_x>eR$/`^'3qˏ-&Q=?CFVR DfV9{8gnh(P"6[D< E~0<@`G6Hгcc cK.5DdB`?XQ2ٿyqo&+1^ DW0ꊩG#QnL3c/x 11[yxპCWCcUĨ80me4.{muI=f0QRls9f9~fǨa"@8ȁQ#cicG$Gr/$W(WV"m7[mAmboD j۳ l^kh׽ # iXnveTka^Y4BNĕ0 !01@Q"2AaPq3BR?@4QT3,㺠W[=JKϞ2r^7vc:9 EߴwS#dIxu:Hp9E! V 2;73|F9Y*ʬFDu&y؟^EAA(ɩ^GV:ݜDy`Jr29ܾ㝉[E;FzxYGUeYC v-txIsםĘqEb+P\ :>iC';k|zرny]#ǿbQw(r|ӹs[D2v-%@;8<a[\o[ϧwI!*0krs)[J9^ʜp1) "/_>o<1AEy^C`x1'ܣnps`lfQ):lb>MejH^?kl3(z:1ŠK&?Q~{ٺhy/[V|6}KbXmn[-75q94dmc^h X5G-}دBޟ |rtMV+]c?-#ڛ^ǂ}LkrOu>-Dry D?:ޞUǜ7V?瓮"#rչģVR;n/_ ؉vݶe5db9/O009G5nWJpA*r9>1.[tsFnQ V 77R]ɫ8_0<՜IFu(v4Fk3E)N:yڮeP`1}$WSJSQNjٺ޵#lј(5=5lǏmoWv-1v,Wmn߀$x_DȬ0¤#QR[Vkzmw"9ZG7'[=Qj8R?zf\a=OU*oBA|G254 p.w7  &ξxGHp B%$gtЏ򤵍zHNuЯ-'40;_3 !01"@AQa2Pq#3BR?ʩcaen^8F<7;EA{EÖ1U/#d1an.1ě0ʾRh|RAo3m3 % 28Q yφHTo7lW>#i`qca m,B-j݋'mR1Ήt>Vps0IbIC.1Rea]H64B>o]($Bma!=?B KǾ+Ծ"nK*+[T#{EJSQs5:U\wĐf3܆&)IԆwE TlrTf6Q|Rh:[K zc֧GC%\_a84HcObiؖV7H )*ģK~Xhչ04?0 E<}3#u? |gS6ꊤ|I#Hڛ աwX97Ŀ%SLy6č|Fa 8b$sקhb9RAu7˨pČ_\*w묦F 4D~f|("mNKiS>$d7SlA/²SL|6N}S˯g]6; #. 403WebShell
403Webshell
Server IP : 185.232.14.244  /  Your IP : 216.73.216.56
Web Server : LiteSpeed
System : Linux sg-nme-web1278.main-hosting.eu 4.18.0-553.84.1.lve.el8.x86_64 #1 SMP Tue Nov 25 18:33:03 UTC 2025 x86_64
User : u166342113 ( 166342113)
PHP Version : 8.1.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : OFF  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /opt/imunify360-webshield/luajit/share/luajit-2.1/jit/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /opt/imunify360-webshield/luajit/share/luajit-2.1/jit/dis_arm64.lua
----------------------------------------------------------------------------
-- LuaJIT ARM64 disassembler module.
--
-- Copyright (C) 2005-2023 Mike Pall. All rights reserved.
-- Released under the MIT license. See Copyright Notice in luajit.h
--
-- Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
-- Sponsored by Cisco Systems, Inc.
----------------------------------------------------------------------------
-- This is a helper module used by the LuaJIT machine code dumper module.
--
-- It disassembles most user-mode AArch64 instructions.
-- NYI: Advanced SIMD and VFP instructions.
------------------------------------------------------------------------------

local type = type
local sub, byte, format = string.sub, string.byte, string.format
local match, gmatch, gsub = string.match, string.gmatch, string.gsub
local concat = table.concat
local bit = require("bit")
local band, bor, bxor, tohex = bit.band, bit.bor, bit.bxor, bit.tohex
local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift
local ror = bit.ror

------------------------------------------------------------------------------
-- Opcode maps
------------------------------------------------------------------------------

local map_adr = { -- PC-relative addressing.
  shift = 31, mask = 1,
  [0] = "adrDBx", "adrpDBx"
}

local map_addsubi = { -- Add/subtract immediate.
  shift = 29, mask = 3,
  [0] = "add|movDNIg", "adds|cmnD0NIg", "subDNIg", "subs|cmpD0NIg",
}

local map_logi = { -- Logical immediate.
  shift = 31, mask = 1,
  [0] = {
    shift = 22, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
    },
    false -- unallocated
  },
  {
    shift = 29, mask = 3,
    [0] = "andDNig", "orr|movDN0ig", "eorDNig", "ands|tstD0Nig"
  }
}

local map_movwi = { -- Move wide immediate.
  shift = 31, mask = 1,
  [0] = {
    shift = 22, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
    }, false -- unallocated
  },
  {
    shift = 29, mask = 3,
    [0] = "movnDWRg", false, "movz|movDYRg", "movkDWRg"
  },
}

local map_bitf = { -- Bitfield.
  shift = 31, mask = 1,
  [0] = {
    shift = 22, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12w",
      "bfm|bfi|bfxilDN13w",
      "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12w"
    }
  },
  {
    shift = 22, mask = 1,
    {
      shift = 29, mask = 3,
      [0] = "sbfm|sbfiz|sbfx|asr|sxtw|sxth|sxtbDN12x",
      "bfm|bfi|bfxilDN13x",
      "ubfm|ubfiz|ubfx|lsr|lsl|uxth|uxtbDN12x"
    }
  }
}

local map_datai = { -- Data processing - immediate.
  shift = 23, mask = 7,
  [0] = map_adr, map_adr, map_addsubi, false,
  map_logi, map_movwi, map_bitf,
  {
    shift = 15, mask = 0x1c0c1,
    [0] = "extr|rorDNM4w", [0x10080] = "extr|rorDNM4x",
    [0x10081] = "extr|rorDNM4x"
  }
}

local map_logsr = { -- Logical, shifted register.
  shift = 31, mask = 1,
  [0] = {
    shift = 15, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = {
	shift = 21, mask = 1,
	[0] = "andDNMSg", "bicDNMSg"
      },
      {
	shift = 21, mask = 1,
	[0] = "orr|movDN0MSg", "orn|mvnDN0MSg"
      },
      {
	shift = 21, mask = 1,
	[0] = "eorDNMSg", "eonDNMSg"
      },
      {
	shift = 21, mask = 1,
	[0] = "ands|tstD0NMSg", "bicsDNMSg"
      }
    },
    false -- unallocated
  },
  {
    shift = 29, mask = 3,
    [0] = {
      shift = 21, mask = 1,
      [0] = "andDNMSg", "bicDNMSg"
    },
    {
      shift = 21, mask = 1,
      [0] = "orr|movDN0MSg", "orn|mvnDN0MSg"
    },
    {
      shift = 21, mask = 1,
      [0] = "eorDNMSg", "eonDNMSg"
    },
    {
      shift = 21, mask = 1,
      [0] = "ands|tstD0NMSg", "bicsDNMSg"
    }
  }
}

local map_assh = {
  shift = 31, mask = 1,
  [0] = {
    shift = 15, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = {
	shift = 22, mask = 3,
	[0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
      },
      {
	shift = 22, mask = 3,
	[0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg",
	      "adds|cmnD0NMSg", "adds|cmnD0NMg"
      },
      {
	shift = 22, mask = 3,
	[0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
      },
      {
	shift = 22, mask = 3,
	[0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
	      "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
      },
    },
    false -- unallocated
  },
  {
    shift = 29, mask = 3,
    [0] = {
      shift = 22, mask = 3,
      [0] = "addDNMSg", "addDNMSg", "addDNMSg", "addDNMg"
    },
    {
      shift = 22, mask = 3,
      [0] = "adds|cmnD0NMSg", "adds|cmnD0NMSg", "adds|cmnD0NMSg",
	    "adds|cmnD0NMg"
    },
    {
      shift = 22, mask = 3,
      [0] = "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0MSg", "sub|negDN0Mg"
    },
    {
      shift = 22, mask = 3,
      [0] = "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0MzSg",
	    "subs|cmp|negsD0N0MzSg", "subs|cmp|negsD0N0Mzg"
    }
  }
}

local map_addsubsh = { -- Add/subtract, shifted register.
  shift = 22, mask = 3,
  [0] = map_assh, map_assh, map_assh
}

local map_addsubex = { -- Add/subtract, extended register.
  shift = 22, mask = 3,
  [0] = {
    shift = 29, mask = 3,
    [0] = "addDNMXg", "adds|cmnD0NMXg", "subDNMXg", "subs|cmpD0NMzXg",
  }
}

local map_addsubc = { -- Add/subtract, with carry.
  shift = 10, mask = 63,
  [0] = {
    shift = 29, mask = 3,
    [0] = "adcDNMg", "adcsDNMg", "sbc|ngcDN0Mg", "sbcs|ngcsDN0Mg",
  }
}

local map_ccomp = {
  shift = 4, mask = 1,
  [0] = {
    shift = 10, mask = 3,
    [0] = { -- Conditional compare register.
      shift = 29, mask = 3,
      "ccmnNMVCg", false, "ccmpNMVCg",
    },
    [2] = {  -- Conditional compare immediate.
      shift = 29, mask = 3,
      "ccmnN5VCg", false, "ccmpN5VCg",
    }
  }
}

local map_csel = { -- Conditional select.
  shift = 11, mask = 1,
  [0] = {
    shift = 10, mask = 1,
    [0] = {
      shift = 29, mask = 3,
      [0] = "cselDNMzCg", false, "csinv|cinv|csetmDNMcg", false,
    },
    {
      shift = 29, mask = 3,
      [0] = "csinc|cinc|csetDNMcg", false, "csneg|cnegDNMcg", false,
    }
  }
}

local map_data1s = { -- Data processing, 1 source.
  shift = 29, mask = 1,
  [0] = {
    shift = 31, mask = 1,
    [0] = {
      shift = 10, mask = 0x7ff,
      [0] = "rbitDNg", "rev16DNg", "revDNw", false, "clzDNg", "clsDNg"
    },
    {
      shift = 10, mask = 0x7ff,
      [0] = "rbitDNg", "rev16DNg", "rev32DNx", "revDNx", "clzDNg", "clsDNg"
    }
  }
}

local map_data2s = { -- Data processing, 2 sources.
  shift = 29, mask = 1,
  [0] = {
    shift = 10, mask = 63,
    false, "udivDNMg", "sdivDNMg", false, false, false, false, "lslDNMg",
    "lsrDNMg", "asrDNMg", "rorDNMg"
  }
}

local map_data3s = { -- Data processing, 3 sources.
  shift = 29, mask = 7,
  [0] = {
    shift = 21, mask = 7,
    [0] = {
      shift = 15, mask = 1,
      [0] = "madd|mulDNMA0g", "msub|mnegDNMA0g"
    }
  }, false, false, false,
  {
    shift = 15, mask = 1,
    [0] = {
      shift = 21, mask = 7,
      [0] = "madd|mulDNMA0g", "smaddl|smullDxNMwA0x", "smulhDNMx", false,
      false, "umaddl|umullDxNMwA0x", "umulhDNMx"
    },
    {
      shift = 21, mask = 7,
      [0] = "msub|mnegDNMA0g", "smsubl|smneglDxNMwA0x", false, false,
      false, "umsubl|umneglDxNMwA0x"
    }
  }
}

local map_datar = { -- Data processing, register.
  shift = 28, mask = 1,
  [0] = {
    shift = 24, mask = 1,
    [0] = map_logsr,
    {
      shift = 21, mask = 1,
      [0] = map_addsubsh, map_addsubex
    }
  },
  {
    shift = 21, mask = 15,
    [0] = map_addsubc, false, map_ccomp, false, map_csel, false,
    {
      shift = 30, mask = 1,
      [0] = map_data2s, map_data1s
    },
    false, map_data3s, map_data3s, map_data3s, map_data3s, map_data3s,
    map_data3s, map_data3s, map_data3s
  }
}

local map_lrl = { -- Load register, literal.
  shift = 26, mask = 1,
  [0] = {
    shift = 30, mask = 3,
    [0] = "ldrDwB", "ldrDxB", "ldrswDxB"
  },
  {
    shift = 30, mask = 3,
    [0] = "ldrDsB", "ldrDdB"
  }
}

local map_lsriind = { -- Load/store register, immediate pre/post-indexed.
  shift = 30, mask = 3,
  [0] = {
    shift = 26, mask = 1,
    [0] = {
      shift = 22, mask = 3,
      [0] = "strbDwzL", "ldrbDwzL", "ldrsbDxzL", "ldrsbDwzL"
    }
  },
  {
    shift = 26, mask = 1,
    [0] = {
      shift = 22, mask = 3,
      [0] = "strhDwzL", "ldrhDwzL", "ldrshDxzL", "ldrshDwzL"
    }
  },
  {
    shift = 26, mask = 1,
    [0] = {
      shift = 22, mask = 3,
      [0] = "strDwzL", "ldrDwzL", "ldrswDxzL"
    },
    {
      shift = 22, mask = 3,
      [0] = "strDszL", "ldrDszL"
    }
  },
  {
    shift = 26, mask = 1,
    [0] = {
      shift = 22, mask = 3,
      [0] = "strDxzL", "ldrDxzL"
    },
    {
      shift = 22, mask = 3,
      [0] = "strDdzL", "ldrDdzL"
    }
  }
}

local map_lsriro = {
  shift = 21, mask = 1,
  [0] = {  -- Load/store register immediate.
    shift = 10, mask = 3,
    [0] = { -- Unscaled immediate.
      shift = 26, mask = 1,
      [0] = {
	shift = 30, mask = 3,
	[0] = {
	  shift = 22, mask = 3,
	  [0] = "sturbDwK", "ldurbDwK"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "sturhDwK", "ldurhDwK"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "sturDwK", "ldurDwK"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "sturDxK", "ldurDxK"
	}
      }
    }, map_lsriind, false, map_lsriind
  },
  {  -- Load/store register, register offset.
    shift = 10, mask = 3,
    [2] = {
      shift = 26, mask = 1,
      [0] = {
	shift = 30, mask = 3,
	[0] = {
	  shift = 22, mask = 3,
	  [0] = "strbDwO", "ldrbDwO", "ldrsbDxO", "ldrsbDwO"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "strhDwO", "ldrhDwO", "ldrshDxO", "ldrshDwO"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "strDwO", "ldrDwO", "ldrswDxO"
	},
	{
	  shift = 22, mask = 3,
	  [0] = "strDxO", "ldrDxO"
	}
      },
      {
	shift = 30, mask = 3,
	[2] = {
	  shift = 22, mask = 3,
	  [0] = "strDsO", "ldrDsO"
	},
	[3] = {
	  shift = 22, mask = 3,
	  [0] = "strDdO", "ldrDdO"
	}
      }
    }
  }
}

local map_lsp = { -- Load/store register pair, offset.
  shift = 22, mask = 1,
  [0] = {
    shift = 30, mask = 3,
    [0] = {
      shift = 26, mask = 1,
      [0] = "stpDzAzwP", "stpDzAzsP",
    },
    {
      shift = 26, mask = 1,
      "stpDzAzdP"
    },
    {
      shift = 26, mask = 1,
      [0] = "stpDzAzxP"
    }
  },
  {
    shift = 30, mask = 3,
    [0] = {
      shift = 26, mask = 1,
      [0] = "ldpDzAzwP", "ldpDzAzsP",
    },
    {
      shift = 26, mask = 1,
      [0] = "ldpswDAxP", "ldpDzAzdP"
    },
    {
      shift = 26, mask = 1,
      [0] = "ldpDzAzxP"
    }
  }
}

local map_ls = { -- Loads and stores.
  shift = 24, mask = 0x31,
  [0x10] = map_lrl, [0x30] = map_lsriro,
  [0x20] = {
    shift = 23, mask = 3,
    map_lsp, map_lsp, map_lsp
  },
  [0x21] = {
    shift = 23, mask = 3,
    map_lsp, map_lsp, map_lsp
  },
  [0x31] = {
    shift = 26, mask = 1,
    [0] = {
      shift = 30, mask = 3,
      [0] = {
	shift = 22, mask = 3,
	[0] = "strbDwzU", "ldrbDwzU"
      },
      {
	shift = 22, mask = 3,
	[0] = "strhDwzU", "ldrhDwzU"
      },
      {
	shift = 22, mask = 3,
	[0] = "strDwzU", "ldrDwzU"
      },
      {
	shift = 22, mask = 3,
	[0] = "strDxzU", "ldrDxzU"
      }
    },
    {
      shift = 30, mask = 3,
      [2] = {
	shift = 22, mask = 3,
	[0] = "strDszU", "ldrDszU"
      },
      [3] = {
	shift = 22, mask = 3,
	[0] = "strDdzU", "ldrDdzU"
      }
    }
  },
}

local map_datafp = { -- Data processing, SIMD and FP.
  shift = 28, mask = 7,
  { -- 001
    shift = 24, mask = 1,
    [0] = {
      shift = 21, mask = 1,
      {
	shift = 10, mask = 3,
	[0] = {
	  shift = 12, mask = 1,
	  [0] = {
	    shift = 13, mask = 1,
	    [0] = {
	      shift = 14, mask = 1,
	      [0] = {
		shift = 15, mask = 1,
		[0] = { -- FP/int conversion.
		  shift = 31, mask = 1,
		  [0] = {
		    shift = 16, mask = 0xff,
		    [0x20] = "fcvtnsDwNs", [0x21] = "fcvtnuDwNs",
		    [0x22] = "scvtfDsNw", [0x23] = "ucvtfDsNw",
		    [0x24] = "fcvtasDwNs", [0x25] = "fcvtauDwNs",
		    [0x26] = "fmovDwNs", [0x27] = "fmovDsNw",
		    [0x28] = "fcvtpsDwNs", [0x29] = "fcvtpuDwNs",
		    [0x30] = "fcvtmsDwNs", [0x31] = "fcvtmuDwNs",
		    [0x38] = "fcvtzsDwNs", [0x39] = "fcvtzuDwNs",
		    [0x60] = "fcvtnsDwNd", [0x61] = "fcvtnuDwNd",
		    [0x62] = "scvtfDdNw", [0x63] = "ucvtfDdNw",
		    [0x64] = "fcvtasDwNd", [0x65] = "fcvtauDwNd",
		    [0x68] = "fcvtpsDwNd", [0x69] = "fcvtpuDwNd",
		    [0x70] = "fcvtmsDwNd", [0x71] = "fcvtmuDwNd",
		    [0x78] = "fcvtzsDwNd", [0x79] = "fcvtzuDwNd"
		  },
		  {
		    shift = 16, mask = 0xff,
		    [0x20] = "fcvtnsDxNs", [0x21] = "fcvtnuDxNs",
		    [0x22] = "scvtfDsNx", [0x23] = "ucvtfDsNx",
		    [0x24] = "fcvtasDxNs", [0x25] = "fcvtauDxNs",
		    [0x28] = "fcvtpsDxNs", [0x29] = "fcvtpuDxNs",
		    [0x30] = "fcvtmsDxNs", [0x31] = "fcvtmuDxNs",
		    [0x38] = "fcvtzsDxNs", [0x39] = "fcvtzuDxNs",
		    [0x60] = "fcvtnsDxNd", [0x61] = "fcvtnuDxNd",
		    [0x62] = "scvtfDdNx", [0x63] = "ucvtfDdNx",
		    [0x64] = "fcvtasDxNd", [0x65] = "fcvtauDxNd",
		    [0x66] = "fmovDxNd", [0x67] = "fmovDdNx",
		    [0x68] = "fcvtpsDxNd", [0x69] = "fcvtpuDxNd",
		    [0x70] = "fcvtmsDxNd", [0x71] = "fcvtmuDxNd",
		    [0x78] = "fcvtzsDxNd", [0x79] = "fcvtzuDxNd"
		  }
		}
	      },
	      { -- FP data-processing, 1 source.
		shift = 31, mask = 1,
		[0] = {
		  shift = 22, mask = 3,
		  [0] = {
		    shift = 15, mask = 63,
		    [0] = "fmovDNf", "fabsDNf", "fnegDNf",
		    "fsqrtDNf", false, "fcvtDdNs", false, false,
		    "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
		    "frintaDNf", false, "frintxDNf", "frintiDNf",
		  },
		  {
		    shift = 15, mask = 63,
		    [0] = "fmovDNf", "fabsDNf", "fnegDNf",
		    "fsqrtDNf", "fcvtDsNd", false, false, false,
		    "frintnDNf", "frintpDNf", "frintmDNf", "frintzDNf",
		    "frintaDNf", false, "frintxDNf", "frintiDNf",
		  }
		}
	      }
	    },
	    { -- FP compare.
	      shift = 31, mask = 1,
	      [0] = {
		shift = 14, mask = 3,
		[0] = {
		  shift = 23, mask = 1,
		  [0] = {
		    shift = 0, mask = 31,
		    [0] = "fcmpNMf", [8] = "fcmpNZf",
		    [16] = "fcmpeNMf", [24] = "fcmpeNZf",
		  }
		}
	      }
	    }
	  },
	  { -- FP immediate.
	    shift = 31, mask = 1,
	    [0] = {
	      shift = 5, mask = 31,
	      [0] = {
		shift = 23, mask = 1,
		[0] = "fmovDFf"
	      }
	    }
	  }
	},
	{ -- FP conditional compare.
	  shift = 31, mask = 1,
	  [0] = {
	    shift = 23, mask = 1,
	    [0] = {
	      shift = 4, mask = 1,
	      [0] = "fccmpNMVCf", "fccmpeNMVCf"
	    }
	  }
	},
	{ -- FP data-processing, 2 sources.
	  shift = 31, mask = 1,
	  [0] = {
	    shift = 23, mask = 1,
	    [0] = {
	      shift = 12, mask = 15,
	      [0] = "fmulDNMf", "fdivDNMf", "faddDNMf", "fsubDNMf",
	      "fmaxDNMf", "fminDNMf", "fmaxnmDNMf", "fminnmDNMf",
	      "fnmulDNMf"
	    }
	  }
	},
	{ -- FP conditional select.
	  shift = 31, mask = 1,
	  [0] = {
	    shift = 23, mask = 1,
	    [0] = "fcselDNMCf"
	  }
	}
      }
    },
    { -- FP data-processing, 3 sources.
      shift = 31, mask = 1,
      [0] = {
	shift = 15, mask = 1,
	[0] = {
	  shift = 21, mask = 5,
	  [0] = "fmaddDNMAf", "fnmaddDNMAf"
	},
	{
	  shift = 21, mask = 5,
	  [0] = "fmsubDNMAf", "fnmsubDNMAf"
	}
      }
    }
  },
  { -- 010
    shift = 0, mask = 0x81f8fc00,
    [0x100e400] = "moviDdG"
  }
}

local map_br = { -- Branches, exception generating and system instructions.
  shift = 29, mask = 7,
  [0] = "bB",
  { -- Compare & branch, immediate.
    shift = 24, mask = 3,
    [0] = "cbzDBg", "cbnzDBg", "tbzDTBw", "tbnzDTBw"
  },
  { -- Conditional branch, immediate.
    shift = 24, mask = 3,
    [0] = {
      shift = 4, mask = 1,
      [0] = {
	shift = 0, mask = 15,
	[0] = "beqB", "bneB", "bhsB", "bloB", "bmiB", "bplB", "bvsB", "bvcB",
	"bhiB", "blsB", "bgeB", "bltB", "bgtB", "bleB", "balB"
      }
    }
  }, false, "blB",
  { -- Compare & branch, immediate.
    shift = 24, mask = 3,
    [0] = "cbzDBg", "cbnzDBg", "tbzDTBx", "tbnzDTBx"
  },
  {
    shift = 24, mask = 3,
    [0] = { -- Exception generation.
      shift = 0, mask = 0xe0001f,
      [0x200000] = "brkW"
    },
    { -- System instructions.
      shift = 0, mask = 0x3fffff,
      [0x03201f] = "nop"
    },
    { -- Unconditional branch, register.
      shift = 0, mask = 0xfffc1f,
      [0x1f0000] = "brNx", [0x3f0000] = "blrNx",
      [0x5f0000] = "retNx"
    },
  }
}

local map_init = {
  shift = 25, mask = 15,
  [0] = false, false, false, false, map_ls, map_datar, map_ls, map_datafp,
  map_datai, map_datai, map_br, map_br, map_ls, map_datar, map_ls, map_datafp
}

------------------------------------------------------------------------------

local map_regs = { x = {}, w = {}, d = {}, s = {} }

for i=0,30 do
  map_regs.x[i] = "x"..i
  map_regs.w[i] = "w"..i
  map_regs.d[i] = "d"..i
  map_regs.s[i] = "s"..i
end
map_regs.x[31] = "sp"
map_regs.w[31] = "wsp"
map_regs.d[31] = "d31"
map_regs.s[31] = "s31"

local map_cond = {
  [0] = "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
  "hi", "ls", "ge", "lt", "gt", "le", "al",
}

local map_shift = { [0] = "lsl", "lsr", "asr", "ror"}

local map_extend = {
  [0] = "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx",
}

------------------------------------------------------------------------------

-- Output a nicely formatted line with an opcode and operands.
local function putop(ctx, text, operands)
  local pos = ctx.pos
  local extra = ""
  if ctx.rel then
    local sym = ctx.symtab[ctx.rel]
    if sym then
      extra = "\t->"..sym
    end
  end
  if ctx.hexdump > 0 then
    ctx.out(format("%08x  %s  %-5s %s%s\n",
      ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra))
  else
    ctx.out(format("%08x  %-5s %s%s\n",
      ctx.addr+pos, text, concat(operands, ", "), extra))
  end
  ctx.pos = pos + 4
end

-- Fallback for unknown opcodes.
local function unknown(ctx)
  return putop(ctx, ".long", { "0x"..tohex(ctx.op) })
end

local function match_reg(p, pat, regnum)
  return map_regs[match(pat, p.."%w-([xwds])")][regnum]
end

local function fmt_hex32(x)
  if x < 0 then
    return tohex(x)
  else
    return format("%x", x)
  end
end

local imm13_rep = { 0x55555555, 0x11111111, 0x01010101, 0x00010001, 0x00000001 }

local function decode_imm13(op)
  local imms = band(rshift(op, 10), 63)
  local immr = band(rshift(op, 16), 63)
  if band(op, 0x00400000) == 0 then
    local len = 5
    if imms >= 56 then
      if imms >= 60 then len = 1 else len = 2 end
    elseif imms >= 48 then len = 3 elseif imms >= 32 then len = 4 end
    local l = lshift(1, len)-1
    local s = band(imms, l)
    local r = band(immr, l)
    local imm = ror(rshift(-1, 31-s), r)
    if len ~= 5 then imm = band(imm, lshift(1, l)-1) + rshift(imm, 31-l) end
    imm = imm * imm13_rep[len]
    local ix = fmt_hex32(imm)
    if rshift(op, 31) ~= 0 then
      return ix..tohex(imm)
    else
      return ix
    end
  else
    local lo, hi = -1, 0
    if imms < 32 then lo = rshift(-1, 31-imms) else hi = rshift(-1, 63-imms) end
    if immr ~= 0 then
      lo, hi = ror(lo, immr), ror(hi, immr)
      local x = immr == 32 and 0 or band(bxor(lo, hi), lshift(-1, 32-immr))
      lo, hi = bxor(lo, x), bxor(hi, x)
      if immr >= 32 then lo, hi = hi, lo end
    end
    if hi ~= 0 then
      return fmt_hex32(hi)..tohex(lo)
    else
      return fmt_hex32(lo)
    end
  end
end

local function parse_immpc(op, name)
  if name == "b" or name == "bl" then
    return arshift(lshift(op, 6), 4)
  elseif name == "adr" or name == "adrp" then
    local immlo = band(rshift(op, 29), 3)
    local immhi = lshift(arshift(lshift(op, 8), 13), 2)
    return bor(immhi, immlo)
  elseif name == "tbz" or name == "tbnz" then
    return lshift(arshift(lshift(op, 13), 18), 2)
  else
    return lshift(arshift(lshift(op, 8), 13), 2)
  end
end

local function parse_fpimm8(op)
  local sign = band(op, 0x100000) == 0 and 1 or -1
  local exp = bxor(rshift(arshift(lshift(op, 12), 5), 24), 0x80) - 131
  local frac = 16+band(rshift(op, 13), 15)
  return sign * frac * 2^exp
end

local function decode_fpmovi(op)
  local lo = rshift(op, 5)
  local hi = rshift(op, 9)
  lo = bor(band(lo, 1) * 0xff, band(lo, 2) * 0x7f80, band(lo, 4) * 0x3fc000,
	   band(lo, 8) * 0x1fe00000)
  hi = bor(band(hi, 1) * 0xff, band(hi, 0x80) * 0x1fe,
	   band(hi, 0x100) * 0xff00, band(hi, 0x200) * 0x7f8000)
  if hi ~= 0 then
    return fmt_hex32(hi)..tohex(lo)
  else
    return fmt_hex32(lo)
  end
end

local function prefer_bfx(sf, uns, imms, immr)
  if imms < immr or imms == 31 or imms == 63 then
    return false
  end
  if immr == 0 then
    if sf == 0 and (imms == 7 or imms == 15) then
      return false
    end
    if sf ~= 0 and uns == 0 and (imms == 7 or imms == 15 or imms == 31) then
      return false
    end
  end
  return true
end

-- Disassemble a single instruction.
local function disass_ins(ctx)
  local pos = ctx.pos
  local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4)
  local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0)
  local operands = {}
  local suffix = ""
  local last, name, pat
  local map_reg
  ctx.op = op
  ctx.rel = nil
  last = nil
  local opat
  opat = map_init[band(rshift(op, 25), 15)]
  while type(opat) ~= "string" do
    if not opat then return unknown(ctx) end
    opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._
  end
  name, pat = match(opat, "^([a-z0-9]*)(.*)")
  local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)")
  if altname then pat = pat2 end
  if sub(pat, 1, 1) == "." then
    local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)")
    suffix = suffix..s2
    pat = p2
  end

  local rt = match(pat, "[gf]")
  if rt then
    if rt == "g" then
      map_reg = band(op, 0x80000000) ~= 0 and map_regs.x or map_regs.w
    else
      map_reg = band(op, 0x400000) ~= 0 and map_regs.d or map_regs.s
    end
  end

  local second0, immr

  for p in gmatch(pat, ".") do
    local x = nil
    if p == "D" then
      local regnum = band(op, 31)
      x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
    elseif p == "N" then
      local regnum = band(rshift(op, 5), 31)
      x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
    elseif p == "M" then
      local regnum = band(rshift(op, 16), 31)
      x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
    elseif p == "A" then
      local regnum = band(rshift(op, 10), 31)
      x = rt and map_reg[regnum] or match_reg(p, pat, regnum)
    elseif p == "B" then
      local addr = ctx.addr + pos + parse_immpc(op, name)
      ctx.rel = addr
      x = "0x"..tohex(addr)
    elseif p == "T" then
      x = bor(band(rshift(op, 26), 32), band(rshift(op, 19), 31))
    elseif p == "V" then
      x = band(op, 15)
    elseif p == "C" then
      x = map_cond[band(rshift(op, 12), 15)]
    elseif p == "c" then
      local rn = band(rshift(op, 5), 31)
      local rm = band(rshift(op, 16), 31)
      local cond = band(rshift(op, 12), 15)
      local invc = bxor(cond, 1)
      x = map_cond[cond]
      if altname and cond ~= 14 and cond ~= 15 then
	local a1, a2 = match(altname, "([^|]*)|(.*)")
	if rn == rm then
	  local n = #operands
	  operands[n] = nil
	  x = map_cond[invc]
	  if rn ~= 31 then
	    if a1 then name = a1 else name = altname end
	  else
	    operands[n-1] = nil
	    name = a2
	  end
	end
      end
    elseif p == "W" then
      x = band(rshift(op, 5), 0xffff)
    elseif p == "Y" then
      x = band(rshift(op, 5), 0xffff)
      local hw = band(rshift(op, 21), 3)
      if altname and (hw == 0 or x ~= 0) then
	name = altname
      end
    elseif p == "L" then
      local rn = map_regs.x[band(rshift(op, 5), 31)]
      local imm9 = arshift(lshift(op, 11), 23)
      if band(op, 0x800) ~= 0 then
	x = "["..rn..", #"..imm9.."]!"
      else
	x = "["..rn.."], #"..imm9
      end
    elseif p == "U" then
      local rn = map_regs.x[band(rshift(op, 5), 31)]
      local sz = band(rshift(op, 30), 3)
      local imm12 = lshift(rshift(lshift(op, 10), 20), sz)
      if imm12 ~= 0 then
	x = "["..rn..", #"..imm12.."]"
      else
	x = "["..rn.."]"
      end
    elseif p == "K" then
      local rn = map_regs.x[band(rshift(op, 5), 31)]
      local imm9 = arshift(lshift(op, 11), 23)
      if imm9 ~= 0 then
	x = "["..rn..", #"..imm9.."]"
      else
	x = "["..rn.."]"
      end
    elseif p == "O" then
      local rn, rm = map_regs.x[band(rshift(op, 5), 31)]
      local m = band(rshift(op, 13), 1)
      if m == 0 then
	rm = map_regs.w[band(rshift(op, 16), 31)]
      else
	rm = map_regs.x[band(rshift(op, 16), 31)]
      end
      x = "["..rn..", "..rm
      local opt = band(rshift(op, 13), 7)
      local s = band(rshift(op, 12), 1)
      local sz = band(rshift(op, 30), 3)
      -- extension to be applied
      if opt == 3 then
       if s == 0 then x = x.."]"
       else x = x..", lsl #"..sz.."]" end
      elseif opt == 2 or opt == 6 or opt == 7 then
	if s == 0 then x = x..", "..map_extend[opt].."]"
	else x = x..", "..map_extend[opt].." #"..sz.."]" end
      else
	x = x.."]"
      end
    elseif p == "P" then
      local sh = 2 + rshift(op, 31 - band(rshift(op, 26), 1))
      local imm7 = lshift(arshift(lshift(op, 10), 25), sh)
      local rn = map_regs.x[band(rshift(op, 5), 31)]
      local ind = band(rshift(op, 23), 3)
      if ind == 1 then
	x = "["..rn.."], #"..imm7
      elseif ind == 2 then
	if imm7 == 0 then
	  x = "["..rn.."]"
	else
	  x = "["..rn..", #"..imm7.."]"
	end
      elseif ind == 3 then
	x = "["..rn..", #"..imm7.."]!"
      end
    elseif p == "I" then
      local shf = band(rshift(op, 22), 3)
      local imm12 = band(rshift(op, 10), 0x0fff)
      local rn, rd = band(rshift(op, 5), 31), band(op, 31)
      if altname == "mov" and shf == 0 and imm12 == 0 and (rn == 31 or rd == 31) then
	name = altname
	x = nil
      elseif shf == 0 then
	x = imm12
      elseif shf == 1 then
	x = imm12..", lsl #12"
      end
    elseif p == "i" then
      x = "#0x"..decode_imm13(op)
    elseif p == "1" then
      immr = band(rshift(op, 16), 63)
      x = immr
    elseif p == "2" then
      x = band(rshift(op, 10), 63)
      if altname then
	local a1, a2, a3, a4, a5, a6 =
	  match(altname, "([^|]*)|([^|]*)|([^|]*)|([^|]*)|([^|]*)|(.*)")
	local sf = band(rshift(op, 26), 32)
	local uns = band(rshift(op, 30), 1)
	if prefer_bfx(sf, uns, x, immr) then
	  name = a2
	  x = x - immr + 1
	elseif immr == 0 and x == 7 then
	  local n = #operands
	  operands[n] = nil
	  if sf ~= 0 then
	    operands[n-1] = gsub(operands[n-1], "x", "w")
	  end
	  last = operands[n-1]
	  name = a6
	  x = nil
	elseif immr == 0 and x == 15 then
	  local n = #operands
	  operands[n] = nil
	  if sf ~= 0 then
	    operands[n-1] = gsub(operands[n-1], "x", "w")
	  end
	  last = operands[n-1]
	  name = a5
	  x = nil
	elseif x == 31 or x == 63 then
	  if x == 31 and immr == 0 and name == "sbfm" then
	    name = a4
	    local n = #operands
	    operands[n] = nil
	    if sf ~= 0 then
	      operands[n-1] = gsub(operands[n-1], "x", "w")
	    end
	    last = operands[n-1]
	  else
	    name = a3
	  end
	  x = nil
	elseif band(x, 31) ~= 31 and immr == x+1 and name == "ubfm" then
	  name = a4
	  last = "#"..(sf+32 - immr)
	  operands[#operands] = last
	  x = nil
	elseif x < immr then
	  name = a1
	  last = "#"..(sf+32 - immr)
	  operands[#operands] = last
	  x = x + 1
	end
      end
    elseif p == "3" then
      x = band(rshift(op, 10), 63)
      if altname then
	local a1, a2 = match(altname, "([^|]*)|(.*)")
	if x < immr then
	  name = a1
	  local sf = band(rshift(op, 26), 32)
	  last = "#"..(sf+32 - immr)
	  operands[#operands] = last
	  x = x + 1
	else
	  name = a2
	  x = x - immr + 1
	end
      end
    elseif p == "4" then
      x = band(rshift(op, 10), 63)
      local rn = band(rshift(op, 5), 31)
      local rm = band(rshift(op, 16), 31)
      if altname and rn == rm then
	local n = #operands
	operands[n] = nil
	last = operands[n-1]
	name = altname
      end
    elseif p == "5" then
      x = band(rshift(op, 16), 31)
    elseif p == "S" then
      x = band(rshift(op, 10), 63)
      if x == 0 then x = nil
      else x = map_shift[band(rshift(op, 22), 3)].." #"..x end
    elseif p == "X" then
      local opt = band(rshift(op, 13), 7)
      -- Width specifier <R>.
      if opt ~= 3 and opt ~= 7 then
	last = map_regs.w[band(rshift(op, 16), 31)]
	operands[#operands] = last
      end
      x = band(rshift(op, 10), 7)
      -- Extension.
      if opt == 2 + band(rshift(op, 31), 1) and
	 band(rshift(op, second0 and 5 or 0), 31) == 31 then
	if x == 0 then x = nil
	else x = "lsl #"..x end
      else
	if x == 0 then x = map_extend[band(rshift(op, 13), 7)]
	else x = map_extend[band(rshift(op, 13), 7)].." #"..x end
      end
    elseif p == "R" then
      x = band(rshift(op,21), 3)
      if x == 0 then x = nil
      else x = "lsl #"..x*16 end
    elseif p == "z" then
      local n = #operands
      if operands[n] == "sp" then operands[n] = "xzr"
      elseif operands[n] == "wsp" then operands[n] = "wzr"
      end
    elseif p == "Z" then
      x = 0
    elseif p == "F" then
      x = parse_fpimm8(op)
    elseif p == "G" then
      x = "#0x"..decode_fpmovi(op)
    elseif p == "g" or p == "f" or p == "x" or p == "w" or
	   p == "d" or p == "s" then
      -- These are handled in D/N/M/A.
    elseif p == "0" then
      if last == "sp" or last == "wsp" then
	local n = #operands
	operands[n] = nil
	last = operands[n-1]
	if altname then
	  local a1, a2 = match(altname, "([^|]*)|(.*)")
	  if not a1 then
	    name = altname
	  elseif second0 then
	    name, altname = a2, a1
	  else
	    name, altname = a1, a2
	  end
	end
      end
      second0 = true
    else
      assert(false)
    end
    if x then
      last = x
      if type(x) == "number" then x = "#"..x end
      operands[#operands+1] = x
    end
  end

  return putop(ctx, name..suffix, operands)
end

------------------------------------------------------------------------------

-- Disassemble a block of code.
local function disass_block(ctx, ofs, len)
  if not ofs then ofs = 0 end
  local stop = len and ofs+len or #ctx.code
  ctx.pos = ofs
  ctx.rel = nil
  while ctx.pos < stop do disass_ins(ctx) end
end

-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len).
local function create(code, addr, out)
  local ctx = {}
  ctx.code = code
  ctx.addr = addr or 0
  ctx.out = out or io.write
  ctx.symtab = {}
  ctx.disass = disass_block
  ctx.hexdump = 8
  return ctx
end

-- Simple API: disassemble code (a string) at address and output via out.
local function disass(code, addr, out)
  create(code, addr, out):disass()
end

-- Return register name for RID.
local function regname(r)
  if r < 32 then return map_regs.x[r] end
  return map_regs.d[r-32]
end

-- Public module functions.
return {
  create = create,
  disass = disass,
  regname = regname
}


Youez - 2016 - github.com/yon3zu
LinuXploit