Implementing indirect load.
[dyninst.git] / dyninstAPI / src / codegen-aarch64.C
1 /*
2  * See the dyninst/COPYRIGHT file for copyright information.
3  *
4  * We provide the Paradyn Tools (below described as "Paradyn")
5  * on an AS IS basis, and do not warrant its validity or performance.
6  * We reserve the right to update, modify, or discontinue this
7  * software at any time.  We shall have no obligation to supply such
8  * updates or modifications or any other form of support to you.
9  *
10  * By your use of Paradyn, you understand and agree that we (or any
11  * other person or entity with proprietary rights in Paradyn) are
12  * under no obligation to provide either maintenance services,
13  * update services, notices of latent defects, or correction of
14  * defects for Paradyn.
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29  */
30
31 #include <stdlib.h>
32 #include "dyninstAPI/src/codegen.h"
33 #include "dyninstAPI/src/debug.h"
34 #include "dyninstAPI/src/instPoint.h"
35 #include "dyninstAPI/src/registerSpace.h"
36 #include "dyninstAPI/src/addressSpace.h"
37 #include "dyninstAPI/src/inst-aarch64.h"
38 #include "dyninstAPI/src/emit-aarch64.h"
39 #include "dyninstAPI/src/function.h"
40
41 #if defined(os_vxworks)
42 #include "common/src/wtxKludges.h"
43 #endif
44
45
46 // "Casting" methods. We use a "base + offset" model, but often need to
47 // turn that into "current instruction pointer".
48 codeBuf_t *insnCodeGen::insnPtr(codeGen &gen) {
49     return (instructUnion *)gen.cur_ptr();
50 }
51
52 #if 0
53 // Same as above, but increment offset to point at the next insn.
54 codeBuf_t *insnCodeGen::ptrAndInc(codeGen &gen) {
55   // MAKE SURE THAT ret WILL STAY VALID!
56   gen.realloc(gen.used() + sizeof(instruction));
57
58   instructUnion *ret = insnPtr(gen);
59   gen.moveIndex(instruction::size());
60   return ret;
61 }
62 #endif
63
64 void insnCodeGen::generate(codeGen &gen, instruction &insn) {
65 #if defined(endian_mismatch)
66   // Writing an instruction.  Convert byte order if necessary.
67   unsigned raw = swapBytesIfNeeded(insn.asInt());
68 #else
69   unsigned raw = insn.asInt();
70 #endif
71
72   gen.copy(&raw, sizeof(unsigned));
73 }
74
75 void insnCodeGen::generate(codeGen &gen, instruction &insn, unsigned position) {
76 #if defined(endian_mismatch)
77     // Writing an instruction.  Convert byte order if necessary.
78     unsigned raw = swapBytesIfNeeded(insn.asInt());
79 #else
80     unsigned raw = insn.asInt();
81 #endif
82
83     gen.insert(&raw, sizeof(unsigned), position);
84 }
85
86 void insnCodeGen::generateIllegal(codeGen &gen) { // instP.h
87     instruction insn;
88     generate(gen,insn);
89 }
90
91 void insnCodeGen::generateTrap(codeGen &gen) {
92     instruction insn(BREAK_POINT_INSN);
93     generate(gen,insn);
94 }
95
96 void insnCodeGen::generateBranch(codeGen &gen, long disp, bool link) {
97     if (labs(disp) > MAX_BRANCH_OFFSET) {
98         fprintf(stderr, "ABS OFF: 0x%lx, MAX: 0x%lx\n",
99                 labs(disp), (unsigned long) MAX_BRANCH_OFFSET);
100         bperr( "Error: attempted a branch of 0x%lx\n", disp);
101         logLine("a branch too far\n");
102         showErrorCallback(52, "Internal error: branch too far");
103         bperr( "Attempted to make a branch of offset 0x%lx\n", disp);
104         assert(0);
105     }
106
107     instruction insn;
108     INSN_SET(insn, 26, 30, BOp);
109     //Set the displacement immediate
110     INSN_SET(insn, 0, 25, disp >> 2);
111
112     //Bit 31 is set if it's a branch-and-link (essentially, a call), unset if it's just a branch
113     if(link)
114         INSN_SET(insn, 31, 31, 1);
115     else
116         INSN_SET(insn, 31, 31, 0);
117
118     insnCodeGen::generate(gen, insn);
119 }
120
121 void insnCodeGen::generateBranch(codeGen &gen, Address from, Address to, bool link) {
122     long disp = (to - from);
123
124     if (labs(disp) > MAX_BRANCH_OFFSET) {
125         generateLongBranch(gen, from, to, link);
126     }else
127         generateBranch(gen, disp, link);
128 }
129
130 void insnCodeGen::generateCall(codeGen &gen, Address from, Address to) {
131     generateBranch(gen, from, to, true);
132 }
133
134 void insnCodeGen::generateLongBranch(codeGen &gen,
135                                      Address from,
136                                      Address to,
137                                      bool isCall) 
138 {
139     Register scratch = REG_NULL;
140
141     instPoint *point = gen.point();
142     if(!point)
143     {
144         if(!isCall)
145         {
146             //scratch = 14; //#sasha hard coding register for springboard
147             assert(gen.rs());
148             scratch = gen.rs()->getScratchRegister(gen);
149         }
150         else
151         {
152             generateBranchViaTrap(gen, from, to, isCall);
153             return;
154         }
155     }
156     else
157     {
158         registerSpace *rs = registerSpace::actualRegSpace(point);
159         gen.setRegisterSpace(rs);
160
161         scratch = rs->getScratchRegister(gen, true);
162         if (scratch == REG_NULL)
163         {
164             fprintf(stderr, " %s[%d] No registers. Calling generateBranchViaTrap...\n", FILE__, __LINE__);
165             generateBranchViaTrap(gen, from, to, isCall);
166             return;
167         }
168     }
169
170     insnCodeGen::loadImmIntoReg<Address>(gen, scratch, to);
171
172     instruction branchInsn;
173     branchInsn.clear();
174
175     //Set bits which are 0 for both BR and BLR
176     INSN_SET(branchInsn, 0, 4, 0);
177     INSN_SET(branchInsn, 10, 15, 0);
178
179     //Set register
180     INSN_SET(branchInsn, 5, 9, scratch);
181
182     // Set other bits . Basically, these are the opcode bits. 
183     // The only difference between BR and BLR is that bit 21 is 1 for BLR.
184     INSN_SET(branchInsn, 16, 31, BRegOp);
185     if(isCall)
186         INSN_SET(branchInsn, 21, 21, 1);
187
188     insnCodeGen::generate(gen, branchInsn);
189 }
190
191 void insnCodeGen::generateBranchViaTrap(codeGen &gen, Address from, Address to, bool isCall) {
192     long disp = to - from;
193     if (labs(disp) <= MAX_BRANCH_OFFSET) {
194         // We shouldn't be here, since this is an internal-called-only func.
195         generateBranch(gen, disp, isCall);
196     }
197
198     assert (!isCall); // Can't do this yet
199
200     if (gen.addrSpace()) {
201         // Too far to branch.  Use trap-based instrumentation.
202         gen.addrSpace()->trapMapping.addTrapMapping(from, to, true);
203         insnCodeGen::generateTrap(gen);
204     } else {
205         // Too far to branch and no proc to register trap.
206         fprintf(stderr, "ABS OFF: 0x%lx, MAX: 0x%lx\n",
207                 labs(disp), (unsigned long) MAX_BRANCH_OFFSET);
208         bperr( "Error: attempted a branch of 0x%lx\n", disp);
209         logLine("a branch too far\n");
210         showErrorCallback(52, "Internal error: branch too far");
211         bperr( "Attempted to make a branch of offset 0x%lx\n", disp);
212         assert(0);
213     }
214 }
215
216 void insnCodeGen::generateConditionalBranch(codeGen& gen, Address to, unsigned opcode)
217 {
218     instruction insn;
219     insn.clear();
220
221     //Set opcode
222     INSN_SET(insn, 25, 31, BCondOp);
223
224     //Set imm19 field
225     INSN_SET(insn, 5, 23, to >> 2);
226
227     auto getConditionCode = [&opcode]() -> unsigned
228     {
229         switch(opcode){
230             case lessOp:    return 0xB;
231             case leOp:      return 0xD;
232             case greaterOp: return 0xC;
233             case geOp:      return 0xA;
234             case eqOp:      return 0x0;
235             case neOp:      return 0x1;
236             default:
237                 assert(0); // wrong condition passed
238                 break;
239         }
240     };
241
242     //Set condition 
243     INSN_SET(insn, 0, 3, getConditionCode());
244
245     insnCodeGen::generate(gen, insn);
246 }
247
248
249 void insnCodeGen::generateAddSubShifted(
250         codeGen &gen, insnCodeGen::ArithOp op, int shift, int imm6, Register rm, 
251         Register rn, Register rd, bool is64bit) 
252 {
253     instruction insn;
254     insn.clear();
255
256     //Set bit 31 to 1 if using 64-bit registers
257     if(is64bit)
258         INSN_SET(insn, 31, 31, 1);
259     //Set opcode
260     INSN_SET(insn, 24, 30, op == Add ? ADDShiftOp : SUBShiftOp);
261
262     //Set shift field
263     assert(shift >= 0 && shift <= 3);
264     INSN_SET(insn, 22, 23, (shift & 0x3));
265
266     //Set imm6 field
267     assert(imm6 >= 0 && imm6 < (is64bit ? 64 : 32));
268     INSN_SET(insn, 10, 15, imm6);
269
270     //Set registers
271     INSN_SET(insn, 0, 4, rd);
272     INSN_SET(insn, 5, 9, rn);
273     INSN_SET(insn, 16, 20, rm);
274
275     insnCodeGen::generate(gen, insn);
276 }
277
278 void insnCodeGen::generateAddSubImmediate(
279         codeGen &gen, insnCodeGen::ArithOp op, int shift, int imm12, Register rn, Register rd, bool is64bit) 
280 {
281     instruction insn;
282     insn.clear();
283
284     //Set bit 31 to 1 if using 64-bit registers
285     if(is64bit)
286         INSN_SET(insn, 31, 31, 1);
287     //Set opcode
288     INSN_SET(insn, 24, 30, op == Add ? ADDImmOp : SUBImmOp);
289
290     //Set shift field
291     assert(shift >= 0 && shift <= 3);
292     INSN_SET(insn, 22, 23, (shift & 0x3));
293
294     //Set imm12 field
295     INSN_SET(insn, 10, 21, imm12);
296
297     //Set registers
298     INSN_SET(insn, 5, 9, rn);
299     INSN_SET(insn, 0, 4, rd);
300
301     insnCodeGen::generate(gen, insn);
302 }
303
304 void insnCodeGen::generateMul(codeGen &gen, Register rm, Register rn, Register rd, bool is64bit) {
305     instruction insn;
306     insn.clear();
307
308     //Set bit 31 to 1 if using 64-bit registers
309     if(is64bit)
310         INSN_SET(insn, 31, 31, 1);
311     //Set opcode
312     INSN_SET(insn, 21, 28, MULOp);
313
314     //Bits 10 to 14 are 1 for MUL
315     INSN_SET(insn, 10, 14, 0x1F);
316
317     //Set registers
318     INSN_SET(insn, 16, 20, rm);
319     INSN_SET(insn, 5, 9, rn);
320     INSN_SET(insn, 0, 4, rd);
321
322     insnCodeGen::generate(gen, insn);
323 }
324
325 //#sasha is rm or rn the denominator?
326 void insnCodeGen::generateDiv(
327         codeGen &gen, Register rm, Register rn, Register rd, bool is64bit)
328 {
329     instruction insn;
330     insn.clear();
331
332     // Set bit 31 to 1 if using 64-bit registers
333     if(is64bit)
334         INSN_SET(insn, 31, 31, 1);
335
336     // Set opcode
337     INSN_SET(insn, 21, 30, SDIVOp);
338
339     INSN_SET(insn, 11, 15, 0x1);
340     INSN_SET(insn, 10, 10, 0x0); // signed: SDIV
341
342     //Set registers
343     INSN_SET(insn, 16, 20, rm);
344     INSN_SET(insn, 5, 9, rn);
345     INSN_SET(insn, 0, 4, rd);
346
347     insnCodeGen::generate(gen, insn);
348
349 }
350
351 void insnCodeGen::generateBitwiseOpShifted(
352         codeGen &gen, insnCodeGen::BitwiseOp op, int shift, Register rm, int imm6, 
353         Register rn, Register rd, bool is64bit) 
354 {
355     instruction insn;
356     insn.clear();
357
358     //Set bit 31 to 1 if using 64-bit registers
359     if(is64bit)
360         INSN_SET(insn, 31, 31, 1);
361
362     //Set opcode
363     int opcode;
364     switch(op) {
365         case insnCodeGen::And: opcode = ANDShiftOp;
366             break;
367         case insnCodeGen::Or: opcode = ORRShiftOp;
368             break;
369         case insnCodeGen::Eor: opcode = EORShiftOp;
370             break;
371     }
372     INSN_SET(insn, 24, 30, opcode);
373
374     //Set shift field
375     assert(shift >= 0 && shift <= 3);
376     INSN_SET(insn, 22, 23, (shift & 0x3));
377
378     //Set imm6 field
379     assert(imm6 >= 0 && imm6 < (is64bit ? 64 : 32));
380     INSN_SET(insn, 10, 15, imm6);
381
382     //Set registers
383     INSN_SET(insn, 16, 20, rm);
384     INSN_SET(insn, 5, 9, rn);
385     INSN_SET(insn, 0, 4, rd);
386
387     insnCodeGen::generate(gen, insn);
388 }
389
390 void insnCodeGen::generateLoadReg(codeGen &gen, Register rt,
391                                   Register ra, Register rb)
392 {
393     assert(0);
394 //#warning "This function is not implemented yet!"
395 }
396
397 void insnCodeGen::generateStoreReg(codeGen &gen, Register rt,
398                                    Register ra, Register rb)
399 {
400     assert(0);
401 //#warning "This function is not implemented yet!"
402 }
403
404 void insnCodeGen::generateLoadReg64(codeGen &gen, Register rt,
405                                     Register ra, Register rb)
406 {
407 assert(0);
408 //#warning "This function is not implemented yet!"
409 }
410
411 void insnCodeGen::generateStoreReg64(codeGen &gen, Register rs,
412                                      Register ra, Register rb)
413 {
414 assert(0);
415 //#warning "This function is not implemented yet!"
416 }
417
418 void insnCodeGen::generateMove(codeGen &gen, int imm16, int shift, Register rd, MoveOp movOp)
419 {
420     instruction insn;
421     insn.clear();
422
423     //Set the sf bit to 1 since we always want to use 64-bit registers
424     INSN_SET(insn, 31, 31, 1);
425
426     //Set opcode
427     INSN_SET(insn, 23, 30, movOp);
428
429     //Set immediate
430     INSN_SET(insn, 5, 20, imm16);
431
432     //Set register
433     INSN_SET(insn, 0, 4, rd);
434
435     //Set shift amount for immediate
436     INSN_SET(insn, 21, 22, (shift & 0x3));
437
438     insnCodeGen::generate(gen, insn);
439 }
440
441 void insnCodeGen::generateMove(
442         codeGen &gen, Register rd, Register rm, bool is64bit)
443 {
444     insnCodeGen::generateBitwiseOpShifted(gen, insnCodeGen::Or, 0, rm, 0, 0x1f, rd, is64bit);  
445 }
446
447 void insnCodeGen::generateMoveSP(codeGen &gen, Register rn, Register rd, bool is64bit) {
448     instruction insn;
449     insn.clear();
450
451     //Set source and destination registers
452     INSN_SET(insn, 0, 4, rd & 0x1f);
453     INSN_SET(insn, 5, 9, rn & 0x1f);
454
455     //Set opcode
456     INSN_SET(insn, 10, 30, MOVSPOp);
457
458     //Set if using 64-bit registers
459     INSN_SET(insn, 31, 31, is64bit);
460
461     insnCodeGen::generate(gen, insn);
462 }
463
464
465 Register insnCodeGen::moveValueToReg(codeGen &gen, long int val, pdvector<Register> *exclude) {
466     Register scratchReg;
467     if(exclude)
468             scratchReg = gen.rs()->getScratchRegister(gen, *exclude, true);
469     else
470             scratchReg = gen.rs()->getScratchRegister(gen, true);
471
472     if (scratchReg == REG_NULL) {
473         fprintf(stderr, " %s[%d] No scratch register available to generate add instruction!", FILE__, __LINE__);
474         assert(0);
475     }
476
477     /*insnCodeGen::generateMove(gen, (val & 0xFFFF), 0, scratchReg, insnCodeGen::MovOp_MOVZ);
478     if (val >= MIN_IMM32 && val < MAX_IMM32)
479         insnCodeGen::generateMove(gen, ((val >> 16) & 0xFFFF), 0x1, scratchReg, insnCodeGen::MovOp_MOVK);
480     if (val < MIN_IMM32 || val > MAX_IMM32) {
481         insnCodeGen::generateMove(gen, ((val >> 32) & 0xFFFF), 0x2, scratchReg, insnCodeGen::MovOp_MOVK);
482         insnCodeGen::generateMove(gen, ((val >> 48) & 0xFFFF), 0x3, scratchReg, insnCodeGen::MovOp_MOVK);
483     }*/
484     loadImmIntoReg<long int>(gen, scratchReg, val);
485
486     return scratchReg;
487 }
488
489
490 template <typename T>
491 void insnCodeGen::loadImmIntoReg(codeGen &gen, Register rt, T value)
492 {
493     assert(value >= 0);
494
495     insnCodeGen::generateMove(gen, (value & 0xFFFF), 0, rt, MovOp_MOVZ);
496     if(value > 0xFFFF)
497         insnCodeGen::generateMove(gen, ((value >> 16) & 0xFFFF), 0x1, rt, MovOp_MOVK);
498     if(value > 0xFFFFFFFF)
499         insnCodeGen::generateMove(gen, ((value >> 32) & 0xFFFF), 0x2, rt, MovOp_MOVK);
500     if(value > 0xFFFFFFFFFFFF)
501         insnCodeGen::generateMove(gen, ((value >> 48) & 0xFFFF), 0x3, rt, MovOp_MOVK);
502 }
503
504
505 // This is for generating STR/LDR (imediate) for indexing modes of Post, Pre and Offset
506 void insnCodeGen::generateMemAccess32or64(codeGen &gen, LoadStore accType,
507         Register r1, Register r2, int immd, bool is64bit, IndexMode im)
508 {
509     instruction insn;
510     insn.clear();
511
512     //Bit 31 is always 1. Bit 30 is 1 if we're using the 64-bit variant.
513     INSN_SET(insn, 31, 31, 1);
514     if(is64bit)
515         INSN_SET(insn, 30, 30, 1);
516
517     switch(im){
518         case Post:
519         case Pre:
520             //Set opcode, index and offset bits
521             if(immd >= -256 && immd <= 255) {
522                 INSN_SET(insn, 21, 29, (accType == Load) ? LDRImmOp : STRImmOp);
523                 INSN_SET(insn, 10, 11, im==Post?0x1:0x3);
524                 INSN_SET(insn, 12, 20, immd);
525             } else {
526                 assert(!"Cannot perform a post/pre-indexed memory access for offsets not in range [-256, 255]!");
527             }
528             break;
529         case Offset:
530             INSN_SET(insn, 22, 29, (accType == Load) ? LDRImmUIOp : STRImmUIOp);
531             assert(immd>=0); // this offset is supposed to unsigned, i.e. positive
532             INSN_SET(insn, 10, 21, immd>>3);
533             break;
534     }
535
536     //Set memory access register and register for address calculation.
537     INSN_SET(insn, 0, 4, r1 & 0x1F);
538     INSN_SET(insn, 5, 9, r2 & 0x1F);
539
540     insnCodeGen::generate(gen, insn);
541 }
542
543 void insnCodeGen::generateMemAccessFP(codeGen &gen, LoadStore accType,
544         Register rt, Register rn, int immd, int size, bool is128bit)
545 {
546     instruction insn;
547     insn.clear();
548
549     if(size < 0 || size > 3)
550         assert(!"Size field for STR (immediate, SIMD&FP) variant has to be in the range [0-3]!");
551
552     //Set size, opcode, index and offset bits
553     INSN_SET(insn, 30, 31, size & 0x3);
554     INSN_SET(insn, 21, 29, (accType == Load) ? LDRFPImmOp : STRFPImmOp);
555     if(is128bit)
556         INSN_SET(insn, 23, 23, 1);
557     INSN_SET(insn, 10, 11, 0x1);
558     if(immd >= -256 && immd <= 255) {
559         INSN_SET(insn, 12, 20, immd);
560     } else {
561         assert(!"Cannot perform a post-indexed memory access for offsets not in range [-256, 255]!");
562     }
563
564     //Set memory access register and register for address calculation.
565     INSN_SET(insn, 0, 4, rt);
566     INSN_SET(insn, 5, 9, rn);
567
568     insnCodeGen::generate(gen, insn);
569 }
570
571 // rlwinm ra,rs,n,0,31-n
572 void insnCodeGen::generateLShift(codeGen &gen, Register rs, int shift, Register ra)
573 {
574 assert(0);
575 //#warning "This function is not implemented yet!"
576 }
577
578 // rlwinm ra,rs,32-n,n,31
579 void insnCodeGen::generateRShift(codeGen &gen, Register rs, int shift, Register ra)
580 {
581 assert(0);
582 //#warning "This function is not implemented yet!"
583 }
584
585 // sld ra, rs, rb
586 void insnCodeGen::generateLShift64(codeGen &gen, Register rs, int shift, Register ra)
587 {
588 assert(0);
589 //#warning "This function is not implemented yet!"
590 }
591
592 // srd ra, rs, rb
593 void insnCodeGen::generateRShift64(codeGen &gen, Register rs, int shift, Register ra)
594 {
595 assert(0);
596 //not implemented
597 }
598
599 //
600 // generate an instruction that does nothing and has to side affect except to
601 //   advance the program counter.
602 //
603 void insnCodeGen::generateNOOP(codeGen &gen, unsigned size) {
604     assert((size % instruction::size()) == 0);
605     while (size) {
606         instruction insn(NOOP);
607         insnCodeGen::generate(gen, insn);
608         size -= instruction::size();
609     }
610 }
611
612 void insnCodeGen::generateSimple(codeGen &gen, int op,
613                                  Register src1, Register src2,
614                                  Register dest)
615 {
616 assert(0);
617 //#warning "This function is not implemented yet!"
618 }
619
620 void insnCodeGen::generateRelOp(codeGen &gen, int cond, int mode, Register rs1,
621                                 Register rs2, Register rd)
622 {
623 assert(0);
624 //#warning "This function is not implemented yet!"
625 }
626
627
628 void insnCodeGen::saveRegister(codeGen &gen, Register r, int sp_offset, IndexMode im)
629 {
630     generateMemAccess32or64(gen, Store, r, REG_SP, sp_offset, true, im);
631 }
632
633
634 void insnCodeGen::restoreRegister(codeGen &gen, Register r, int sp_offset, IndexMode im)
635 {
636     generateMemAccess32or64(gen, Load, r, REG_SP, sp_offset, true, im);
637 }
638
639
640 // Helper method.  Fills register with partial value to be completed
641 // by an operation with a 16-bit signed immediate.  Such as loads and
642 // stores.
643 void insnCodeGen::loadPartialImmIntoReg(codeGen &gen, Register rt, long value)
644 {
645 assert(0);
646 //#warning "This function is not implemented yet!"
647 }
648
649 int insnCodeGen::createStackFrame(codeGen &gen, int numRegs, pdvector<Register>& freeReg, pdvector<Register>& excludeReg){
650 assert(0);
651 //#warning "This function is not implemented yet!"
652                 return freeReg.size();
653 }
654
655 void insnCodeGen::removeStackFrame(codeGen &gen) {
656 assert(0);
657 //#warning "This function is not implemented yet!"
658 }
659
660 bool insnCodeGen::generate(codeGen &gen,
661                            instruction &insn,
662                            AddressSpace * /*proc*/,
663                            Address /*origAddr*/,
664                            Address /*relocAddr*/,
665                            patchTarget * /*fallthroughOverride*/,
666                            patchTarget * /*targetOverride*/) {
667   assert(0 && "Deprecated!");
668   return false;
669 }
670
671 bool insnCodeGen::generateMem(codeGen &,
672                               instruction&,
673                               Address,
674                               Address,
675                               Register,
676                   Register) {
677 assert(0);
678 //#warning "This function is not implemented yet!"
679 return false; }
680
681 void insnCodeGen::generateMoveFromLR(codeGen &gen, Register rt) {
682 assert(0);
683 //#warning "This function is not implemented yet!"
684 }
685
686 void insnCodeGen::generateMoveToLR(codeGen &gen, Register rs) {
687 assert(0);
688 //#warning "This function is not implemented yet!"
689 }
690 void insnCodeGen::generateMoveToCR(codeGen &gen, Register rs) {
691 assert(0);
692 //#warning "This function is not implemented yet!"
693 }
694
695 bool insnCodeGen::modifyJump(Address target,
696                              NS_aarch64::instruction &insn,
697                              codeGen &gen) {
698     long disp = target - gen.currAddr();
699
700     if(INSN_GET_ISCALL(insn))
701     {
702         generateBranch(gen, gen.currAddr(), target, INSN_GET_ISCALL(insn));
703         return true;
704     }
705
706     if (labs(disp) > MAX_BRANCH_OFFSET) {
707         generateBranchViaTrap(gen, gen.currAddr(), target, INSN_GET_ISCALL(insn));
708         return true;
709     }
710
711     generateBranch(gen,
712                    gen.currAddr(),
713                    target,
714                    INSN_GET_ISCALL(insn));
715     return true;
716 }
717
718 /* TODO and/or FIXME
719  * The logic used by this function is common across architectures but is replicated 
720  * in architecture-specific manner in all codegen-* files.
721  * This means that the logic itself needs to be refactored into the (platform 
722  * independent) codegen.C file. Appropriate architecture-specific,
723  * bit-twiddling functions can then be defined if necessary in the codegen-* files 
724  * and called as necessary by the common, refactored logic.
725 */
726 bool insnCodeGen::modifyJcc(Address target,
727                             NS_aarch64::instruction &insn,
728                             codeGen &gen) {
729     long disp = target - gen.currAddr();
730     auto isTB = insn.isInsnType(COND_BR_t::TB_MASK, COND_BR_t::TB);
731     
732     if(labs(disp) > MAX_CBRANCH_OFFSET ||
733             (isTB && labs(disp) > MAX_TBRANCH_OFFSET))
734     {
735         const unsigned char *origInsn = insn.ptr();
736         Address origFrom = gen.currAddr();
737
738         /*
739          * A conditional branch of the form:
740          *    b.cond A
741          * C: ...next insn...:
742          * [Note that b.cond could also be cbz, cbnz, tbz or tbnz -- all valid conditional branch instructions]
743          *
744          * Gets converted to:
745          *    b.cond B
746          *    b      C
747          * B: b      A
748          * C: ...next insn...
749          */
750
751         // Store start index of code buffer to later calculate how much the original instruction's will have moved
752         codeBufIndex_t startIdx = gen.getIndex();
753
754         /* Generate the --b.cond B-- instruction. Directly modifying the offset 
755          * bits of the instruction passed since other bits are to remain the same anyway.
756            B will be 4 bytes from the next instruction. (it will get multiplied by 4 by the CPU) */
757         instruction newInsn(insn);
758         if(insn.isInsnType(COND_BR_t::TB_MASK, COND_BR_t::TB))
759             INSN_SET(newInsn, 5, 18, 0x1);
760         else
761             INSN_SET(newInsn, 5, 23, 0x1);
762         generate(gen, newInsn);
763
764         /* Generate the --b C-- instruction. C will be 4 bytes from the next 
765          * instruction, hence offset for this instruction is set to 1.
766           (it will get multiplied by 4 by the CPU) */
767         newInsn.clear();
768         INSN_SET(newInsn, 0, 25, 0x1);
769         INSN_SET(newInsn, 26, 31, 0x05);
770         generate(gen, newInsn);
771
772         /* Generate the final --b A-- instruction.
773          * The 'from' address to be passed in to generateBranch is now several
774          * bytes (8 actually, but I'm not hardcoding this) ahead of the original 'from' address.
775          * So adjust it accordingly.*/
776         codeBufIndex_t curIdx = gen.getIndex();
777         Address newFrom = origFrom + (unsigned)(curIdx - startIdx);
778         insnCodeGen::generateBranch(gen, newFrom, target);
779     } 
780     else
781     {
782         instruction condBranchInsn(insn);
783
784         // Set the displacement immediate
785         if(isTB)
786             INSN_SET(condBranchInsn, 5, 18, disp >> 2);
787         else
788             INSN_SET(condBranchInsn, 5, 23, disp >> 2);
789
790         generate(gen, condBranchInsn);
791     }
792
793     return true;
794 }
795
796 bool insnCodeGen::modifyCall(Address target,
797                              NS_aarch64::instruction &insn,
798                              codeGen &gen) {
799     if (insn.isUncondBranch())
800         return modifyJump(target, insn, gen);
801     else
802         return modifyJcc(target, insn, gen);
803 }
804
805 bool insnCodeGen::modifyData(Address target,
806         NS_aarch64::instruction &insn,
807         codeGen &gen) 
808 {
809     int raw = insn.asInt();
810     bool isneg = false;
811
812     if (target < gen.currAddr())
813         isneg = true;
814
815     if (((raw >> 24) & 0x1F) == 0x10) {
816         Address offset;
817         if((raw >> 31) & 0x1) {
818             target &= 0xFFFFF000;
819             Address cur = gen.currAddr() & 0xFFFFF000;
820             offset = isneg ? (cur - target) : (target - cur);
821             offset >>= 12;
822         } else {
823             Address cur = gen.currAddr();
824             offset = isneg ? (cur - target) : (target - cur);
825         }
826         signed long imm = isneg ? -((signed long)offset) : offset;
827
828         //If offset is within +/- 1 MB, modify the instruction (ADR/ADRP) with the new offset
829         if (offset <= (1 << 20)) {
830             instruction newInsn(insn);
831             INSN_SET(newInsn, 5, 23, ((imm >> 2) & 0x7FFFF));
832             INSN_SET(newInsn, 29, 30, (imm & 0x3));
833             generate(gen, newInsn);
834         }
835         //Else, generate move instructions to move the value to the same register
836         else {
837             //Register rd = raw & 0x1F;
838             //loadImmIntoReg<Address>(gen, rd, target);
839             instruction newInsn;
840             instruction newInsn2;
841             newInsn.clear();
842             signed long page_rel = ((long)(target >> 12)) - ((long)(gen.currAddr() >> 12));
843             signed long off = target & 0xFFFF;
844             INSN_SET(newInsn, 0, 4, raw & 0x1F);
845             INSN_SET(newInsn, 5, 23, ((page_rel >> 2) & 0x7FFFF));
846             INSN_SET(newInsn, 24, 28, 0x10);
847             INSN_SET(newInsn, 29, 30, (page_rel & 0x3));
848             INSN_SET(newInsn, 31, 31, 1);
849             generate(gen, newInsn);
850             newInsn2.clear();
851             INSN_SET(newInsn2, 0, 4, raw & 0x1F);
852             INSN_SET(newInsn2, 5, 9, raw & 0x1F);
853             INSN_SET(newInsn2, 10, 21, off);
854             INSN_SET(newInsn2, 22, 31, 0x244);
855             generate(gen , newInsn2);
856
857         }
858     } else if (((raw >> 24) & 0x3F) == 0x18 || ((raw >> 24) & 0x3F) == 0x1C) {
859         Address offset = !isneg ? (target - gen.currAddr()) : (gen.currAddr() - target);
860         //If offset is within +/- 1 MB, modify the instruction (LDR/LDRSW) with the new offset
861         if (offset <= (1 << 20)) {
862             instruction newInsn(insn);
863
864             isneg ? (offset += 4) : (offset -= 4);
865             signed long imm = isneg ? -(offset >> 2) : (offset >> 2);
866             INSN_SET(newInsn, 5, 23, (imm & 0x7FFFF));
867
868             generate(gen, newInsn);
869         }
870         //Else, generate move instructions to move the value to the same register
871         else {
872             //Get scratch register for loading the target address in
873             Register immReg = gen.rs()->getScratchRegister(gen, true);
874             if(immReg == REG_NULL)
875                 assert(!"No scratch register available to load the target address into for a PC-relative data access using LDR/LDRSW!");
876             //Generate sequence of instructions for loading the target address in scratch register
877             assert(!"DDDD");
878             loadImmIntoReg<Address>(gen, immReg, target);
879
880             Register rt = raw & 0x1F;
881
882             //Generate instruction for reading value at target address using unsigned-offset variant of the immediate variant of LDR/LDRSW
883             instruction newInsn;
884             newInsn.clear();
885
886             if(((raw >> 31) & 0x1) == 0) {
887                 INSN_SET(newInsn, 30, 30, ((raw >> 30) & 0x1));
888                 INSN_SET(newInsn, 22, 29, LDRImmUIOp);
889             } else {
890                 INSN_SET(newInsn, 22, 29, LDRSWImmUIOp);
891             }
892
893             INSN_SET(newInsn, 31, 31, 0x1);
894             INSN_SET(newInsn, 10, 21, 0);
895             INSN_SET(newInsn, 5, 9, immReg);
896             INSN_SET(newInsn, 0, 4, rt);
897
898             generate(gen, newInsn);
899         }
900     } else {
901         assert(!"Got an instruction other than ADR/ADRP/LDR(literal)/LDRSW(literal) in PC-relative data access!");
902     }
903
904     return true;
905 }
906