1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00

[WebAssembly] call_indirect issues table number relocs

This patch changes to make call_indirect explicitly refer to the
corresponding function table, residualizing TABLE_NUMBER relocs against
it.

With this change, wasm-ld now sees all references to tables, and can
link multiple tables.

Differential Revision: https://reviews.llvm.org/D90948
This commit is contained in:
Andy Wingo 2021-01-05 11:05:18 +01:00
parent 2b1fcde239
commit 6ddb7e7525
16 changed files with 204 additions and 81 deletions

View File

@ -405,13 +405,6 @@ void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
const MCAsmLayout &Layout) {
// As a stopgap measure until call_indirect instructions start explicitly
// referencing the indirect function table via TABLE_NUMBER relocs, ensure
// that the indirect function table import makes it to the output if anything
// in the compilation unit has caused it to be present.
if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table"))
Asm.registerSymbol(*Sym);
// Build a map of sections to the function that defines them, for use
// in recordRelocation.
for (const MCSymbol &S : Asm.symbols()) {

View File

@ -472,6 +472,15 @@ public:
WebAssemblyOperand::IntOp{static_cast<int64_t>(BT)}));
}
void addFunctionTableOperand(OperandVector &Operands, StringRef TableName,
SMLoc StartLoc, SMLoc EndLoc) {
MCSymbolWasm *Sym = GetOrCreateFunctionTableSymbol(getContext(), TableName);
auto *Val = MCSymbolRefExpr::create(Sym, getContext());
Operands.push_back(std::make_unique<WebAssemblyOperand>(
WebAssemblyOperand::Symbol, StartLoc, EndLoc,
WebAssemblyOperand::SymOp{Val}));
}
bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) override {
// Note: Name does NOT point into the sourcecode, but to a local, so
@ -508,6 +517,7 @@ public:
bool ExpectBlockType = false;
bool ExpectFuncType = false;
bool ExpectHeapType = false;
bool ExpectFunctionTable = false;
if (Name == "block") {
push(Block);
ExpectBlockType = true;
@ -547,15 +557,7 @@ public:
return true;
} else if (Name == "call_indirect" || Name == "return_call_indirect") {
ExpectFuncType = true;
// Ensure that the object file has a __indirect_function_table import, as
// we call_indirect against it.
auto &Ctx = getStreamer().getContext();
MCSymbolWasm *Sym =
GetOrCreateFunctionTableSymbol(Ctx, "__indirect_function_table");
// Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
// it as NO_STRIP so as to ensure that the indirect function table makes
// it to linked output.
Sym->setNoStrip();
ExpectFunctionTable = true;
} else if (Name == "ref.null") {
ExpectHeapType = true;
}
@ -571,7 +573,7 @@ public:
return true;
// Got signature as block type, don't need more
ExpectBlockType = false;
auto &Ctx = getStreamer().getContext();
auto &Ctx = getContext();
// The "true" here will cause this to be a nameless symbol.
MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true);
auto *WasmSym = cast<MCSymbolWasm>(Sym);
@ -583,6 +585,16 @@ public:
Operands.push_back(std::make_unique<WebAssemblyOperand>(
WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(),
WebAssemblyOperand::SymOp{Expr}));
// Allow additional operands after the signature, notably for
// call_indirect against a named table.
if (Lexer.isNot(AsmToken::EndOfStatement)) {
if (expect(AsmToken::Comma, ","))
return true;
if (Lexer.is(AsmToken::EndOfStatement)) {
return error("Unexpected trailing comma");
}
}
}
while (Lexer.isNot(AsmToken::EndOfStatement)) {
@ -608,8 +620,11 @@ public:
WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(),
WebAssemblyOperand::IntOp{static_cast<int64_t>(HeapType)}));
Parser.Lex();
} else if (ExpectFunctionTable) {
addFunctionTableOperand(Operands, Id.getString(), Id.getLoc(),
Id.getEndLoc());
Parser.Lex();
} else {
// Assume this identifier is a label.
const MCExpr *Val;
SMLoc End;
if (Parser.parseExpression(Val, End))
@ -674,6 +689,11 @@ public:
// Support blocks with no operands as default to void.
addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void);
}
if (ExpectFunctionTable && Operands.size() == 2) {
// If call_indirect doesn't specify a target table, supply one.
addFunctionTableOperand(Operands, "__indirect_function_table", NameLoc,
SMLoc::getFromPointer(Name.end()));
}
Parser.Lex();
return false;
}

