Skip to content

Commit

Permalink
[WebAssembly] Add support for data sections in the assembler.
Browse files Browse the repository at this point in the history
Summary:
This is quite minimal so far, introduce them with .section,
fill them with .int8 or .asciz, end with .size

Reviewers: dschuff, sbc100, aheejin

Subscribers: jgravelle-google, sunfish, llvm-commits

Tags: #llvm

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

llvm-svn: 355321
  • Loading branch information
aardappel committed Mar 4, 2019
1 parent de11105 commit f3feb6a
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 12 deletions.
31 changes: 23 additions & 8 deletions llvm/lib/MC/MCParser/WasmAsmParser.cpp
Expand Up @@ -130,11 +130,27 @@ class WasmAsmParser : public MCAsmParserExtension {
if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") ||
expect(AsmToken::EndOfStatement, "eol"))
return true;
// This is done automatically by the assembler for text sections currently,
// so we don't need to emit that here. This is what it would do (and may
// be needed later for other section types):
// auto WS = getContext().getWasmSection(Name, SectionKind::getText());
// getStreamer().SwitchSection(WS);
struct SectionType {
const char *Name;
SectionKind Kind;
};
static SectionType SectionTypes[] = {
{ ".text", SectionKind::getText() },
{ ".rodata", SectionKind::getReadOnly() },
{ ".data", SectionKind::getData() },
// TODO: add more types.
};
for (size_t I = 0; I < sizeof(SectionTypes) / sizeof(SectionType); I++) {
if (Name.startswith(SectionTypes[I].Name)) {
auto WS = getContext().getWasmSection(Name, SectionTypes[I].Kind);
getStreamer().SwitchSection(WS);
return false;
}
}
// Not found, just ignore this section.
// For code in a text section WebAssemblyAsmParser automatically adds
// one section per function, so they're optional to be specified with
// this directive.
return false;
}

Expand All @@ -153,9 +169,8 @@ class WasmAsmParser : public MCAsmParserExtension {
if (expect(AsmToken::EndOfStatement, "eol"))
return true;
// This is done automatically by the assembler for functions currently,
// so we don't need to emit that here. This is what it would do:
(void)Sym;
// getStreamer().emitELFSize(Sym, Expr);
// so this is only currently needed for data sections:
getStreamer().emitELFSize(Sym, Expr);
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/MC/WasmObjectWriter.cpp
Expand Up @@ -1348,7 +1348,7 @@ uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");

} else if (WS.isData()) {
if (WS.isTemporary() && !WS.getSize())
if (!isInSymtab(WS))
continue;

if (!WS.isDefined()) {
Expand Down
34 changes: 33 additions & 1 deletion llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
Expand Up @@ -172,6 +172,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
FunctionLocals,
Instructions,
EndFunction,
DataSection,
} CurrentState = FileStart;

// For ensuring blocks are properly nested.
Expand Down Expand Up @@ -552,6 +553,17 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return false;
}

bool CheckDataSection() {
if (CurrentState != DataSection) {
auto WS = cast<MCSectionWasm>(getStreamer().getCurrentSection().first);
if (WS && WS->getKind().isText())
return error("data directive must occur in a data segment: ",
Lexer.getTok());
}
CurrentState = DataSection;
return false;
}

// This function processes wasm-specific directives streamed to
// WebAssemblyTargetStreamer, all others go to the generic parser
// (see WasmAsmParser).
Expand Down Expand Up @@ -650,6 +662,25 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return expect(AsmToken::EndOfStatement, "EOL");
}

if (DirectiveID.getString() == ".int8") {
if (CheckDataSection()) return true;
int64_t V;
if (Parser.parseAbsoluteExpression(V))
return error("Cannot parse int8 constant: ", Lexer.getTok());
// TODO: error if value doesn't fit?
Out.EmitIntValue(static_cast<uint64_t>(V), 1);
return expect(AsmToken::EndOfStatement, "EOL");
}

if (DirectiveID.getString() == ".asciz") {
if (CheckDataSection()) return true;
std::string S;
if (Parser.parseEscapedString(S))
return error("Cannot parse string constant: ", Lexer.getTok());
Out.EmitBytes(StringRef(S.c_str(), S.length() + 1));
return expect(AsmToken::EndOfStatement, "EOL");
}

return true; // We didn't process this directive.
}

