forked from OSchip/llvm-project
Handle expressions of the form _GLOBAL_OFFSET_TABLE_-symbol the same way gas
does. The _GLOBAL_OFFSET_TABLE_ is still magical in that we get a R_386_GOTPC, but it doesn't change the immediate in the same way as when the expression has no right hand side symbol. llvm-svn: 146311
This commit is contained in:
parent
3bffb085f4
commit
c7f355b8e1
llvm
|
@ -169,23 +169,36 @@ static bool Is32BitMemOperand(const MCInst &MI, unsigned Op) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// StartsWithGlobalOffsetTable - Return true for the simple cases where this
|
||||
/// expression starts with _GLOBAL_OFFSET_TABLE_. This is a needed to support
|
||||
/// PIC on ELF i386 as that symbol is magic. We check only simple case that
|
||||
/// StartsWithGlobalOffsetTable - Check if this expression starts with
|
||||
/// _GLOBAL_OFFSET_TABLE_ and if it is of the form
|
||||
/// _GLOBAL_OFFSET_TABLE_-symbol. This is needed to support PIC on ELF
|
||||
/// i386 as _GLOBAL_OFFSET_TABLE_ is magical. We check only simple case that
|
||||
/// are know to be used: _GLOBAL_OFFSET_TABLE_ by itself or at the start
|
||||
/// of a binary expression.
|
||||
static bool StartsWithGlobalOffsetTable(const MCExpr *Expr) {
|
||||
enum GlobalOffsetTableExprKind {
|
||||
GOT_None,
|
||||
GOT_Normal,
|
||||
GOT_SymDiff
|
||||
};
|
||||
static GlobalOffsetTableExprKind
|
||||
StartsWithGlobalOffsetTable(const MCExpr *Expr) {
|
||||
const MCExpr *RHS = 0;
|
||||
if (Expr->getKind() == MCExpr::Binary) {
|
||||
const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Expr);
|
||||
Expr = BE->getLHS();
|
||||
RHS = BE->getRHS();
|
||||
}
|
||||
|
||||
if (Expr->getKind() != MCExpr::SymbolRef)
|
||||
return false;
|
||||
return GOT_None;
|
||||
|
||||
const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr*>(Expr);
|
||||
const MCSymbol &S = Ref->getSymbol();
|
||||
return S.getName() == "_GLOBAL_OFFSET_TABLE_";
|
||||
if (S.getName() != "_GLOBAL_OFFSET_TABLE_")
|
||||
return GOT_None;
|
||||
if (RHS && RHS->getKind() == MCExpr::SymbolRef)
|
||||
return GOT_SymDiff;
|
||||
return GOT_Normal;
|
||||
}
|
||||
|
||||
void X86MCCodeEmitter::
|
||||
|
@ -209,13 +222,16 @@ EmitImmediate(const MCOperand &DispOp, unsigned Size, MCFixupKind FixupKind,
|
|||
|
||||
// If we have an immoffset, add it to the expression.
|
||||
if ((FixupKind == FK_Data_4 ||
|
||||
FixupKind == MCFixupKind(X86::reloc_signed_4byte)) &&
|
||||
StartsWithGlobalOffsetTable(Expr)) {
|
||||
FixupKind == MCFixupKind(X86::reloc_signed_4byte))) {
|
||||
GlobalOffsetTableExprKind Kind = StartsWithGlobalOffsetTable(Expr);
|
||||
if (Kind != GOT_None) {
|
||||
assert(ImmOffset == 0);
|
||||
|
||||
FixupKind = MCFixupKind(X86::reloc_global_offset_table);
|
||||
if (Kind == GOT_Normal)
|
||||
ImmOffset = CurByte;
|
||||
}
|
||||
}
|
||||
|
||||
// If the fixup is pc-relative, we need to bias the value to be relative to
|
||||
// the start of the field, not the end of the field.
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
addl $_GLOBAL_OFFSET_TABLE_, %ebx
|
||||
leal _GLOBAL_OFFSET_TABLE_(%ebx), %ebx
|
||||
|
||||
// But not in this case
|
||||
foo:
|
||||
addl _GLOBAL_OFFSET_TABLE_-foo,%ebx
|
||||
|
||||
// CHECK: ('sh_name', 0x00000005) # '.text'
|
||||
// CHECK-NEXT: ('sh_type',
|
||||
// CHECK-NEXT: ('sh_flags',
|
||||
|
@ -16,4 +20,4 @@
|
|||
// CHECK-NEXT: ('sh_info',
|
||||
// CHECK-NEXT: ('sh_addralign',
|
||||
// CHECK-NEXT: ('sh_entsize',
|
||||
// CHECK-NEXT: ('_section_data', '81c30200 00008d9b 02000000')
|
||||
// CHECK-NEXT: ('_section_data', '81c30200 00008d9b 02000000 031d0200 0000')
|
||||
|
|
Loading…
Reference in New Issue