View File

@ -68,7 +68,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) {
if (MI->getOpcode() == WebAssembly::CALL_INDIRECT &&
I - Start == NumVariadicDefs) {
// Skip type and flags arguments when printing for tests
// Skip type and table arguments when printing for tests.
++I;
continue;
}

View File

@ -401,6 +401,16 @@ inline bool isCallIndirect(unsigned Opc) {
}
}
inline bool isRetCallIndirect(unsigned Opc) {
switch (Opc) {
case WebAssembly::RET_CALL_INDIRECT:
case WebAssembly::RET_CALL_INDIRECT_S:
return true;
default:
return false;
}
}
inline bool isBrTable(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::BR_TABLE_I32:

View File

@ -869,18 +869,11 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
if (IsDirect) {
MIB.addGlobalAddress(Func);
} else {
// Add placeholders for the type index and immediate flags
// Placehoder for the type index.
MIB.addImm(0);
MIB.addImm(0);
// Ensure that the object file has a __indirect_function_table import, as we
// call_indirect against it.
MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol(
MF->getMMI().getContext(), "__indirect_function_table");
// Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
// it as NO_STRIP so as to ensure that the indirect function table makes it
// to linked output.
Sym->setNoStrip();
// The table into which this call_indirect indexes.
MIB.addSym(WebAssembly::getOrCreateFunctionTableSymbol(
MF->getMMI().getContext(), "__indirect_function_table"));
}
for (unsigned ArgReg : Args)

View File

@ -475,19 +475,12 @@ static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults,
for (auto Def : CallResults.defs())
MIB.add(Def);
// Add placeholders for the type index and immediate flags
if (IsIndirect) {
// Placehoder for the type index.
MIB.addImm(0);
MIB.addImm(0);
// Ensure that the object file has a __indirect_function_table import, as we
// call_indirect against it.
MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol(
MF.getContext(), "__indirect_function_table");
// Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark
// it as NO_STRIP so as to ensure that the indirect function table makes it
// to linked output.
Sym->setNoStrip();
// The table into which this call_indirect indexes.
MIB.addSym(WebAssembly::getOrCreateFunctionTableSymbol(
MF.getContext(), "__indirect_function_table"));
}
for (auto Use : CallParams.uses())

View File

@ -48,6 +48,9 @@ defm RET_CALL_RESULTS :
I<(outs), (ins variable_ops), (outs), (ins), [],
"return_call_results", "return_call_results", -1>;
// Note that instructions with variable_ops have custom printers in
// WebAssemblyInstPrinter.cpp.
let variadicOpsAreDefs = 1 in
defm CALL :
I<(outs), (ins function32_op:$callee, variable_ops),
@ -56,9 +59,12 @@ defm CALL :
let variadicOpsAreDefs = 1 in
defm CALL_INDIRECT :
I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops),
(outs), (ins TypeIndex:$type, i32imm:$flags), [],
"call_indirect", "call_indirect\t$type", 0x11>;
I<(outs),
(ins TypeIndex:$type, table32_op:$table, variable_ops),
(outs),
(ins TypeIndex:$type, table32_op:$table),
[],
"call_indirect", "call_indirect\t$type, $table", 0x11>;
let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in
defm RET_CALL :
@ -69,9 +75,9 @@ defm RET_CALL :
let isReturn = 1 in
defm RET_CALL_INDIRECT :
I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops),
(outs), (ins TypeIndex:$type, i32imm:$flags), [],
"return_call_indirect\t", "return_call_indirect\t$type",
I<(outs), (ins TypeIndex:$type, table32_op:$table, variable_ops),
(outs), (ins TypeIndex:$type, table32_op:$table), [],
"return_call_indirect\t", "return_call_indirect\t$type, $table",
0x13>,
Requires<[HasTailCall]>;

