- int64_t displacement = _target->finalAddress() - this->finalAddress() - 4;
- if ( _target->contentType() == ld::Atom::typeBranchIsland ) {
- // an ARM branch can branch farther than a thumb branch. The branch
- // island generation was conservative and put islands every thumb
- // branch distance apart. Check to see if this is a an island
- // hopping branch that could be optimized to go directly to target.
- int64_t skipToFinalDisplacement = _finalTarget.atom->finalAddress() + _finalTarget.offset - this->finalAddress() - 4;
- if ( (skipToFinalDisplacement < 16777214) && (skipToFinalDisplacement > (-16777216LL)) ) {
- // can skip branch island and jump straight to target
- if (_s_log) fprintf(stderr, "%s: optimized jump to final target at 0x%08llX, thisAddr=0x%08llX\n",
- _target->name(), _finalTarget.atom->finalAddress(), this->finalAddress());
- displacement = skipToFinalDisplacement;
- }
- else {
- // ultimate target is too far for thumb2 branch, jump to island
- if (_s_log) fprintf(stderr, "%s: jump to branch island at 0x%08llX\n",
- _target->name(), _finalTarget.atom->finalAddress());
- }
- }
- // The instruction is really two instructions:
- // The lower 16 bits are the first instruction, which contains the high
- // 11 bits of the displacement.
- // The upper 16 bits are the second instruction, which contains the low
- // 11 bits of the displacement, as well as differentiating bl and blx.
- uint32_t s = (uint32_t)(displacement >> 24) & 0x1;
- uint32_t i1 = (uint32_t)(displacement >> 23) & 0x1;
- uint32_t i2 = (uint32_t)(displacement >> 22) & 0x1;
- uint32_t imm10 = (uint32_t)(displacement >> 12) & 0x3FF;
- uint32_t imm11 = (uint32_t)(displacement >> 1) & 0x7FF;
- uint32_t j1 = (i1 == s);
- uint32_t j2 = (i2 == s);
- uint32_t opcode = 0x9000F000;
- uint32_t nextDisp = (j1 << 13) | (j2 << 11) | imm11;
- uint32_t firstDisp = (s << 10) | imm10;
- uint32_t newInstruction = opcode | (nextDisp << 16) | firstDisp;
- //warning("s=%d, j1=%d, j2=%d, imm10=0x%0X, imm11=0x%0X, opcode=0x%08X, first=0x%04X, next=0x%04X, new=0x%08X, disp=0x%llX for %s to %s\n",
- // s, j1, j2, imm10, imm11, opcode, firstDisp, nextDisp, newInstruction, displacement, inAtom->getDisplayName(), ref->getTarget().getDisplayName());
- OSWriteLittleInt32(buffer, 0, newInstruction);