[WebAssembly] Add new explicit relocation types for PIC relocations

See https://github.com/WebAssembly/tool-conventions/pull/106

Differential Revision: https://reviews.llvm.org/D59907

llvm-svn: 357710
This commit is contained in:
Sam Clegg 2019-04-04 17:43:50 +00:00
parent 3e787f751f
commit 50f199c1ba
12 changed files with 190 additions and 49 deletions

View File

@ -2,14 +2,16 @@
#error "WASM_RELOC must be defined"
#endif
WASM_RELOC(R_WASM_FUNCTION_INDEX_LEB, 0)
WASM_RELOC(R_WASM_TABLE_INDEX_SLEB, 1)
WASM_RELOC(R_WASM_TABLE_INDEX_I32, 2)
WASM_RELOC(R_WASM_MEMORY_ADDR_LEB, 3)
WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB, 4)
WASM_RELOC(R_WASM_MEMORY_ADDR_I32, 5)
WASM_RELOC(R_WASM_TYPE_INDEX_LEB, 6)
WASM_RELOC(R_WASM_GLOBAL_INDEX_LEB, 7)
WASM_RELOC(R_WASM_FUNCTION_OFFSET_I32, 8)
WASM_RELOC(R_WASM_SECTION_OFFSET_I32, 9)
WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10)
WASM_RELOC(R_WASM_FUNCTION_INDEX_LEB, 0)
WASM_RELOC(R_WASM_TABLE_INDEX_SLEB, 1)
WASM_RELOC(R_WASM_TABLE_INDEX_I32, 2)
WASM_RELOC(R_WASM_MEMORY_ADDR_LEB, 3)
WASM_RELOC(R_WASM_MEMORY_ADDR_SLEB, 4)
WASM_RELOC(R_WASM_MEMORY_ADDR_I32, 5)
WASM_RELOC(R_WASM_TYPE_INDEX_LEB, 6)
WASM_RELOC(R_WASM_GLOBAL_INDEX_LEB, 7)
WASM_RELOC(R_WASM_FUNCTION_OFFSET_I32, 8)
WASM_RELOC(R_WASM_SECTION_OFFSET_I32, 9)
WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10)
WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11)
WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12)

View File

@ -284,7 +284,9 @@ public:
VK_Hexagon_IE,
VK_Hexagon_IE_GOT,
VK_WebAssembly_TYPEINDEX,// Reference to a symbol's type (signature)
VK_WASM_TYPEINDEX, // Reference to a symbol's type (signature)
VK_WASM_MBREL, // Memory address relative to memory base
VK_WASM_TBREL, // Table index relative to table bare
VK_AMDGPU_GOTPCREL32_LO, // symbol@gotpcrel32@lo
VK_AMDGPU_GOTPCREL32_HI, // symbol@gotpcrel32@hi

View File

@ -302,7 +302,9 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
case VK_Hexagon_LD_PLT: return "LDPLT";
case VK_Hexagon_IE: return "IE";
case VK_Hexagon_IE_GOT: return "IEGOT";
case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX";
case VK_WASM_TYPEINDEX: return "TYPEINDEX";
case VK_WASM_MBREL: return "MBREL";
case VK_WASM_TBREL: return "TBREL";
case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
case VK_AMDGPU_REL32_LO: return "rel32@lo";
@ -415,7 +417,9 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
.Case("lo8", VK_AVR_LO8)
.Case("hi8", VK_AVR_HI8)
.Case("hlo8", VK_AVR_HLO8)
.Case("typeindex", VK_WebAssembly_TYPEINDEX)
.Case("typeindex", VK_WASM_TYPEINDEX)
.Case("tbrel", VK_WASM_TBREL)
.Case("mbrel", VK_WASM_MBREL)
.Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
.Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
.Case("rel32@lo", VK_AMDGPU_REL32_LO)

View File

