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:
Rafael Espindola 2011-12-10 02:28:43 +00:00
parent 3bffb085f4
commit c7f355b8e1
2 changed files with 32 additions and 12 deletions
llvm
lib/Target/X86/MCTargetDesc
test/MC/ELF

View File

@ -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.

View File

@ -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')