Index: llvm/include/llvm/MC/MCXCOFFObjectWriter.h =================================================================== --- llvm/include/llvm/MC/MCXCOFFObjectWriter.h +++ llvm/include/llvm/MC/MCXCOFFObjectWriter.h @@ -28,6 +28,11 @@ } bool is64Bit() const { return Is64Bit; } + virtual uint8_t getRelocType(const MCValue &Target, + const MCFixup &Fixup) const = 0; + virtual uint8_t getRelocSignAndSize(const MCFixup &Fixup, + bool IsPCRel) const = 0; + private: bool Is64Bit; }; Index: llvm/lib/MC/MCXCOFFStreamer.cpp =================================================================== --- llvm/lib/MC/MCXCOFFStreamer.cpp +++ llvm/lib/MC/MCXCOFFStreamer.cpp @@ -69,9 +69,13 @@ raw_svector_ostream VecOS(Code); Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); - // TODO: Handle Fixups later - + // Add the fixups and data. MCDataFragment *DF = getOrCreateDataFragment(&STI); + for (auto &Fixup : Fixups) { + Fixup.setOffset(Fixup.getOffset() + DF->getContents().size()); + DF->getFixups().push_back(Fixup); + } + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); } Index: llvm/lib/MC/XCOFFObjectWriter.cpp =================================================================== --- llvm/lib/MC/XCOFFObjectWriter.cpp +++ llvm/lib/MC/XCOFFObjectWriter.cpp @@ -11,8 +11,11 @@ //===----------------------------------------------------------------------===// #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCSymbolXCOFF.h" @@ -43,12 +46,22 @@ // only relevant to the ObjectWriter, so we materialize them in this class. namespace { +// 32 bit XCOFF Relocation structure itself is 12 byte, +// however we only use 10 byte spaces when writing it out. +constexpr unsigned SizeOfXCOFFRelocation32 = 10; constexpr unsigned DefaultSectionAlign = 4; constexpr int16_t MaxSectionIndex = INT16_MAX; // Packs the csect's alignment and type into a byte. uint8_t getEncodedType(const MCSectionXCOFF *); +struct XCOFFRelocation { + uint32_t SymbolTableIndex; + uint32_t FixupOffsetInCSect; + uint8_t SignAndSize; + uint8_t Type; +}; + // Wrapper around an MCSymbolXCOFF. struct Symbol { const MCSymbolXCOFF *const MCSym; @@ -69,6 +82,7 @@ uint32_t Size; SmallVector Syms; + SmallVector Relocations; StringRef getName() const { return MCCsect->getSectionName(); } ControlSection(const MCSectionXCOFF *MCSec) : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {} @@ -79,7 +93,6 @@ // with a storage mapping class of `xmc_pr` will get placed into the same // container. using CsectGroup = std::deque; - using CsectGroups = std::deque; // Represents the data related to a section excluding the csects that make up @@ -141,11 +154,21 @@ uint32_t SymbolTableEntryCount = 0; uint32_t SymbolTableOffset = 0; uint16_t SectionCount = 0; + uint32_t RelocationEntryOffset = 0; support::endian::Writer W; std::unique_ptr TargetObjectWriter; StringTableBuilder Strings; + // Maps the MC Section representation to its corrresponding ControlSection + // wrapper. Needed for finding the ControlSection to insert an MCSymbol into + // from its containing MCSectionXCOFF. + DenseMap SectionMap; + + // Maps the MCSymbol representation to its corrresponding symbol table index. + // Needed for relocation. + DenseMap SymbolIndexMap; + // CsectGroups. These store the csects which make up different parts of // the sections. Should have one for each set of csects that get mapped into // the same section and get handled in a 'similar' way. @@ -188,6 +211,8 @@ void writeSectionHeaderTable(); void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout); void writeSymbolTable(const MCAsmLayout &Layout); + void writeRelocations(); + void writeRelocation(XCOFFRelocation Reloc, const ControlSection &CSection); // Called after all the csects and symbols have been processed by // `executePostLayoutBinding`, this function handles building up the majority @@ -198,6 +223,7 @@ // *) Builds up the section header table by adding any non-empty sections to // `Sections`. void assignAddressesAndIndices(const MCAsmLayout &); + void finalizeSectionInfo(); bool needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */ @@ -228,8 +254,11 @@ CsectGroups{&BSSCsects}) {} void XCOFFObjectWriter::reset() { - UndefinedCsects.clear(); + // Clear mappings we created. + SymbolIndexMap.clear(); + SectionMap.clear(); + UndefinedCsects.clear(); // Reset any sections we have written to, and empty the section header table. for (auto *Sec : Sections) Sec->reset(); @@ -238,6 +267,7 @@ SymbolTableEntryCount = 0; SymbolTableOffset = 0; SectionCount = 0; + RelocationEntryOffset = 0; Strings.clear(); MCObjectWriter::reset(); @@ -291,14 +321,9 @@ if (TargetObjectWriter->is64Bit()) report_fatal_error("64-bit XCOFF object files are not supported yet."); - // Maps the MC Section representation to its corresponding ControlSection - // wrapper. Needed for finding the ControlSection to insert an MCSymbol into - // from its containing MCSectionXCOFF. - DenseMap WrapperMap; - for (const auto &S : Asm) { const auto *MCSec = cast(&S); - assert(WrapperMap.find(MCSec) == WrapperMap.end() && + assert(SectionMap.find(MCSec) == SectionMap.end() && "Cannot add a csect twice."); assert(XCOFF::XTY_ER != MCSec->getCSectType() && "An undefined csect should not get registered."); @@ -310,7 +335,7 @@ CsectGroup &Group = getCsectGroup(MCSec); Group.emplace_back(MCSec); - WrapperMap[MCSec] = &Group.back(); + SectionMap[MCSec] = &Group.back(); } for (const MCSymbol &S : Asm.symbols()) { @@ -324,6 +349,7 @@ // Handle undefined symbol. if (ContainingCsect->getCSectType() == XCOFF::XTY_ER) { UndefinedCsects.emplace_back(ContainingCsect); + SectionMap[ContainingCsect] = &UndefinedCsects.back(); continue; } @@ -332,11 +358,11 @@ if (XSym == ContainingCsect->getQualNameSymbol()) continue; - assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() && + assert(SectionMap.find(ContainingCsect) != SectionMap.end() && "Expected containing csect to exist in map"); // Lookup the containing csect and add the symbol to it. - WrapperMap[ContainingCsect]->Syms.emplace_back(XSym); + SectionMap[ContainingCsect]->Syms.emplace_back(XSym); // If the name does not fit in the storage provided in the symbol table // entry, add it to the string table. @@ -348,10 +374,51 @@ assignAddressesAndIndices(Layout); } -void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &, - const MCFragment *, const MCFixup &, - MCValue, uint64_t &) { - // TODO: recordRelocation is not yet implemented. +void XCOFFObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + + if (Target.getSymB()) + report_fatal_error("Handling Target.SymB for relocation is unimplemented."); + + const MCSymbol &SymA = Target.getSymA()->getSymbol(); + + MCAsmBackend &Backend = Asm.getBackend(); + bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsPCRel; + + assert( + (Layout.getFragmentOffset(Fragment) <= UINT32_MAX || + TargetObjectWriter->is64Bit()) && + "getFragmentOffset should return less than UINT32_MAX in 32-bit mode."); + uint32_t FixupOffsetInCSect = + Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + uint8_t SignAndSize = TargetObjectWriter->getRelocSignAndSize(Fixup, IsPCRel); + uint8_t Type = TargetObjectWriter->getRelocType(Target, Fixup); + + const MCSectionXCOFF *SymASec = + cast(SymA).getContainingCsect(); + assert(SectionMap.find(SymASec) != SectionMap.end() && + "Expected containing csect to exist in map."); + + uint32_t Index = (SymA.isTemporary() || SymA.isUndefined(false)) + ? SymbolIndexMap[SymASec->getQualNameSymbol()] + : SymbolIndexMap[&SymA]; + + // Only R_POS relocation type requires setting the FixedValue. + // The value we put in here is the symbol address relaitve to the + // beginning of the object file. + if (Type == XCOFF::RelocationType::R_POS) + FixedValue = SectionMap[SymASec]->Address + + (SymA.isDefined() ? Layout.getSymbolOffset(SymA) : 0); + + XCOFFRelocation Reloc{Index, FixupOffsetInCSect, SignAndSize, Type}; + MCSectionXCOFF *RelocationSec = cast(Fragment->getParent()); + assert(SectionMap.find(RelocationSec) != SectionMap.end() && + "Expected containing csect to exist in map."); + SectionMap[RelocationSec]->Relocations.push_back(Reloc); } void XCOFFObjectWriter::writeSections(const MCAssembler &Asm, @@ -396,12 +463,13 @@ if (TargetObjectWriter->is64Bit()) report_fatal_error("64-bit XCOFF object files are not supported yet."); + finalizeSectionInfo(); uint64_t StartOffset = W.OS.tell(); writeFileHeader(); writeSectionHeaderTable(); writeSections(Asm, Layout); - // TODO writeRelocations(); + writeRelocations(); writeSymbolTable(Layout); // Write the string table. @@ -536,19 +604,44 @@ W.write(Sec->Size); W.write(Sec->FileOffsetToData); - - // Relocation pointer and Lineno pointer. Not supported yet. - W.write(0); + W.write(Sec->FileOffsetToRelocations); + // Line number pointer. Not supported yet. W.write(0); - // Relocation and line-number counts. Not supported yet. - W.write(0); + W.write(Sec->RelocationCount); + // Line number counts. Not supported yet. W.write(0); W.write(Sec->Flags); } } +void XCOFFObjectWriter::writeRelocation(XCOFFRelocation Reloc, + const ControlSection &CSection) { + W.write(CSection.Address + Reloc.FixupOffsetInCSect); + W.write(Reloc.SymbolTableIndex); + W.write(Reloc.SignAndSize); + W.write(Reloc.Type); +} + +void XCOFFObjectWriter::writeRelocations() { + for (const auto *Section : Sections) { + // Nothing to write for this Section. + if (Section->Index == Section::UninitializedIndex) + continue; + + for (const auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + for (const auto &Csect : *Group) { + for (const auto Reloc : Csect.Relocations) + writeRelocation(Reloc, Csect); + } + } + } +} + void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) { for (const auto &Csect : UndefinedCsects) { writeSymbolTableEntryForControlSection( @@ -578,6 +671,38 @@ } } +void XCOFFObjectWriter::finalizeSectionInfo() { + for (auto *Section : Sections) { + // Nothing to record for this Section. + if (Section->Index == Section::UninitializedIndex) + continue; + + for (const auto *Group : Section->Groups) { + if (Group->empty()) + continue; + + for (auto &Csect : *Group) + Section->RelocationCount += Csect.Relocations.size(); + } + } + + // Calculate file offset to relocation entries. + uint32_t RawPointer = RelocationEntryOffset; + for (auto Sec : Sections) { + if (Sec->Index == Section::UninitializedIndex || !Sec->RelocationCount) + continue; + + Sec->FileOffsetToRelocations = RawPointer; + RawPointer += Sec->RelocationCount * SizeOfXCOFFRelocation32; + } + + // TODO What to align the SymbolTable too? + // TODO Error check that the number of symbol table entries fits in 32-bits + // signed ... + if (SymbolTableEntryCount) + SymbolTableOffset = RawPointer; +} + void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) { // The first symbol table entry is for the file name. We are not emitting it // yet, so start at index 0. @@ -588,6 +713,7 @@ Csect.Size = 0; Csect.Address = 0; Csect.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[Csect.MCCsect->getQualNameSymbol()] = Csect.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for each contained symbol. SymbolTableIndex += 2; } @@ -622,11 +748,13 @@ Csect.Size = Layout.getSectionAddressSize(MCSec); Address = Csect.Address + Csect.Size; Csect.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[MCSec->getQualNameSymbol()] = Csect.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for the csect. SymbolTableIndex += 2; for (auto &Sym : Csect.Syms) { Sym.SymbolTableIndex = SymbolTableIndex; + SymbolIndexMap[Sym.MCSym] = Sym.SymbolTableIndex; // 1 main and 1 auxiliary symbol table entry for each contained // symbol. SymbolTableIndex += 2; @@ -658,12 +786,7 @@ RawPointer += Sec->Size; } - // TODO Add in Relocation storage to the RawPointer Calculation. - // TODO What to align the SymbolTable to? - // TODO Error check that the number of symbol table entries fits in 32-bits - // signed ... - if (SymbolTableEntryCount) - SymbolTableOffset = RawPointer; + RelocationEntryOffset = RawPointer; } // Takes the log base 2 of the alignment and shifts the result into the 5 most Index: llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp =================================================================== --- llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp +++ llvm/lib/Target/PowerPC/MCTargetDesc/PPCXCOFFObjectWriter.cpp @@ -7,13 +7,25 @@ // //===----------------------------------------------------------------------===// -#include "PPCMCTargetDesc.h" +#include "MCTargetDesc/PPCFixupKinds.h" +#include "MCTargetDesc/PPCMCTargetDesc.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCValue.h" #include "llvm/MC/MCXCOFFObjectWriter.h" using namespace llvm; namespace { class PPCXCOFFObjectWriter : public MCXCOFFObjectTargetWriter { + static constexpr uint8_t SignBitMask = 0x80; + +protected: + uint8_t getRelocType(const MCValue &Taraget, + const MCFixup &Fixup) const override; + uint8_t getRelocSignAndSize(const MCFixup &Fixup, + bool IsPCRel) const override; public: PPCXCOFFObjectWriter(bool Is64Bit); @@ -27,3 +39,56 @@ llvm::createPPCXCOFFObjectWriter(bool Is64Bit) { return std::make_unique(Is64Bit); } + +uint8_t PPCXCOFFObjectWriter::getRelocType(const MCValue &Target, + const MCFixup &Fixup) const { + const MCSymbolRefExpr::VariantKind Modifier = + Target.isAbsolute() ? MCSymbolRefExpr::VK_None + : Target.getSymA()->getKind(); + unsigned Type; + switch ((unsigned)Fixup.getKind()) { + default: + report_fatal_error("Unimplemented fixup kind."); + case PPC::fixup_ppc_half16: + switch (Modifier) { + default: + report_fatal_error("Unsupported modifier for half16 fixup."); + case MCSymbolRefExpr::VK_None: + Type = XCOFF::RelocationType::R_TOC; + break; + } + break; + case PPC::fixup_ppc_br24: + Type = XCOFF::RelocationType::R_RBR; + break; + case FK_Data_4: + Type = XCOFF::RelocationType::R_POS; + break; + } + return Type; +} + +uint8_t PPCXCOFFObjectWriter::getRelocSignAndSize(const MCFixup &Fixup, + bool IsPCRel) const { + uint8_t Result = 0; + + // Set the Sign Bit if needed. + if (IsPCRel) + Result |= SignBitMask; + + switch ((unsigned)Fixup.getKind()) { + default: + report_fatal_error("Unsupported Fixup kind for relocation length."); + case PPC::fixup_ppc_half16: + Result |= 15; + break; + case PPC::fixup_ppc_br24: + Result |= 25; + break; + case FK_Data_4: + Result |= 31; + break; + } + + return Result; +} Index: llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/PowerPC/aix-xcoff-reloc.ll @@ -0,0 +1,142 @@ +; RUN: llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc-ibm-aix-xcoff -mattr=-altivec -filetype=obj -o %t.o < %s +; RUN: llvm-readobj --section-headers --file-header %t.o | \ +; RUN: FileCheck --check-prefix=OBJ %s +; RUN: llvm-readobj --relocs --expand-relocs %t.o | FileCheck --check-prefix=RELOC %s +; RUN: llvm-objdump -D %t.o | FileCheck --check-prefix=DIS %s + +; RUN: not llc -verify-machineinstrs -mcpu=pwr4 -mtriple powerpc64-ibm-aix-xcoff -mattr=-altivec -filetype=obj < %s 2>&1 | \ +; RUN: FileCheck --check-prefix=XCOFF64 %s +; XCOFF64: LLVM ERROR: 64-bit XCOFF object files are not supported yet. + +@globalA = global i32 6, align 4 + +define i32 @foo() { +entry: + %call = call i32 @bar(i32 1) + %0 = load i32, i32* @globalA, align 4 + %add = add nsw i32 %call, %0 + ret i32 %add +} + +declare i32 @bar(i32) + +; OBJ: File: {{.*}}aix-xcoff-reloc.ll.tmp.o +; OBJ-NEXT: Format: aixcoff-rs6000 +; OBJ-NEXT: Arch: powerpc +; OBJ-NEXT: AddressSize: 32bit +; OBJ-NEXT: FileHeader { +; OBJ-NEXT: Magic: 0x1DF +; OBJ-NEXT: NumberOfSections: 2 +; OBJ-NEXT: TimeStamp: None (0x0) +; OBJ-NEXT: SymbolTableOffset: 0xDE +; OBJ-NEXT: SymbolTableEntries: 18 +; OBJ-NEXT: OptionalHeaderSize: 0x0 +; OBJ-NEXT: Flags: 0x0 +; OBJ-NEXT: } +; OBJ-NEXT: Sections [ +; OBJ-NEXT: Section { +; OBJ-NEXT: Index: 1 +; OBJ-NEXT: Name: .text +; OBJ-NEXT: PhysicalAddress: 0x0 +; OBJ-NEXT: VirtualAddress: 0x0 +; OBJ-NEXT: Size: 0x34 +; OBJ-NEXT: RawDataOffset: 0x64 +; OBJ-NEXT: RelocationPointer: 0xAC +; OBJ-NEXT: LineNumberPointer: 0x0 +; OBJ-NEXT: NumberOfRelocations: 2 +; OBJ-NEXT: NumberOfLineNumbers: 0 +; OBJ-NEXT: Type: STYP_TEXT (0x20) +; OBJ-NEXT: } +; OBJ-NEXT: Section { +; OBJ-NEXT: Index: 2 +; OBJ-NEXT: Name: .data +; OBJ-NEXT: PhysicalAddress: 0x34 +; OBJ-NEXT: VirtualAddress: 0x34 +; OBJ-NEXT: Size: 0x14 +; OBJ-NEXT: RawDataOffset: 0x98 +; OBJ-NEXT: RelocationPointer: 0xC0 +; OBJ-NEXT: LineNumberPointer: 0x0 +; OBJ-NEXT: NumberOfRelocations: 3 +; OBJ-NEXT: NumberOfLineNumbers: 0 +; OBJ-NEXT: Type: STYP_DATA (0x40) +; OBJ-NEXT: } +; OBJ-NEXT: ] + +; RELOC: File: {{.*}}aix-xcoff-reloc.ll.tmp.o +; RELOC-NEXT: Format: aixcoff-rs6000 +; RELOC-NEXT: Arch: powerpc +; RELOC-NEXT: AddressSize: 32bit +; RELOC-NEXT: Relocations [ +; RELOC-NEXT: Section (index: 1) .text { +; RELOC-NEXT: Relocation { +; RELOC-NEXT: Virtual Address: 0x10 +; RELOC-NEXT: Symbol: .bar (0) +; RELOC-NEXT: IsSigned: Yes +; RELOC-NEXT: FixupBitValue: 0 +; RELOC-NEXT: Length: 26 +; RELOC-NEXT: Type: R_RBR (0x1A) +; RELOC-NEXT: } +; RELOC-NEXT: Relocation { +; RELOC-NEXT: Virtual Address: 0x1A +; RELOC-NEXT: Symbol: globalA (16) +; RELOC-NEXT: IsSigned: No +; RELOC-NEXT: FixupBitValue: 0 +; RELOC-NEXT: Length: 16 +; RELOC-NEXT: Type: R_TOC (0x3) +; RELOC-NEXT: } +; RELOC-NEXT: } +; RELOC-NEXT: Section (index: 2) .data { +; RELOC-NEXT: Relocation { +; RELOC-NEXT: Virtual Address: 0x38 +; RELOC-NEXT: Symbol: .foo (4) +; RELOC-NEXT: IsSigned: No +; RELOC-NEXT: FixupBitValue: 0 +; RELOC-NEXT: Length: 32 +; RELOC-NEXT: Type: R_POS (0x0) +; RELOC-NEXT: } +; RELOC-NEXT: Relocation { +; RELOC-NEXT: Virtual Address: 0x3C +; RELOC-NEXT: Symbol: TOC (14) +; RELOC-NEXT: IsSigned: No +; RELOC-NEXT: FixupBitValue: 0 +; RELOC-NEXT: Length: 32 +; RELOC-NEXT: Type: R_POS (0x0) +; RELOC-NEXT: } +; RELOC-NEXT: Relocation { +; RELOC-NEXT: Virtual Address: 0x44 +; RELOC-NEXT: Symbol: globalA (8) +; RELOC-NEXT: IsSigned: No +; RELOC-NEXT: FixupBitValue: 0 +; RELOC-NEXT: Length: 32 +; RELOC-NEXT: Type: R_POS (0x0) +; RELOC-NEXT: } +; RELOC-NEXT: } +; RELOC-NEXT: ] + +; DIS: {{.*}}aix-xcoff-reloc.ll.tmp.o: file format aixcoff-rs6000 +; DIS: Disassembly of section .text: +; DIS: 00000000 .text: +; DIS-NEXT: 0: 7c 08 02 a6 mflr 0 +; DIS-NEXT: 4: 90 01 00 08 stw 0, 8(1) +; DIS-NEXT: 8: 94 21 ff c0 stwu 1, -64(1) +; DIS-NEXT: c: 38 60 00 01 li 3, 1 +; DIS-NEXT: 10: 4b ff ff f1 bl .-16 +; DIS-NEXT: 14: 60 00 00 00 nop +; DIS-NEXT: 18: 80 82 00 00 lwz 4, 0(2) +; DIS-NEXT: 1c: 80 84 00 00 lwz 4, 0(4) +; DIS-NEXT: 20: 7c 63 22 14 add 3, 3, 4 +; DIS-NEXT: 24: 38 21 00 40 addi 1, 1, 64 +; DIS-NEXT: 28: 80 01 00 08 lwz 0, 8(1) +; DIS-NEXT: 2c: 7c 08 03 a6 mtlr 0 +; DIS-NEXT: 30: 4e 80 00 20 blr + +; DIS: Disassembly of section .data: +; DIS: 00000034 globalA: +; DIS-NEXT: 34: 00 00 00 06 +; DIS: 00000038 foo: +; DIS-NEXT: 38: 00 00 00 00 +; DIS-NEXT: 3c: 00 00 00 44 +; DIS-NEXT: 40: 00 00 00 00 +; DIS: 00000044 globalA: +; DIS-NEXT: 44: 00 00 00 34 +