< prev index next >
src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
Print this page
rev 9227 : 8143067: aarch64: guarantee failure in javac
Summary: Fix adrp going out of range during code relocation
Reviewed-by: duke
*** 95,112 ****
// 1 - adrp Rx, target_page
// ldr/str Ry, [Rx, #offset_in_page]
// 2 - adrp Rx, target_page
// add Ry, Rx, #offset_in_page
// 3 - adrp Rx, target_page (page aligned reloc, offset == 0)
! // In the first 2 cases we must check that Rx is the same in the adrp and the
! // subsequent ldr/str or add instruction. Otherwise we could accidentally end
! // up treating a type 3 relocation as a type 1 or 2 just because it happened
! // to be followed by a random unrelated ldr/str or add instruction.
! //
! // In the case of a type 3 relocation, we know that these are only generated
! // for the safepoint polling page, or for the card type byte map base so we
! // assert as much and of course that the offset is 0.
//
unsigned insn2 = ((unsigned*)branch)[1];
if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 &&
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 9, 5)) {
--- 95,107 ----
// 1 - adrp Rx, target_page
// ldr/str Ry, [Rx, #offset_in_page]
// 2 - adrp Rx, target_page
// add Ry, Rx, #offset_in_page
// 3 - adrp Rx, target_page (page aligned reloc, offset == 0)
! // nop/movk Rx, #imm12<<32
! // In all cases we check that Rx is the same in the adrp and the subsequent
! // ldr/str, add or movk.
//
unsigned insn2 = ((unsigned*)branch)[1];
if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 &&
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 9, 5)) {
*** 121,137 ****
Instruction_aarch64::extract(insn2, 4, 0)) {
// add (immediate)
Instruction_aarch64::patch(branch + sizeof (unsigned),
21, 10, offset_lo);
instructions = 2;
} else {
! assert((jbyte *)target ==
! ((CardTableModRefBS*)(Universe::heap()->barrier_set()))->byte_map_base ||
! target == StubRoutines::crc_table_addr() ||
! (address)target == os::get_polling_page(),
! "adrp must be polling page or byte map base");
! assert(offset_lo == 0, "offset must be 0 for polling page or byte map base");
}
}
int offset_lo = offset & 3;
offset >>= 2;
Instruction_aarch64::spatch(branch, 23, 5, offset);
--- 116,137 ----
Instruction_aarch64::extract(insn2, 4, 0)) {
// add (immediate)
Instruction_aarch64::patch(branch + sizeof (unsigned),
21, 10, offset_lo);
instructions = 2;
+ } else if (insn2 == aarch64_NOP || // NOP or MOVK Rx, #imm12 << 32
+ (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110) &&
+ Instruction_aarch64::extract(insn, 4, 0) ==
+ Instruction_aarch64::extract(insn2, 4, 0)) {
+ if (offset >= -(1<<20) && offset < (1<<20)) {
+ *(unsigned *)(branch + 4) = aarch64_NOP;
+ } else {
+ Instruction_aarch64::patch_movk(branch, 4, 20, 5, (uint64_t)target, 32);
+ offset &= (1<<20)-1;
+ }
} else {
! ShouldNotReachHere();
}
}
int offset_lo = offset & 3;
offset >>= 2;
Instruction_aarch64::spatch(branch, 23, 5, offset);
*** 213,229 ****
// 1 - adrp Rx, target_page
// ldr/str Ry, [Rx, #offset_in_page]
// 2 - adrp Rx, target_page ]
// add Ry, Rx, #offset_in_page
// 3 - adrp Rx, target_page (page aligned reloc, offset == 0)
//
// In the first two cases we check that the register is the same and
// return the target_page + the offset within the page.
! // Otherwise we assume it is a page aligned relocation and return
! // the target page only. The only cases this is generated is for
! // the safepoint polling page or for the card table byte map base so
! // we assert as much.
//
unsigned insn2 = ((unsigned*)insn_addr)[1];
if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 &&
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 9, 5)) {
--- 213,228 ----
// 1 - adrp Rx, target_page
// ldr/str Ry, [Rx, #offset_in_page]
// 2 - adrp Rx, target_page ]
// add Ry, Rx, #offset_in_page
// 3 - adrp Rx, target_page (page aligned reloc, offset == 0)
+ // nop/movk Rx, #imm12<<32
//
// In the first two cases we check that the register is the same and
// return the target_page + the offset within the page.
! //
! // In the third case we return just the target_page
//
unsigned insn2 = ((unsigned*)insn_addr)[1];
if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 &&
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 9, 5)) {
*** 235,250 ****
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 4, 0)) {
// add (immediate)
unsigned int byte_offset = Instruction_aarch64::extract(insn2, 21, 10);
return address(target_page + byte_offset);
! } else {
! assert((jbyte *)target_page ==
! ((CardTableModRefBS*)(Universe::heap()->barrier_set()))->byte_map_base ||
! (address)target_page == os::get_polling_page(),
! "adrp must be polling page or byte map base");
return (address)target_page;
}
} else {
ShouldNotReachHere();
}
} else if (Instruction_aarch64::extract(insn, 31, 23) == 0b110100101) {
--- 234,254 ----
Instruction_aarch64::extract(insn, 4, 0) ==
Instruction_aarch64::extract(insn2, 4, 0)) {
// add (immediate)
unsigned int byte_offset = Instruction_aarch64::extract(insn2, 21, 10);
return address(target_page + byte_offset);
! } else if (insn2 == aarch64_NOP || // NOP or MOVK Rx, #imm12 << 32
! (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110) &&
! Instruction_aarch64::extract(insn, 4, 0) ==
! Instruction_aarch64::extract(insn2, 4, 0)) {
! if (insn2 != aarch64_NOP) {
! target_page = (target_page & 0xffffffff) |
! ((uint64_t)Instruction_aarch64::extract(insn2, 20, 5) << 32);
! }
return (address)target_page;
+ } else {
+ ShouldNotReachHere();
}
} else {
ShouldNotReachHere();
}
} else if (Instruction_aarch64::extract(insn, 31, 23) == 0b110100101) {
*** 3071,3081 ****
str(rscratch1, adr);
}
void MacroAssembler::cmpptr(Register src1, Address src2) {
unsigned long offset;
! adrp(rscratch1, src2, offset);
ldr(rscratch1, Address(rscratch1, offset));
cmp(src1, rscratch1);
}
void MacroAssembler::store_check(Register obj, Address dst) {
--- 3075,3085 ----
str(rscratch1, adr);
}
void MacroAssembler::cmpptr(Register src1, Address src2) {
unsigned long offset;
! far_adrp(rscratch1, src2, offset);
ldr(rscratch1, Address(rscratch1, offset));
cmp(src1, rscratch1);
}
void MacroAssembler::store_check(Register obj, Address dst) {
*** 3099,3109 ****
assert(CardTableModRefBS::dirty_card_val() == 0, "must be");
{
ExternalAddress cardtable((address) ct->byte_map_base);
unsigned long offset;
! adrp(rscratch1, cardtable, offset);
assert(offset == 0, "byte_map_base is misaligned");
}
if (UseCondCardMark) {
Label L_already_dirty;
--- 3103,3113 ----
assert(CardTableModRefBS::dirty_card_val() == 0, "must be");
{
ExternalAddress cardtable((address) ct->byte_map_base);
unsigned long offset;
! far_adrp(rscratch1, cardtable, offset);
assert(offset == 0, "byte_map_base is misaligned");
}
if (UseCondCardMark) {
Label L_already_dirty;
*** 3594,3604 ****
const Register card_addr = tmp;
lsr(card_addr, store_addr, CardTableModRefBS::card_shift);
unsigned long offset;
! adrp(tmp2, cardtable, offset);
// get the address of the card
add(card_addr, card_addr, tmp2);
ldrb(tmp2, Address(card_addr, offset));
cmpw(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val());
--- 3598,3608 ----
const Register card_addr = tmp;
lsr(card_addr, store_addr, CardTableModRefBS::card_shift);
unsigned long offset;
! far_adrp(tmp2, cardtable, offset);
// get the address of the card
add(card_addr, card_addr, tmp2);
ldrb(tmp2, Address(card_addr, offset));
cmpw(tmp2, (int)G1SATBCardTableModRefBS::g1_young_card_val());
*** 3781,3791 ****
strw(t1, Address(top, arrayOopDesc::length_offset_in_bytes()));
// set klass to intArrayKlass
{
unsigned long offset;
// dubious reloc why not an oop reloc?
! adrp(rscratch1, ExternalAddress((address)Universe::intArrayKlassObj_addr()),
offset);
ldr(t1, Address(rscratch1, offset));
}
// store klass last. concurrent gcs assumes klass length is valid if
// klass field is not null.
--- 3785,3795 ----
strw(t1, Address(top, arrayOopDesc::length_offset_in_bytes()));
// set klass to intArrayKlass
{
unsigned long offset;
// dubious reloc why not an oop reloc?
! far_adrp(rscratch1, ExternalAddress((address)Universe::intArrayKlassObj_addr()),
offset);
ldr(t1, Address(rscratch1, offset));
}
// store klass last. concurrent gcs assumes klass length is valid if
// klass field is not null.
*** 3846,3865 ****
Register heap_end = rscratch2;
Label retry;
bind(retry);
{
unsigned long offset;
! adrp(rscratch1, ExternalAddress((address) Universe::heap()->end_addr()), offset);
ldr(heap_end, Address(rscratch1, offset));
}
ExternalAddress heap_top((address) Universe::heap()->top_addr());
// Get the current top of the heap
{
unsigned long offset;
! adrp(rscratch1, heap_top, offset);
// Use add() here after ARDP, rather than lea().
// lea() does not generate anything if its offset is zero.
// However, relocs expect to find either an ADD or a load/store
// insn after an ADRP. add() always generates an ADD insn, even
// for add(Rn, Rn, 0).
--- 3850,3869 ----
Register heap_end = rscratch2;
Label retry;
bind(retry);
{
unsigned long offset;
! far_adrp(rscratch1, ExternalAddress((address) Universe::heap()->end_addr()), offset);
ldr(heap_end, Address(rscratch1, offset));
}
ExternalAddress heap_top((address) Universe::heap()->top_addr());
// Get the current top of the heap
{
unsigned long offset;
! far_adrp(rscratch1, heap_top, offset);
// Use add() here after ARDP, rather than lea().
// lea() does not generate anything if its offset is zero.
// However, relocs expect to find either an ADD or a load/store
// insn after an ADRP. add() always generates an ADD insn, even
// for add(Rn, Rn, 0).
*** 3946,3956 ****
}
address MacroAssembler::read_polling_page(Register r, address page, relocInfo::relocType rtype) {
unsigned long off;
! adrp(r, Address(page, rtype), off);
InstructionMark im(this);
code_section()->relocate(inst_mark(), rtype);
ldrw(zr, Address(r, off));
return inst_mark();
}
--- 3950,3960 ----
}
address MacroAssembler::read_polling_page(Register r, address page, relocInfo::relocType rtype) {
unsigned long off;
! far_adrp(r, Address(page, rtype), off);
InstructionMark im(this);
code_section()->relocate(inst_mark(), rtype);
ldrw(zr, Address(r, off));
return inst_mark();
}
*** 3960,3987 ****
code_section()->relocate(inst_mark(), rtype);
ldrw(zr, Address(r, 0));
return inst_mark();
}
! void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) {
! relocInfo::relocType rtype = dest.rspec().reloc()->type();
! if (uabs(pc() - dest.target()) >= (1LL << 32)) {
! guarantee(rtype == relocInfo::none
! || rtype == relocInfo::external_word_type
! || rtype == relocInfo::poll_type
! || rtype == relocInfo::poll_return_type,
! "can only use a fixed address with an ADRP");
! // Out of range. This doesn't happen very often, but we have to
! // handle it
! mov(reg1, dest);
! byte_offset = 0;
} else {
InstructionMark im(this);
code_section()->relocate(inst_mark(), dest.rspec());
byte_offset = (uint64_t)dest.target() & 0xfff;
_adrp(reg1, dest.target());
- }
}
void MacroAssembler::build_frame(int framesize) {
assert(framesize > 0, "framesize must be > 0");
if (framesize < ((1 << 9) + 2 * wordSize)) {
--- 3964,4000 ----
code_section()->relocate(inst_mark(), rtype);
ldrw(zr, Address(r, 0));
return inst_mark();
}
! void MacroAssembler::far_adrp(Register reg1, const Address &dest, unsigned long &byte_offset) {
! uint64_t pc_page = (uint64_t)pc() >> 12;
! uint64_t adr_page = (uint64_t)dest.target() >> 12;
! int64_t offset = adr_page - pc_page;
!
! InstructionMark im(this);
! code_section()->relocate(inst_mark(), dest.rspec());
! if (offset >= -(1<<20) && offset < (1<<20)) {
! _adrp(reg1, dest.target());
! nop();
} else {
+ offset = (offset & ((1<<20)-1)) << 12;
+ _adrp(reg1, pc()+offset);
+ movk(reg1, ((uint64_t)dest.target() >> 32) & 0xffff, 32);
+ }
+ byte_offset = (uint64_t)dest.target() & 0xfff;
+ }
+
+ void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) {
+ uint64_t pc_page = (uint64_t)pc() >> 12;
+ uint64_t adr_page = (uint64_t)dest.target() >> 12;
+ int64_t offset = adr_page - pc_page;
+ guarantee(offset >= -(1<<20) && offset < (1<<20), "adrp out of range, use far_adrp");
InstructionMark im(this);
code_section()->relocate(inst_mark(), dest.rspec());
byte_offset = (uint64_t)dest.target() & 0xfff;
_adrp(reg1, dest.target());
}
void MacroAssembler::build_frame(int framesize) {
assert(framesize > 0, "framesize must be > 0");
if (framesize < ((1 << 9) + 2 * wordSize)) {
< prev index next >