Lines Matching +full:bl +full:- +full:data +full:- +full:offset

1 //===- ARM.cpp ------------------------------------------------------------===//
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
52 enum class CodeState { Data = 0, Thumb = 2, Arm = 4 }; enumerator
80 // Set the EF_ARM_BE8 flag in the ELF header, if ELF file is big-endian in calcEFlags()
81 // with BE-8 code. in calcEFlags()
84 if (config->armVFPArgs == ARMVFPArgKind::Base || in calcEFlags()
85 config->armVFPArgs == ARMVFPArgKind::Default) in calcEFlags()
87 else if (config->armVFPArgs == ARMVFPArgKind::VFP) in calcEFlags()
90 if (!config->isLE && config->armBe8) in calcEFlags()
125 // (S + A) - GOT_ORG in getRelExpr()
128 // GOT(S) + A - GOT_ORG in getRelExpr()
132 // GOT(S) + A - P in getRelExpr()
137 return config->target1Rel ? R_PC : R_ABS; in getRelExpr()
139 if (config->target2 == Target2Policy::Rel) in getRelExpr()
141 if (config->target2 == Target2Policy::Abs) in getRelExpr()
151 // B(S) + A - P in getRelExpr()
201 if ((type == R_ARM_ABS32) || (type == R_ARM_TARGET1 && !config->target1Rel)) in getDynRel()
207 write32(buf, in.plt->getVA()); in writeGotPlt()
218 write32(buf + 0, 0xe52de004); // str lr, [sp,#-4]! in writePltHeaderLong()
222 write32(buf + 16, 0x00000000); // L2: .word &(.got.plt) - L1 - 8 in writePltHeaderLong()
223 write32(buf + 20, 0xd4d4d4d4); // Pad to 32-byte boundary in writePltHeaderLong()
224 write32(buf + 24, 0xd4d4d4d4); // Pad to 32-byte boundary in writePltHeaderLong()
226 uint64_t gotPlt = in.gotPlt->getVA(); in writePltHeaderLong()
227 uint64_t l1 = in.plt->getVA() + 8; in writePltHeaderLong()
228 write32(buf + 16, gotPlt - l1 - 8); in writePltHeaderLong()
234 return config->armHasThumb2ISA && !config->armHasArmISA; in useThumbPLTs()
247 // e: .word .got.plt - .plt - 16 in writePltHeader()
249 // At 0x8, we want to jump to .got.plt, the -16 accounts for 8 bytes from in writePltHeader()
252 uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 16; in writePltHeader() local
253 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset"); in writePltHeader()
262 write32(buf + 12, offset); in writePltHeader()
264 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary in writePltHeader()
265 memcpy(buf + 20, trapInstr.data(), 4); in writePltHeader()
266 memcpy(buf + 24, trapInstr.data(), 4); in writePltHeader()
267 memcpy(buf + 28, trapInstr.data(), 4); in writePltHeader()
274 0xe52de004, // L1: str lr, [sp,#-4]! in writePltHeader()
275 0xe28fe600, // add lr, pc, #0x0NN00000 &(.got.plt - L1 - 4) in writePltHeader()
276 0xe28eea00, // add lr, lr, #0x000NN000 &(.got.plt - L1 - 4) in writePltHeader()
277 0xe5bef000, // ldr pc, [lr, #0x00000NNN] &(.got.plt -L1 - 4) in writePltHeader()
280 uint64_t offset = in.gotPlt->getVA() - in.plt->getVA() - 4; in writePltHeader() local
281 if (!llvm::isUInt<27>(offset)) { in writePltHeader()
282 // We cannot encode the Offset, use the long form. in writePltHeader()
287 write32(buf + 4, pltData[1] | ((offset >> 20) & 0xff)); in writePltHeader()
288 write32(buf + 8, pltData[2] | ((offset >> 12) & 0xff)); in writePltHeader()
289 write32(buf + 12, pltData[3] | (offset & 0xfff)); in writePltHeader()
290 memcpy(buf + 16, trapInstr.data(), 4); // Pad to 32-byte boundary in writePltHeader()
291 memcpy(buf + 20, trapInstr.data(), 4); in writePltHeader()
292 memcpy(buf + 24, trapInstr.data(), 4); in writePltHeader()
293 memcpy(buf + 28, trapInstr.data(), 4); in writePltHeader()
314 write32(buf + 12, 0x00000000); // L2: .word Offset(&(.got.plt) - L1 - 8 in writePltLong()
316 write32(buf + 12, gotPltEntryAddr - l1 - 8); in writePltLong()
325 uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8; in writePlt() local
329 // optimal rotation for the 8-bit immediate used in the add instructions we in writePlt()
333 0xe28fc600, // L1: add ip, pc, #0x0NN00000 Offset(&(.got.plt) - L1 - 8 in writePlt()
334 0xe28cca00, // add ip, ip, #0x000NN000 Offset(&(.got.plt) - L1 - 8 in writePlt()
335 0xe5bcf000, // ldr pc, [ip, #0x00000NNN] Offset(&(.got.plt) - L1 - 8 in writePlt()
337 if (!llvm::isUInt<27>(offset)) { in writePlt()
338 // We cannot encode the Offset, use the long form. in writePlt()
342 write32(buf + 0, pltData[0] | ((offset >> 20) & 0xff)); in writePlt()
343 write32(buf + 4, pltData[1] | ((offset >> 12) & 0xff)); in writePlt()
344 write32(buf + 8, pltData[2] | (offset & 0xfff)); in writePlt()
345 memcpy(buf + 12, trapInstr.data(), 4); // Pad to 16-byte boundary in writePlt()
347 uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 12; in writePlt() local
348 assert(llvm::isUInt<32>(offset) && "This should always fit into a 32-bit offset"); in writePlt()
362 relocateNoSym(buf, R_ARM_THM_MOVW_ABS_NC, offset); in writePlt()
366 relocateNoSym(buf + 4, R_ARM_THM_MOVT_ABS, offset); in writePlt()
390 // undefined non-weak symbol will have been errored. in needsThunk()
410 (!config->armHasBlx && (s.getVA() & 1)); in needsThunk()
423 (!config->armHasBlx && (s.getVA() & 1) == 0);; in needsThunk()
430 // The placing of pre-created ThunkSections is controlled by the value in getThunkSectionSpacing()
440 // Pre-created ThunkSections are spaced roughly 16MiB apart on ARMv7. This in getThunkSectionSpacing()
441 // is to match the most common expected case of a Thumb 2 encoded BL, BLX or in getThunkSectionSpacing()
443 // ARM B, BL, BLX range +/- 32MiB in getThunkSectionSpacing()
444 // Thumb B.W, BL, BLX range +/- 16MiB in getThunkSectionSpacing()
445 // Thumb B<cc>.W range +/- 1MiB in getThunkSectionSpacing()
446 // If a branch cannot reach a pre-created ThunkSection a new one will be in getThunkSectionSpacing()
452 // 12 byte Thunks at any offset in a ThunkSection without risk of a branch to in getThunkSectionSpacing()
457 // ARMv6T2) the range is +/- 4MiB. in getThunkSectionSpacing()
459 return (config->armJ1J2BranchEncoding) ? 0x1000000 - 0x30000 in getThunkSectionSpacing()
460 : 0x400000 - 0x7500; in getThunkSectionSpacing()
465 // Destination is ARM, if ARM caller then Src is already 4-byte aligned. in inBranchRange()
473 int64_t offset = dst - src; in inBranchRange() local
479 return llvm::isInt<26>(offset); in inBranchRange()
481 return llvm::isInt<21>(offset); in inBranchRange()
484 return config->armJ1J2BranchEncoding ? llvm::isInt<25>(offset) in inBranchRange()
485 : llvm::isInt<23>(offset); in inBranchRange()
504 " to STT_SECTION symbol " + cast<Defined>(s).section->name + in stateChangeWarning()
518 // Rotate a 32-bit unsigned value right by a specified amt of bits.
521 return (val >> amt) | (val << ((32 - amt) & 31)); in rotr32()
533 } while (group--); in getRemAndLZForGroup()
540 // immediate field carries is a 12-bit modified immediate, made up of a 4-bit in encodeAluGroup()
541 // even rotate right and an 8-bit immediate. in encodeAluGroup()
545 val = -val; in encodeAluGroup()
551 imm = rotr32(imm, 24 - lz); in encodeAluGroup()
562 // R_ARM_LDR_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a in encodeLdrGroup()
564 // bottom bit to recover S + A - P. in encodeLdrGroup()
565 if (rel.sym->isFunc()) in encodeLdrGroup()
571 val = -val; in encodeLdrGroup()
580 // R_ARM_LDRS_PC_Gn is S + A - P, we have ((S + A) | T) - P, if S is a in encodeLdrsGroup()
582 // bottom bit to recover S + A - P. in encodeLdrsGroup()
583 if (rel.sym->isFunc()) in encodeLdrsGroup()
589 val = -val; in encodeLdrsGroup()
623 // R_ARM_CALL is used for BL and BLX instructions, for symbols of type in relocate()
624 // STT_FUNC we choose whether to write a BL or BLX depending on the in relocate()
632 if (!rel.sym->isFunc() && isBlx != bit0Thumb) in relocate()
634 if (rel.sym->isFunc() ? bit0Thumb : isBlx) { in relocate()
643 // unconditional BL. in relocate()
645 // fall through as BL encoding is shared with B in relocate()
655 // We do a 9 bit check because val is right-shifted by 1 bit. in relocate()
660 // We do a 12 bit check because val is right-shifted by 1 bit. in relocate()
678 // R_ARM_THM_CALL is used for BL and BLX instructions, for symbols of type in relocate()
679 // STT_FUNC we choose whether to write a BL or BLX depending on the in relocate()
689 if (!rel.sym->isFunc() && !rel.sym->isInPlt() && isBlx == useThumb) in relocate()
691 if ((rel.sym->isFunc() || rel.sym->isInPlt()) ? !useThumb : isBlx) { in relocate()
692 // We are writing a BLX. Ensure BLX destination is 4-byte aligned. As in relocate()
700 if (!config->armJ1J2BranchEncoding) { in relocate()
717 // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 in relocate()
819 imm = -imm; in relocate()
829 // ADR and LDR literal encoding T1 positive offset only imm8:00 in relocate()
830 // R_ARM_THM_PC8 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a in relocate()
832 // bottom bit to recover S + A - Pa. in relocate()
833 if (rel.sym->isFunc()) in relocate()
842 // R_ARM_THM_PC12 is S + A - Pa, we have ((S + A) | T) - Pa, if S is a in relocate()
844 // bottom bit to recover S + A - Pa. in relocate()
845 if (rel.sym->isFunc()) in relocate()
850 imm12 = -imm12; in relocate()
912 if (!config->armJ1J2BranchEncoding) { in getImplicitAddend()
923 // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 in getImplicitAddend()
934 // MOVT is in the range -32768 <= A < 32768 in getImplicitAddend()
968 // 12-bit immediate is a modified immediate made up of a 4-bit even in getImplicitAddend()
969 // right rotation and 8-bit constant. After the rotation the value in getImplicitAddend()
970 // is zero-extended. When bit 23 is set the instruction is an add, when in getImplicitAddend()
974 return (instr & 0x00400000) ? -val : val; in getImplicitAddend()
983 return u ? imm12 : -imm12; in getImplicitAddend()
993 return u ? (imm4h | imm4l) : -(imm4h | imm4l); in getImplicitAddend()
1005 return (hi & 0x00f0) ? -imm : imm; in getImplicitAddend()
1011 // this trick permits the PC bias of -4 to be encoded using imm8 = 0xff in getImplicitAddend()
1012 return ((((read16(buf) & 0xff) << 2) + 4) & 0x3ff) - 4; in getImplicitAddend()
1017 return u ? imm12 : -imm12; in getImplicitAddend()
1028 return b->getName() == "$a" || b->getName().starts_with("$a."); in isArmMapSymbol()
1032 return s->getName() == "$t" || s->getName().starts_with("$t."); in isThumbMapSymbol()
1036 return b->getName() == "$d" || b->getName().starts_with("$d."); in isDataMapSymbol()
1045 return a->value < b->value; in sortArmMappingSymbols()
1056 for (Symbol *sym : file->getLocalSymbols()) { in addArmInputSectionMappingSymbols()
1063 if (auto *sec = cast_if_present<InputSection>(def->section)) in addArmInputSectionMappingSymbols()
1064 if (sec->flags & SHF_EXECINSTR) in addArmInputSectionMappingSymbols()
1072 // in the synthetic symbol table. Due to the presence of strip (--strip-all),
1078 if (auto *sec = cast_if_present<InputSection>(sym->section)) in addArmSyntheticSectionMappingSymbol()
1079 if (sec->flags & SHF_EXECINSTR) in addArmSyntheticSectionMappingSymbol()
1096 // the initial contents big-endian. Convert the big-endian instructions to
1097 // little endian leaving literal data untouched. We use mapping symbols to
1110 CodeState curState = CodeState::Data; in convertArmInstructionstoBE8()
1111 uint64_t start = 0, width = 0, size = sec->getSize(); in convertArmInstructionstoBE8()
1113 CodeState newState = CodeState::Data; in convertArmInstructionstoBE8()
1122 if (curState != CodeState::Data) { in convertArmInstructionstoBE8()
1124 toLittleEndianInstructions(buf, start, msym->value, width); in convertArmInstructionstoBE8()
1126 start = msym->value; in convertArmInstructionstoBE8()
1132 if (curState != CodeState::Data) { in convertArmInstructionstoBE8()
1138 // The Arm Cortex-M Security Extensions (CMSE) splits a system into two parts;
1139 // the non-secure and secure states with the secure state inaccessible from the
1140 // non-secure state, apart from an area of memory in secure state called the
1141 // secure gateway which is accessible from non-secure state. The secure gateway
1146 // v8-M Security Extensions Requirements on Development Tools.
1148 // The CMSE model of software development requires the non-secure and secure
1149 // states to be developed as two separate programs. The non-secure developer is
1152 // non-secure state.
1156 // - Creation of new secure gateway veneers based on symbol conventions.
1157 // - Checking the address of existing secure gateway veneers.
1158 // - Warning when existing secure gateway veneers removed.
1163 // --in-implib (specify an input import library from a previous revision of the
1165 // --out-implib (specify an output import library to be created by the linker).
1177 // - Reads an existing import library with importCmseSymbols().
1178 // - Determines which new secure gateway veneers to create and redirects calls
1181 // - Models the SG veneers as a synthetic section.
1199 sym->setName(CHECK(eSyms[i].getName(stringTable), this)); in importCmseSymbols()
1200 sym->value = eSym.st_value; in importCmseSymbols()
1201 sym->size = eSym.st_size; in importCmseSymbols()
1202 sym->type = eSym.getType(); in importCmseSymbols()
1203 sym->binding = eSym.getBinding(); in importCmseSymbols()
1204 sym->stOther = eSym.st_other; in importCmseSymbols()
1207 error("CMSE symbol '" + sym->getName() + "' in import library '" + in importCmseSymbols()
1213 error("CMSE symbol '" + sym->getName() + "' in import library '" + in importCmseSymbols()
1218 if (symtab.cmseImportLib.count(sym->getName())) { in importCmseSymbols()
1219 error("CMSE symbol '" + sym->getName() + in importCmseSymbols()
1225 warn("CMSE symbol '" + sym->getName() + "' in import library '" + in importCmseSymbols()
1230 symtab.cmseImportLib[sym->getName()] = sym; in importCmseSymbols()
1237 auto check = [](Symbol *s, StringRef type) -> std::optional<std::string> { in checkCmseSymAttributes()
1239 if (!(d && d->isFunc() && (d->value & 1))) in checkCmseSymAttributes()
1240 return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" + in checkCmseSymAttributes()
1241 s->getName() + "' is not a Thumb function definition") in checkCmseSymAttributes()
1243 if (!d->section) in checkCmseSymAttributes()
1244 return (Twine(toString(s->file)) + ": cmse " + type + " symbol '" + in checkCmseSymAttributes()
1245 s->getName() + "' cannot be an absolute symbol") in checkCmseSymAttributes()
1256 // Look for [__acle_se_<sym>, <sym>] pairs, as specified in the Cortex-M
1264 if (!config->cmseImplib) in processArmCmseSymbols()
1269 if (!acleSeSym->getName().starts_with(ACLESESYM_PREFIX)) in processArmCmseSymbols()
1273 if (!config->armCMSESupport) { in processArmCmseSymbols()
1274 error("CMSE is only supported by ARMv8-M architecture or later"); in processArmCmseSymbols()
1275 config->cmseImplib = false; in processArmCmseSymbols()
1281 StringRef name = acleSeSym->getName().substr(std::strlen(ACLESESYM_PREFIX)); in processArmCmseSymbols()
1284 error(toString(acleSeSym->file) + ": cmse special symbol '" + in processArmCmseSymbols()
1285 acleSeSym->getName() + in processArmCmseSymbols()
1304 MutableArrayRef<Symbol *> syms = file->getMutableSymbols(); in processArmCmseSymbols()
1306 StringRef symName = syms[i]->getName(); in processArmCmseSymbols()
1323 uint64_t offset = 0; member in elf::ArmCmseSGVeneer
1336 if (impLibMaxAddr <= sym->value) in ArmCmseSGSection()
1337 impLibMaxAddr = sym->value + sym->size; in ArmCmseSGSection()
1346 if (!symtab.inCMSEOutImpLib.count(sym->getName())) in ArmCmseSGSection()
1347 warn("entry function '" + sym->getName() + in ArmCmseSGSection()
1351 if (!symtab.cmseImportLib.empty() && config->cmseOutputLib.empty()) { in ArmCmseSGSection()
1354 if (!symtab.inCMSEOutImpLib.count(sym->getName())) in ArmCmseSGSection()
1355 warn("new entry function '" + sym->getName() + in ArmCmseSGSection()
1363 if (symtab.cmseImportLib.count(sym->getName())) in addSGVeneer()
1364 symtab.inCMSEOutImpLib[sym->getName()] = true; in addSGVeneer()
1366 if (acleSeSym->file != sym->file || in addSGVeneer()
1369 // Only secure symbols with values equal to that of it's non-secure in addSGVeneer()
1372 if (symtab.cmseImportLib.count(sym->getName())) { in addSGVeneer()
1373 Defined *impSym = symtab.cmseImportLib[sym->getName()]; in addSGVeneer()
1374 ss = make<ArmCmseSGVeneer>(sym, acleSeSym, impSym->value); in addSGVeneer()
1384 uint8_t *p = buf + s->offset; in writeTo()
1389 target->relocateNoSym(p + 4, R_ARM_THM_JUMP24, in writeTo()
1390 s->acleSeSym->getVA() - in writeTo()
1391 (getVA() + s->offset + s->size)); in writeTo()
1401 return (impLibMaxAddr ? impLibMaxAddr - getVA() : 0) + newEntries * entsize; in getSize()
1412 [](auto *i) { return i->getAddr().has_value(); }); in finalizeContents()
1414 return a->getAddr().value() < b->getAddr().value(); in finalizeContents()
1417 uint64_t addr = (*sgVeneers.begin())->getAddr().has_value() in finalizeContents()
1418 ? (*sgVeneers.begin())->getAddr().value() in finalizeContents()
1421 // linker-synthesized veneer with the lowest address. in finalizeContents()
1429 s->offset = i * s->size; in finalizeContents()
1430 Defined(file, StringRef(), s->sym->binding, s->sym->stOther, s->sym->type, in finalizeContents()
1431 s->offset | 1, s->size, this) in finalizeContents()
1432 .overwrite(*s->sym); in finalizeContents()
1440 // See Arm® v8-M Security Extensions: Requirements on Development Tools
1450 osIsPairs.emplace_back(make<OutputSection>(strtab->name, 0, 0), strtab); in writeARMCmseImportLib()
1451 osIsPairs.emplace_back(make<OutputSection>(impSymTab->name, 0, 0), impSymTab); in writeARMCmseImportLib()
1452 osIsPairs.emplace_back(make<OutputSection>(shstrtab->name, 0, 0), shstrtab); in writeARMCmseImportLib()
1455 [](const auto &a, const auto &b) -> bool { in writeARMCmseImportLib()
1456 return a.second.sym->getVA() < b.second.sym->getVA(); in writeARMCmseImportLib()
1461 impSymTab->addSymbol(makeDefined( in writeARMCmseImportLib()
1462 ctx.internalFile, d->getName(), d->computeBinding(), in writeARMCmseImportLib()
1463 /*stOther=*/0, STT_FUNC, d->getVA(), d->getSize(), nullptr)); in writeARMCmseImportLib()
1469 osec->sectionIndex = ++idx; in writeARMCmseImportLib()
1470 osec->recordSection(isec); in writeARMCmseImportLib()
1471 osec->finalizeInputSections(); in writeARMCmseImportLib()
1472 osec->shName = shstrtab->addString(osec->name); in writeARMCmseImportLib()
1473 osec->size = isec->getSize(); in writeARMCmseImportLib()
1474 isec->finalizeContents(); in writeARMCmseImportLib()
1475 osec->offset = alignToPowerOf2(off, osec->addralign); in writeARMCmseImportLib()
1476 off = osec->offset + osec->size; in writeARMCmseImportLib()
1479 const uint64_t sectionHeaderOff = alignToPowerOf2(off, config->wordsize); in writeARMCmseImportLib()
1484 config->mmapOutputFile ? 0 : (unsigned)FileOutputBuffer::F_no_mmap; in writeARMCmseImportLib()
1485 unlinkAsync(config->cmseOutputLib); in writeARMCmseImportLib()
1487 FileOutputBuffer::create(config->cmseOutputLib, fileSize, flags); in writeARMCmseImportLib()
1489 error("failed to open " + config->cmseOutputLib + ": " + in writeARMCmseImportLib()
1496 uint8_t *const buf = buffer->getBufferStart(); in writeARMCmseImportLib()
1499 eHdr->e_type = ET_REL; in writeARMCmseImportLib()
1500 eHdr->e_entry = 0; in writeARMCmseImportLib()
1501 eHdr->e_shoff = sectionHeaderOff; in writeARMCmseImportLib()
1502 eHdr->e_ident[EI_CLASS] = ELFCLASS32; in writeARMCmseImportLib()
1503 eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB; in writeARMCmseImportLib()
1504 eHdr->e_ident[EI_VERSION] = EV_CURRENT; in writeARMCmseImportLib()
1505 eHdr->e_ident[EI_OSABI] = config->osabi; in writeARMCmseImportLib()
1506 eHdr->e_ident[EI_ABIVERSION] = 0; in writeARMCmseImportLib()
1507 eHdr->e_machine = EM_ARM; in writeARMCmseImportLib()
1508 eHdr->e_version = EV_CURRENT; in writeARMCmseImportLib()
1509 eHdr->e_flags = config->eflags; in writeARMCmseImportLib()
1510 eHdr->e_ehsize = sizeof(typename ELFT::Ehdr); in writeARMCmseImportLib()
1511 eHdr->e_phnum = 0; in writeARMCmseImportLib()
1512 eHdr->e_shentsize = sizeof(typename ELFT::Shdr); in writeARMCmseImportLib()
1513 eHdr->e_phoff = 0; in writeARMCmseImportLib()
1514 eHdr->e_phentsize = 0; in writeARMCmseImportLib()
1515 eHdr->e_shnum = shnum; in writeARMCmseImportLib()
1516 eHdr->e_shstrndx = shstrtab->getParent()->sectionIndex; in writeARMCmseImportLib()
1519 auto *sHdrs = reinterpret_cast<typename ELFT::Shdr *>(buf + eHdr->e_shoff); in writeARMCmseImportLib()
1521 osec->template writeHeaderTo<ELFT>(++sHdrs); in writeARMCmseImportLib()
1527 osec->template writeTo<ELFT>(buf + osec->offset, tg); in writeARMCmseImportLib()
1530 if (auto e = buffer->commit()) in writeARMCmseImportLib()
1531 fatal("failed to write output '" + buffer->getPath() + in writeARMCmseImportLib()