@ -151,6 +151,7 @@ struct WasmRelocationEntry {
switch (Type) {
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_MEMORY_ADDR_SLEB:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
case wasm::R_WASM_MEMORY_ADDR_I32:
case wasm::R_WASM_FUNCTION_OFFSET_I32:
case wasm::R_WASM_SECTION_OFFSET_I32:
@ -580,6 +581,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
}
switch (RelEntry.Type) {
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_I32: {
// Provisional value is table address of the resolved symbol itself
@ -604,6 +606,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
}
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_MEMORY_ADDR_I32:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
case wasm::R_WASM_MEMORY_ADDR_SLEB: {
// Provisional value is address of the global
const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
@ -698,7 +701,9 @@ void WasmObjectWriter::applyRelocations(
writeI32(Stream, Value, Offset);
break;
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
case wasm::R_WASM_MEMORY_ADDR_SLEB:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
writePatchableSLEB(Stream, Value, Offset);
break;
default:

View File

@ -767,6 +767,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
case wasm::R_WASM_FUNCTION_INDEX_LEB:
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_I32:
case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation function index",
object_error::parse_failed);
@ -793,6 +794,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_MEMORY_ADDR_SLEB:
case wasm::R_WASM_MEMORY_ADDR_I32:
case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
if (!isValidDataSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation data index",
object_error::parse_failed);

View File

@ -90,9 +90,21 @@ namespace WebAssemblyII {
enum TOF {
MO_NO_FLAG = 0,
// Address of data symbol via a wasm global. This adds a level of indirection
// similar to the GOT on native platforms.
// On a symbol operand this indicates that the immediate is a wasm global
// index. The value of the wasm global will be set to the symbol address at
// runtime. This adds a level of indirection similar to the GOT on native
// platforms.
MO_GOT,
// On a symbol operand this indicates that the immediate is the symbol
// address relative the __memory_base wasm global.
// Only applicable to data symbols.
MO_MEMORY_BASE_REL,
// On a symbol operand this indicates that the immediate is the symbol
// address relative the __table_base wasm global.
// Only applicable to function symbols.
MO_TABLE_BASE_REL,
};
} // end namespace WebAssemblyII

View File

@ -42,14 +42,6 @@ private:
WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
: MCWasmObjectTargetWriter(Is64Bit) {}
static bool isFunctionSignatureRef(const MCSymbolRefExpr *Ref) {
return Ref->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
}
static bool isGOTRef(const MCSymbolRefExpr *Ref) {
return Ref->getKind() == MCSymbolRefExpr::VK_GOT;
}
static const MCSection *getFixupSection(const MCExpr *Expr) {
if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
if (SyExp->getSymbol().isInSection())
@ -75,6 +67,23 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
assert(RefA);
auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
switch (Modifier) {
case MCSymbolRefExpr::VK_GOT:
return wasm::R_WASM_GLOBAL_INDEX_LEB;
case MCSymbolRefExpr::VK_WASM_TBREL:
assert(SymA.isFunction());
return wasm::R_WASM_TABLE_INDEX_REL_SLEB;
case MCSymbolRefExpr::VK_WASM_MBREL:
assert(SymA.isData());
return wasm::R_WASM_MEMORY_ADDR_REL_SLEB;
case MCSymbolRefExpr::VK_WASM_TYPEINDEX:
return wasm::R_WASM_TYPE_INDEX_LEB;
default:
break;
}
switch (unsigned(Fixup.getKind())) {
case WebAssembly::fixup_sleb128_i32:
if (SymA.isFunction())
@ -83,14 +92,10 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
case WebAssembly::fixup_sleb128_i64:
llvm_unreachable("fixup_sleb128_i64 not implemented yet");
case WebAssembly::fixup_uleb128_i32:
if (SymA.isGlobal() || isGOTRef(RefA))
if (SymA.isGlobal())
return wasm::R_WASM_GLOBAL_INDEX_LEB;
if (SymA.isFunction()) {
if (isFunctionSignatureRef(RefA))
return wasm::R_WASM_TYPE_INDEX_LEB;
else
return wasm::R_WASM_FUNCTION_INDEX_LEB;
}
if (SymA.isFunction())
return wasm::R_WASM_FUNCTION_INDEX_LEB;
if (SymA.isEvent())
return wasm::R_WASM_EVENT_INDEX_LEB;
return wasm::R_WASM_MEMORY_ADDR_LEB;

View File

@ -1003,17 +1003,22 @@ SDValue WebAssemblyTargetLowering::LowerGlobalAddress(SDValue Op,
MachineFunction &MF = DAG.getMachineFunction();
MVT PtrVT = getPointerTy(MF.getDataLayout());
const char *BaseName;
if (GV->getValueType()->isFunctionTy())
if (GV->getValueType()->isFunctionTy()) {
BaseName = MF.createExternalSymbolName("__table_base");
else
OperandFlags = WebAssemblyII::MO_TABLE_BASE_REL;
}
else {
BaseName = MF.createExternalSymbolName("__memory_base");
OperandFlags = WebAssemblyII::MO_MEMORY_BASE_REL;
}
SDValue BaseAddr =
DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
DAG.getTargetExternalSymbol(BaseName, PtrVT));
SDValue SymAddr = DAG.getNode(
WebAssemblyISD::WrapperPIC, DL, VT,
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset()));
DAG.getTargetGlobalAddress(GA->getGlobal(), DL, VT, GA->getOffset(),
OperandFlags));
return DAG.getNode(ISD::ADD, DL, VT, BaseAddr, SymAddr);
} else {

View File

@ -122,16 +122,31 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
MCSymbol *Sym) const {
bool isGOT = MO.getTargetFlags() == WebAssemblyII::MO_GOT;
MCSymbolRefExpr::VariantKind Kind =
isGOT ? MCSymbolRefExpr::VK_GOT : MCSymbolRefExpr::VK_None;
MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VK_None;
unsigned TargetFlags = MO.getTargetFlags();
switch (TargetFlags) {
case WebAssemblyII::MO_NO_FLAG:
break;
case WebAssemblyII::MO_GOT:
Kind = MCSymbolRefExpr::VK_GOT;
break;
case WebAssemblyII::MO_MEMORY_BASE_REL:
Kind = MCSymbolRefExpr::VK_WASM_MBREL;
break;
case WebAssemblyII::MO_TABLE_BASE_REL:
Kind = MCSymbolRefExpr::VK_WASM_TBREL;
break;
default:
llvm_unreachable("Unknown target flag on GV operand");
}
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, Kind, Ctx);
if (MO.getOffset() != 0) {
const auto *WasmSym = cast<MCSymbolWasm>(Sym);
if (isGOT)
if (TargetFlags == WebAssemblyII::MO_GOT)
report_fatal_error("GOT symbol references do not support offsets");
if (WasmSym->isFunction())
report_fatal_error("Function addresses with offsets not supported");
if (WasmSym->isGlobal())
@ -217,7 +232,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
const MCExpr *Expr = MCSymbolRefExpr::create(
WasmSym, MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX, Ctx);
WasmSym, MCSymbolRefExpr::VK_WASM_TYPEINDEX, Ctx);
MCOp = MCOperand::createExpr(Expr);
break;
}

View File

@ -5,14 +5,14 @@ target triple = "wasm32-unknown-unknown"
declare i32 @foo()
declare i32 @bar()
declare hidden i32 @hidden_function();
declare hidden i32 @hidden_function()
@indirect_func = global i32 ()* @foo
define void @call_indirect_func() {
; CHECK-LABEL: call_indirect_func:
; CHECK: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, indirect_func{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, indirect_func@MBREL{{$}}
; CHECK-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; CHECK-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
; CHECK-NEXT: i32.call_indirect $push[[L4:[0-9]+]]=, $pop[[L3]]{{$}}
@ -43,7 +43,7 @@ define i8* @get_function_address() {
define i8* @get_function_address_hidden() {
; CHECK-LABEL: get_function_address_hidden:
; CHECK: global.get $push[[L0:[0-9]+]]=, __table_base{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_function{{$}}
; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_function@TBREL{{$}}
; CHECK-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; CHECK-NEXT: return $pop[[L2]]{{$}}
; CHECK-NEXT: end_function{{$}}

View File

@ -21,7 +21,7 @@ declare i32 @foo();
define i32 @load_hidden_global() {
; CHECK-LABEL: load_hidden_global:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
@ -36,7 +36,7 @@ define i32 @load_hidden_global() {
define i32 @load_hidden_global_offset() {
; CHECK-LABEL: load_hidden_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1:[0-9]+]]{{$}}
; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
@ -56,7 +56,7 @@ define i32 @load_hidden_global_offset() {
define void @store_hidden_global(i32 %n) {
; CHECK-LABEL: store_hidden_global:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global@MBREL{{$}}
; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.store 0($pop[[L2]]), $0{{$}}
@ -71,7 +71,7 @@ define void @store_hidden_global(i32 %n) {
define void @store_hidden_global_offset(i32 %n) {
; CHECK-LABEL: store_hidden_global_offset:
; PIC: global.get $push[[L0:[0-9]+]]=, __memory_base{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array{{$}}
; PIC-NEXT: i32.const $push[[L1:[0-9]+]]=, hidden_global_array@MBREL{{$}}
; PIC-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
; PIC-NEXT: i32.const $push[[L3:[0-9]+]]=, 20{{$}}
; PIC-NEXT: i32.add $push[[L4:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}

View File

@ -16,6 +16,32 @@ load_default_func:
i32.load 0
end_function
load_hidden_data:
.functype load_hidden_data () -> (i32)
global.get __memory_base
i32.const .L.hidden_data@MBREL
i32.add
end_function
load_hidden_func:
.functype load_hidden_func () -> (i32)
global.get __table_base
i32.const hidden_func@TBREL
i32.add
end_function
hidden_func:
.functype hidden_func () -> (i32)
i32.const 0
end_function
.section .rodata.hidden_data,"",@
.L.hidden_data:
.int8 100
.size .L.hidden_data, 1
#.hidden hidden_func
#.hidden hidden_data
.size default_data, 4
.functype default_func () -> (i32)
@ -34,7 +60,7 @@ load_default_func:
# CHECK-NEXT: Field: __linear_memory
# CHECK-NEXT: Kind: MEMORY
# CHECK-NEXT: Memory:
# CHECK-NEXT: Initial: 0x00000000
# CHECK-NEXT: Initial: 0x00000001
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: __indirect_function_table
# CHECK-NEXT: Kind: TABLE
@ -57,7 +83,7 @@ load_default_func:
# CHECK-NEXT: GlobalType: I32
# CHECK-NEXT: GlobalMutable: true
# CHECK-NEXT: - Type: FUNCTION
# CHECK-NEXT: FunctionTypes: [ 0, 0 ]
# CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ]
# CHECK-NEXT: - Type: CODE
# CHECK-NEXT: Relocations:
# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
@ -66,6 +92,18 @@ load_default_func:
# CHECK-NEXT: - Type: R_WASM_GLOBAL_INDEX_LEB
# CHECK-NEXT: Index: 3
# CHECK-NEXT: Offset: 0x00000010
# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
# CHECK-NEXT: Index: 5
# CHECK-NEXT: Offset: 0x0000001C
# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_REL_SLEB
# CHECK-NEXT: Index: 6
# CHECK-NEXT: Offset: 0x00000022
# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
# CHECK-NEXT: Index: 8
# CHECK-NEXT: Offset: 0x0000002C
# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_REL_SLEB
# CHECK-NEXT: Index: 9
# CHECK-NEXT: Offset: 0x00000032
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Locals: []
@ -73,6 +111,23 @@ load_default_func:
# CHECK-NEXT: - Index: 2
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 2381808080002800000B
# CHECK-NEXT: - Index: 3
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 2380808080004180808080006A0B
# CHECK-NEXT: - Index: 4
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 2380808080004180808080006A0B
# CHECK-NEXT: - Index: 5
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 41000B
# CHECK-NEXT: - Type: DATA
# CHECK-NEXT: Segments:
# CHECK-NEXT: - SectionOffset: 6
# CHECK-NEXT: InitFlags: 0
# CHECK-NEXT: Offset:
# CHECK-NEXT: Opcode: I32_CONST
# CHECK-NEXT: Value: 0
# CHECK-NEXT: Content: '64'
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: linking
# CHECK-NEXT: Version: 2
@ -96,4 +151,38 @@ load_default_func:
# CHECK-NEXT: Name: default_func
# CHECK-NEXT: Flags: [ UNDEFINED ]
# CHECK-NEXT: Function: 0
# CHECK-NEXT: - Index: 4
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: load_hidden_data
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 3
# CHECK-NEXT: - Index: 5
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: __memory_base
# CHECK-NEXT: Flags: [ UNDEFINED ]
# CHECK-NEXT: - Index: 6
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: .L.hidden_data
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Segment: 0
# CHECK-NEXT: Size: 1
# CHECK-NEXT: - Index: 7
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: load_hidden_func
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 4
# CHECK-NEXT: - Index: 8
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: __table_base
# CHECK-NEXT: Flags: [ UNDEFINED ]
# CHECK-NEXT: - Index: 9
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: hidden_func
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 5
# CHECK-NEXT: SegmentInfo:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Name: .rodata.hidden_data
# CHECK-NEXT: Alignment: 0
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: ...