Expand Down Expand Up @@ -717,9 +748,10 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
void onEndOfFunction() {
// Automatically output a .size directive, so it becomes optional for the
// user.
if (!LastFunctionLabel) return;
auto TempSym = getContext().createLinkerPrivateTempSymbol();
getStreamer().EmitLabel(TempSym);
auto Start = MCSymbolRefExpr::create(LastLabel, getContext());
auto Start = MCSymbolRefExpr::create(LastFunctionLabel, getContext());
auto End = MCSymbolRefExpr::create(TempSym, getContext());
auto Expr =
MCBinaryExpr::create(MCBinaryExpr::Sub, End, Start, getContext());
Expand Down
16 changes: 14 additions & 2 deletions llvm/test/MC/WebAssembly/basic-assembly.s
Expand Up @@ -77,12 +77,19 @@ test0:
.LBB0_4:
end_block
end_try
i32.const 0
i32.const .L.str
throw 0
.LBB0_5:
#i32.trunc_sat_f32_s
global.get __stack_pointer
end_function

.section .rodata..L.str,"",@
.L.str:
.int8 'H'
.asciz "ello, World!"
.size .L.str, 14

.globaltype __stack_pointer, i32

# CHECK: .text
Expand Down Expand Up @@ -154,10 +161,15 @@ test0:
# CHECK-NEXT: .LBB0_4:
# CHECK-NEXT: end_block
# CHECK-NEXT: end_try
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: i32.const .L.str
# CHECK-NEXT: throw 0
# CHECK-NEXT: .LBB0_5:
# CHECK-NEXT: global.get __stack_pointer
# CHECK-NEXT: end_function

# CHECK: .section .rodata..L.str,"",@
# CHECK-NEXT:.L.str:
# CHECK-NEXT: .int8 72
# CHECK-NEXT: .asciz "ello, World!"

# CHECK: .globaltype __stack_pointer, i32
94 changes: 94 additions & 0 deletions llvm/test/MC/WebAssembly/data-section.s
@@ -0,0 +1,94 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
# Check that it converts to .o without errors:
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s

# Minimal test for data sections.

test0:
.functype test0 () -> (i32)
i32.const .L.str
.Ltestlabel:
end_function

.section .rodata..L.str,"",@
.L.str:
.int8 100
.size .L.str, 1


# CHECK: .text
# CHECK-LABEL: test0:
# CHECK-NEXT: .functype test0 () -> (i32)
# CHECK-NEXT: i32.const .L.str
# CHECK-NEXT: .Ltestlabel:
# CHECK-NEXT: end_function

# CHECK: .section .rodata..L.str,"",@
# CHECK-NEXT:.L.str:
# CHECK-NEXT: .int8 100


# BIN: --- !WASM
# BIN-NEXT: FileHeader:
# BIN-NEXT: Version: 0x00000001
# BIN-NEXT: Sections:
# BIN-NEXT: - Type: TYPE
# BIN-NEXT: Signatures:
# BIN-NEXT: - Index: 0
# BIN-NEXT: ReturnType: I32
# BIN-NEXT: ParamTypes: []
# 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: 0x00000001
# BIN-NEXT: - Module: env
# BIN-NEXT: Field: __indirect_function_table
# BIN-NEXT: Kind: TABLE
# BIN-NEXT: Table:
# BIN-NEXT: ElemType: FUNCREF
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x00000000
# BIN-NEXT: - Type: FUNCTION
# BIN-NEXT: FunctionTypes: [ 0 ]
# BIN-NEXT: - Type: CODE
# BIN-NEXT: Relocations:
# BIN-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB
# BIN-NEXT: Index: 1
# BIN-NEXT: Offset: 0x00000004
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 4180808080000B
# BIN-NEXT: - Type: DATA
# BIN-NEXT: Segments:
# BIN-NEXT: - SectionOffset: 6
# BIN-NEXT: InitFlags: 0
# BIN-NEXT: Offset:
# BIN-NEXT: Opcode: I32_CONST
# BIN-NEXT: Value: 0
# BIN-NEXT: Content: '64'
# 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: DATA
# BIN-NEXT: Name: .L.str
# BIN-NEXT: Flags: [ BINDING_LOCAL ]
# BIN-NEXT: Segment: 0
# BIN-NEXT: Size: 1
# BIN-NEXT: SegmentInfo:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Name: .rodata..L.str
# BIN-NEXT: Alignment: 0
# BIN-NEXT: Flags: [ ]
# BIN-NEXT: ...

0 comments on commit f3feb6a

Please sign in to comment.