/* generate branch to skip the data */if(data_size==0)returngen_code_ptr;target=(long)gen_code_ptr+data_size+4;arm_reloc_pc24((uint32_t*)gen_code_ptr,0xeafffffe,target);gen_code_ptr+=4;}/* copy the data */data_ptr=gen_code_ptr;memcpy(gen_code_ptr,data_start,data_size);gen_code_ptr+=data_size;/* patch the ldr to point to the data */for(le=ldr_start;le<ldr_end;le++){ptr=(uint32_t*)le->ptr;offset=((unsignedlong)(le->data_ptr)-(unsignedlong)data_start)+(unsignedlong)data_ptr-(unsignedlong)ptr-8;if(offset<0){
#ifdef__ia64/* Patch instruction with "val" where "mask" has 1 bits. */staticinlinevoidia64_patch(uint64_tinsn_addr,uint64_tmask,uint64_tval){uint64_tm0,m1,v0,v1,b0,b1,*b=(uint64_t*)(insn_addr&-16);#defineinsn_mask((1UL<<41)-1)unsignedlongshift;b0=b[0];b1=b[1];shift=5+41*(insn_addr%16);/* 5 template, 3 x 41-bit insns */if(shift>=64){m1=mask<<(shift-64);v1=val<<(shift-64);}else{m0=mask<<shift;m1=mask>>(64-shift);v0=val<<shift;v1=val>>(64-shift);b[0]=(b0&~m0)|(v0&m0);}b[1]=(b1&~m1)|(v1&m1);}staticinlinevoidia64_patch_imm60(uint64_tinsn_addr,uint64_tval){ia64_patch(insn_addr,0x011ffffe000UL,(((val&0x0800000000000000UL)>>23)/* bit 59 -> 36 */|((val&0x00000000000fffffUL)<<13)/* bit 0 -> 13 */));ia64_patch(insn_addr-1,0x1fffffffffcUL,val>>18);}staticinlinevoidia64_imm64(void*insn,uint64_tval){/*Ignoretheslotnumberoftherelocation;GCCandInteltoolchainsdifferedforsometimeonwhetherIMM64relocsareagainstslot1(Intel)orslot2(GCC).*/uint64_tinsn_addr=(uint64_t)insn&~3UL;ia64_patch(insn_addr+2,0x01fffefe000UL,(((val&0x8000000000000000UL)>>27)/* bit 63 -> 36 */|((val&0x0000000000200000UL)<<0)/* bit 21 -> 21 */|((val&0x00000000001f0000UL)<<6)/* bit 16 -> 22 */|((val&0x000000000000ff80UL)<<20)/* bit 7 -> 27 */|((val&0x000000000000007fUL)<<13)/* bit 0 -> 13 */));ia64_patch(insn_addr+1,0x1ffffffffffUL,val>>22);}staticinlinevoidia64_imm60b(void*insn,uint64_tval){/*Ignoretheslotnumberoftherelocation;GCCandInteltoolchainsdifferedforsometimeonwhetherIMM64relocsareagainstslot1(Intel)orslot2(GCC).*/uint64_tinsn_addr=(uint64_t)insn&~3UL;if(val+((uint64_t)1<<59)>=(1UL<<60))fprintf(stderr,"%s: value %ld out of IMM60 range\n",__FUNCTION__,(int64_t)val);ia64_patch_imm60(insn_addr+2,val);}staticinlinevoidia64_imm22(void*insn,uint64_tval){if(val+(1<<21)>=(1<<22))fprintf(stderr,"%s: value %li out of IMM22 range\n",__FUNCTION__,(int64_t)val);ia64_patch((uint64_t)insn,0x01fffcfe000UL,(((val&0x200000UL)<<15)/* bit 21 -> 36 */|((val&0x1f0000UL)<<6)/* bit 16 -> 22 */|((val&0x00ff80UL)<<20)/* bit 7 -> 27 */|((val&0x00007fUL)<<13)/* bit 0 -> 13 */));}/*Likeia64_imm22(),butalsoclearbits20-21.Foraddl,thishastheeffectofturning"addl rX=imm22,rY"into"addl rX=imm22,r0".*/staticinlinevoidia64_imm22_r0(void*insn,uint64_tval){if(val+(1<<21)>=(1<<22))fprintf(stderr,"%s: value %li out of IMM22 range\n",__FUNCTION__,(int64_t)val);ia64_patch((uint64_t)insn,0x01fffcfe000UL|(0x3UL<<20),(((val&0x200000UL)<<15)/* bit 21 -> 36 */|((val&0x1f0000UL)<<6)/* bit 16 -> 22 */|((val&0x00ff80UL)<<20)/* bit 7 -> 27 */|((val&0x00007fUL)<<13)/* bit 0 -> 13 */));}staticinlinevoidia64_imm21b(void*insn,uint64_tval){if(val+(1<<20)>=(1<<21))fprintf(stderr,"%s: value %li out of IMM21b range\n",__FUNCTION__,(int64_t)val);ia64_patch((uint64_t)insn,0x11ffffe000UL,(((val&0x100000UL)<<16)/* bit 20 -> 36 */|((val&0x0fffffUL)<<13)/* bit 0 -> 13 */));}staticinlinevoidia64_nop_b(void*insn){ia64_patch((uint64_t)insn,(1UL<<41)-1,2UL<<37);}staticinlinevoidia64_ldxmov(void*insn,uint64_tval){if(val+(1<<21)<(1<<22))ia64_patch((uint64_t)insn,0x1fff80fe000UL,8UL<<37);}staticinlineintia64_patch_ltoff(void*insn,uint64_tval,intrelaxable){if(relaxable&&(val+(1<<21)<(1<<22))){ia64_imm22_r0(insn,val);return0;}return1;}structia64_fixup{structia64_fixup*next;void*addr;/* address that needs to be patched */longvalue;};#defineIA64_PLT(insn,plt_index)\do{\structia64_fixup*fixup=alloca(sizeof(*fixup));\fixup->next=plt_fixes;\plt_fixes=fixup;\fixup->addr=(insn);\fixup->value=(plt_index);\plt_offset[(plt_index)]=1;\}while(0)#defineIA64_LTOFF(insn,val,relaxable)\do{\if(ia64_patch_ltoff(insn,val,relaxable)){\structia64_fixup*fixup=alloca(sizeof(*fixup));\fixup->next=ltoff_fixes;\ltoff_fixes=fixup;\fixup->addr=(insn);\fixup->value=(val);\}\}while(0)staticinlinevoidia64_apply_fixes(uint8_t**gen_code_pp,structia64_fixup*ltoff_fixes,uint64_tgp,structia64_fixup*plt_fixes,intnum_plts,unsignedlong*plt_target,unsignedint*plt_offset){staticconstuint8_tplt_bundle[]={0x04,0x00,0x00,0x00,0x01,0x00,0x00,0x00,/* nop 0; movl r1=GP */0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x60,0x05,0x00,0x00,0x00,0x01,0x00,0x00,0x00,/* nop 0; brl IP */0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0};uint8_t*gen_code_ptr=*gen_code_pp,*plt_start,*got_start,*vp;structia64_fixup*fixup;unsignedintoffset=0;structfdesc{longip;longgp;}*fdesc;inti;if(plt_fixes){plt_start=gen_code_ptr;for(i=0;i<num_plts;++i){if(plt_offset[i]){plt_offset[i]=offset;offset+=sizeof(plt_bundle);fdesc=(structfdesc*)plt_target[i];memcpy(gen_code_ptr,plt_bundle,sizeof(plt_bundle));ia64_imm64(gen_code_ptr+0x02,fdesc->gp);ia64_imm60b(gen_code_ptr+0x12,(fdesc->ip-(long)(gen_code_ptr+0x10))>>4);gen_code_ptr+=sizeof(plt_bundle);}}for(fixup=plt_fixes;fixup;fixup=fixup->next)ia64_imm21b(fixup->addr,((long)plt_start+plt_offset[fixup->value]-((long)fixup->addr&~0xf))>>4);}got_start=gen_code_ptr;/* First, create the GOT: */for(fixup=ltoff_fixes;fixup;fixup=fixup->next){/* first check if we already have this value in the GOT: */for(vp=got_start;vp<gen_code_ptr;++vp)if(*(uint64_t*)vp==fixup->value)break;if(vp==gen_code_ptr){/* Nope, we need to put the value in the GOT: */*(uint64_t*)vp=fixup->value;gen_code_ptr+=8;}ia64_imm22(fixup->addr,(long)vp-gp);}