View File

@ -161,6 +161,8 @@ MCOperand WebAssemblyMCInstLower::lowerSymbolOperand(const MachineOperand &MO,
report_fatal_error("Global indexes with offsets not supported");
if (WasmSym->isEvent())
report_fatal_error("Event indexes with offsets not supported");
if (WasmSym->isTable())
report_fatal_error("Table indexes with offsets not supported");
Expr = MCBinaryExpr::createAdd(
Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
@ -259,7 +261,7 @@ void WebAssemblyMCInstLower::lower(const MachineInstr *MI,
// return_call_indirect instructions have the return type of the
// caller
if (MI->getOpcode() == WebAssembly::RET_CALL_INDIRECT)
if (WebAssembly::isRetCallIndirect(MI->getOpcode()))
getFunctionReturns(MI, Returns);
MCOp = lowerTypeIndexOperand(std::move(Returns), std::move(Params));

View File

@ -34,14 +34,15 @@ entry:
; CHECK-NEXT: i32.const 1
; CHECK-NEXT: local.get 0
; CHECK-NEXT: i32.wrap_i64
; CHECK-NEXT: call_indirect (i32) -> ()
; CHECK-NEXT: call_indirect (i32) -> (), __indirect_function_table
; CHECK: .functype test () -> ()
; CHECK-NEXT: i64.const bar
; CHECK-NEXT: call foo
; Check we're emitting a 64-bit reloc for `i64.const bar` and the global.
; Check we're emitting a 64-bit relocs for the call_indirect, the
; `i64.const bar` reference in code, and the global.
; YAML: Memory:
; YAML-NEXT: Flags: [ IS_64 ]
@ -50,7 +51,10 @@ entry:
; YAML: - Type: CODE
; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
; YAML-NEXT: Index: 0
; YAML-NEXT: Offset: 0x16
; YAML-NEXT: Offset: 0x1A
; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64
; YAML-NEXT: Index: 0
; YAML-NEXT: Offset: 0x2D
; YAML: - Type: DATA
; YAML: - Type: R_WASM_TABLE_INDEX_I64

View File

@ -57,7 +57,7 @@ define %pair @pair_call_return() {
; CHECK-LABEL: pair_call_indirect:
; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64)
; CHECK-NEXT: local.get 0{{$}}
; CHECK-NEXT: call_indirect () -> (i32, i64){{$}}
; CHECK-NEXT: call_indirect () -> (i32, i64), __indirect_function_table{{$}}
; CHECK-NEXT: end_function{{$}}
; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
define %pair @pair_call_indirect(%pair()* %f) {

View File

@ -153,7 +153,7 @@ empty_fref_table:
# CHECK-NEXT: i64.const 1234
# CHECK-NEXT: call something2
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: call_indirect (i32, f64) -> ()
# CHECK-NEXT: call_indirect (i32, f64) -> (), __indirect_function_table
# CHECK-NEXT: i32.const 1
# CHECK-NEXT: i32.add
# CHECK-NEXT: local.tee 0

View File

@ -0,0 +1,83 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
test0:
.functype test0 () -> ()
i32.const 42
f64.const 2.5
i32.const 0
call_indirect (i32, f64) -> (), empty_fref_table
end_function
.tabletype empty_fref_table, funcref
empty_fref_table:
# CHECK: .text
# CHECK-LABEL: test0:
# CHECK-NEXT: .functype test0 () -> ()
# CHECK-NEXT: i32.const 42
# CHECK-NEXT: f64.const 0x1.4p1
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: call_indirect (i32, f64) -> (), empty_fref_table
# CHECK-NEXT: end_function
# CHECK: .tabletype empty_fref_table, funcref
# CHECK: empty_fref_table:
# BIN: --- !WASM
# BIN-NEXT: FileHeader:
# BIN-NEXT: Version: 0x1
# BIN-NEXT: Sections:
# BIN-NEXT: - Type: TYPE
# BIN-NEXT: Signatures:
# BIN-NEXT: - Index: 0
# BIN-NEXT: ParamTypes: []
# BIN-NEXT: ReturnTypes: []
# BIN-NEXT: - Index: 1
# BIN-NEXT: ParamTypes:
# BIN-NEXT: - I32
# BIN-NEXT: - F64
# BIN-NEXT: ReturnTypes: []
# BIN-NEXT: - Type: IMPORT
# BIN-NEXT: Imports:
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: __linear_memory
# BIN-NEXT: Kind: MEMORY
# BIN-NEXT: Memory:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Type: FUNCTION
# BIN-NEXT: FunctionTypes: [ 0 ]
# BIN-NEXT: - Type: TABLE
# BIN-NEXT: Tables:
# BIN-NEXT: - Index: 0
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x0
# BIN-NEXT: - Type: CODE
# BIN-NEXT: Relocations:
# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x11
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x16
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 412A440000000000000440410011818080800080808080000B
# BIN-NEXT: - Type: CUSTOM
# BIN-NEXT: Name: linking
# BIN-NEXT: Version: 2
# BIN-NEXT: SymbolTable:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Kind: FUNCTION
# BIN-NEXT: Name: test0
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Function: 0
# BIN-NEXT: - Index: 1
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: empty_fref_table
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Table: 0
# BIN-NEXT: ...

View File

@ -43,18 +43,28 @@ entry:
; CHECK-NEXT: Index: 0x1
; CHECK-NEXT: }
; CHECK-NEXT: Relocation {
; CHECK-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20)
; CHECK-NEXT: Offset: 0x1F
; CHECK-NEXT: Symbol: __indirect_function_table
; CHECK-NEXT: }
; CHECK-NEXT: Relocation {
; CHECK-NEXT: Type: R_WASM_TYPE_INDEX_LEB (6)
; CHECK-NEXT: Offset: 0x24
; CHECK-NEXT: Offset: 0x28
; CHECK-NEXT: Index: 0x0
; CHECK-NEXT: }
; CHECK-NEXT: Relocation {
; CHECK-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0)
; CHECK-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20)
; CHECK-NEXT: Offset: 0x2D
; CHECK-NEXT: Symbol: __indirect_function_table
; CHECK-NEXT: }
; CHECK-NEXT: Relocation {
; CHECK-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0)
; CHECK-NEXT: Offset: 0x35
; CHECK-NEXT: Symbol: c
; CHECK-NEXT: }
; CHECK-NEXT: Relocation {
; CHECK-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0)
; CHECK-NEXT: Offset: 0x34
; CHECK-NEXT: Offset: 0x3C
; CHECK-NEXT: Symbol: d
; CHECK-NEXT: }
; CHECK-NEXT: }

