Skip to content

Commit

Permalink
[WebAssembly] Support multiple .init_array fragments when writing W…
Browse files Browse the repository at this point in the history
…asm objects (llvm#111008)

(cherry picked from commit ac5dd45)
  • Loading branch information
georgestagg authored and tru committed Dec 17, 2024
1 parent 2384a06 commit 8069ce6
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 42 deletions.
89 changes: 47 additions & 42 deletions llvm/lib/MC/WasmObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1853,49 +1853,54 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
if (EmptyFrag.getKind() != MCFragment::FT_Data)
report_fatal_error(".init_array section should be aligned");

const MCFragment &AlignFrag = *EmptyFrag.getNext();
if (AlignFrag.getKind() != MCFragment::FT_Align)
report_fatal_error(".init_array section should be aligned");
if (cast<MCAlignFragment>(AlignFrag).getAlignment() !=
Align(is64Bit() ? 8 : 4))
report_fatal_error(".init_array section should be aligned for pointers");

const MCFragment &Frag = *AlignFrag.getNext();
if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
report_fatal_error("only data supported in .init_array section");

uint16_t Priority = UINT16_MAX;
unsigned PrefixLength = strlen(".init_array");
if (WS.getName().size() > PrefixLength) {
if (WS.getName()[PrefixLength] != '.')
const MCFragment *nextFrag = EmptyFrag.getNext();
while (nextFrag != nullptr) {
const MCFragment &AlignFrag = *nextFrag;
if (AlignFrag.getKind() != MCFragment::FT_Align)
report_fatal_error(".init_array section should be aligned");
if (cast<MCAlignFragment>(AlignFrag).getAlignment() !=
Align(is64Bit() ? 8 : 4))
report_fatal_error(
".init_array section priority should start with '.'");
if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority))
report_fatal_error("invalid .init_array section priority");
}
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
for (const uint8_t *
P = (const uint8_t *)Contents.data(),
*End = (const uint8_t *)Contents.data() + Contents.size();
P != End; ++P) {
if (*P != 0)
report_fatal_error("non-symbolic data in .init_array section");
}
for (const MCFixup &Fixup : DataFrag.getFixups()) {
assert(Fixup.getKind() ==
MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
const MCExpr *Expr = Fixup.getValue();
auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
if (!SymRef)
report_fatal_error("fixups in .init_array should be symbol references");
const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
if (TargetSym.getIndex() == InvalidIndex)
report_fatal_error("symbols in .init_array should exist in symtab");
if (!TargetSym.isFunction())
report_fatal_error("symbols in .init_array should be for functions");
InitFuncs.push_back(
std::make_pair(Priority, TargetSym.getIndex()));
".init_array section should be aligned for pointers");

const MCFragment &Frag = *AlignFrag.getNext();
nextFrag = Frag.getNext();
if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
report_fatal_error("only data supported in .init_array section");

uint16_t Priority = UINT16_MAX;
unsigned PrefixLength = strlen(".init_array");
if (WS.getName().size() > PrefixLength) {
if (WS.getName()[PrefixLength] != '.')
report_fatal_error(
".init_array section priority should start with '.'");
if (WS.getName().substr(PrefixLength + 1).getAsInteger(10, Priority))
report_fatal_error("invalid .init_array section priority");
}
const auto &DataFrag = cast<MCDataFragment>(Frag);
const SmallVectorImpl<char> &Contents = DataFrag.getContents();
for (const uint8_t *
P = (const uint8_t *)Contents.data(),
*End = (const uint8_t *)Contents.data() + Contents.size();
P != End; ++P) {
if (*P != 0)
report_fatal_error("non-symbolic data in .init_array section");
}
for (const MCFixup &Fixup : DataFrag.getFixups()) {
assert(Fixup.getKind() ==
MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
const MCExpr *Expr = Fixup.getValue();
auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
if (!SymRef)
report_fatal_error(
"fixups in .init_array should be symbol references");
const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
if (TargetSym.getIndex() == InvalidIndex)
report_fatal_error("symbols in .init_array should exist in symtab");
if (!TargetSym.isFunction())
report_fatal_error("symbols in .init_array should be for functions");
InitFuncs.push_back(std::make_pair(Priority, TargetSym.getIndex()));
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions llvm/test/MC/WebAssembly/init-array.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s

init1:
.functype init1 () -> ()
end_function

init2:
.functype init2 () -> ()
end_function

.section .init_array,"",@
.p2align 2, 0
.int32 init1

.section .init_array,"",@
.p2align 2
.int32 init2

# CHECK: - Type: FUNCTION
# CHECK-NEXT: FunctionTypes: [ 0, 0 ]
# CHECK-NEXT: - Type: CODE
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 0B
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 0B
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: linking
# CHECK-NEXT: Version: 2
# CHECK-NEXT: SymbolTable:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: init1
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 0
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: Name: init2
# CHECK-NEXT: Flags: [ BINDING_LOCAL ]
# CHECK-NEXT: Function: 1
# CHECK-NEXT: InitFunctions:
# CHECK-NEXT: - Priority: 65535
# CHECK-NEXT: Symbol: 0
# CHECK-NEXT: - Priority: 65535
# CHECK-NEXT: Symbol: 1
# CHECK-NEXT: ...
#

0 comments on commit 8069ce6

Please sign in to comment.