View File

@ -16,7 +16,7 @@ foo1:
foo2:
.functype foo2 () -> ()
# CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13,
# CHECK: return_call_indirect (i32) -> (i32), __indirect_function_table # encoding: [0x13,
# CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0@TYPEINDEX, kind: fixup_uleb128_i32
return_call_indirect (i32) -> (i32)

View File

@ -53,10 +53,13 @@ test0:
# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x4
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x9
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 118180808000000B
# BIN-NEXT: Body: 11818080800080808080000B
# BIN-NEXT: - Type: CUSTOM
# BIN-NEXT: Name: linking
# BIN-NEXT: Version: 2
@ -69,6 +72,6 @@ test0:
# BIN-NEXT: - Index: 1
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Name: __indirect_function_table
# BIN-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
# BIN-NEXT: Flags: [ UNDEFINED ]
# BIN-NEXT: Table: 0
# BIN-NEXT: ...

View File

@ -78,7 +78,7 @@ alias_address:
# CHECK: - Type: TYPE
# CHECK-NEXT: Signatures:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: ParamTypes:
# CHECK-NEXT: ParamTypes: []
# CHECK-NEXT: ReturnTypes:
# CHECK-NEXT: - I32
# CHECK-NEXT: - Type: IMPORT
@ -120,28 +120,34 @@ alias_address:
# CHECK-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
# CHECK-NEXT: Index: 0
# CHECK-NEXT: Offset: 0x24
# CHECK-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# CHECK-NEXT: Index: 6
# CHECK-NEXT: Offset: 0x29
# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB
# CHECK-NEXT: Index: 7
# CHECK-NEXT: Offset: 0x31
# CHECK-NEXT: Index: 8
# CHECK-NEXT: Offset: 0x35
# CHECK-NEXT: - Type: R_WASM_TYPE_INDEX_LEB
# CHECK-NEXT: Index: 0
# CHECK-NEXT: Offset: 0x37
# CHECK-NEXT: Offset: 0x3B
# CHECK-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# CHECK-NEXT: Index: 6
# CHECK-NEXT: Offset: 0x40
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Locals:
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 41000B
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Locals:
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 1080808080000B
# CHECK-NEXT: - Index: 2
# CHECK-NEXT: Locals:
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 1080808080000B
# CHECK-NEXT: - Index: 3
# CHECK-NEXT: Locals:
# CHECK-NEXT: Body: 410028028880808000118080808000000B
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 41002802888080800011808080800080808080000B
# CHECK-NEXT: - Index: 4
# CHECK-NEXT: Locals:
# CHECK-NEXT: Body: 410028029080808000118080808000000B
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 41002802908080800011808080800080808080000B
# CHECK-NEXT: - Type: DATA
# CHECK-NEXT: Relocations:
# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32
@ -205,46 +211,46 @@ alias_address:
# CHECK-NEXT: Segment: 1
# CHECK-NEXT: Size: 4
# CHECK-NEXT: - Index: 6
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Name: __indirect_function_table
# CHECK-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
# CHECK-NEXT: Table: 0
# CHECK-NEXT: - Index: 7
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: call_alias_ptr
# CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ]
# CHECK-NEXT: Function: 4
# CHECK-NEXT: - Index: 7
# CHECK-NEXT: - Index: 8
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: alias_address
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Segment: 2
# CHECK-NEXT: Size: 4
# CHECK-NEXT: - Index: 8
# CHECK-NEXT: - Index: 9
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: bar
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Segment: 0
# CHECK-NEXT: Size: 4
# CHECK-NEXT: - Index: 9
# CHECK-NEXT: - Index: 10
# CHECK-NEXT: Kind: DATA
# CHECK-NEXT: Name: bar_alias
# CHECK-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, NO_STRIP ]
# CHECK-NEXT: Segment: 0
# CHECK-NEXT: Size: 4
# CHECK-NEXT: - Index: 10
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Name: __indirect_function_table
# CHECK-NEXT: Flags: [ UNDEFINED, NO_STRIP ]
# CHECK-NEXT: Table: 0
# CHECK-NEXT: SegmentInfo:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Name: .data.bar
# CHECK-NEXT: Alignment: 3
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Name: .data.direct_address
# CHECK-NEXT: Alignment: 3
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: - Index: 2
# CHECK-NEXT: Name: .data.alias_address
# CHECK-NEXT: Alignment: 3
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: Flags: [ ]
# CHECK-NEXT: ...
# CHECK-SYMS: SYMBOL TABLE: