... | ... |
@@ -268,9 +268,8 @@ static inline operand_t readOperand(struct cli_bc_func *func, unsigned char *p, |
268 | 268 |
*dest= 0; |
269 | 269 |
ty = 8*readFixedNumber(p, off, len, ok, 1); |
270 | 270 |
if (!ty) { |
271 |
- cli_errmsg("bytecode: void type constant is invalid!\n"); |
|
272 |
- *ok = 0; |
|
273 |
- return MAX_OP; |
|
271 |
+ /* This is a global variable */ |
|
272 |
+ return 0x80000000 | v; |
|
274 | 273 |
} |
275 | 274 |
if (ty <= 8) |
276 | 275 |
*(uint8_t*)dest = v; |
... | ... |
@@ -652,6 +651,99 @@ static int parseApis(struct cli_bc *bc, unsigned char *buffer) |
652 | 652 |
return CL_SUCCESS; |
653 | 653 |
} |
654 | 654 |
|
655 |
+static uint16_t type_components(struct cli_bc *bc, uint16_t id, char *ok) |
|
656 |
+{ |
|
657 |
+ unsigned i, sum=0; |
|
658 |
+ const struct cli_bc_type *ty; |
|
659 |
+ if (id <= 64) |
|
660 |
+ return 1; |
|
661 |
+ ty = &bc->types[id-65]; |
|
662 |
+ /* TODO: protect against recursive types */ |
|
663 |
+ switch (ty->kind) { |
|
664 |
+ case DFunctionType: |
|
665 |
+ cli_errmsg("bytecode: function type not accepted for constant: %u\n", id); |
|
666 |
+ /* don't accept functions as constant initializers */ |
|
667 |
+ *ok = 0; |
|
668 |
+ return 0; |
|
669 |
+ case DPointerType: |
|
670 |
+ cli_errmsg("bytecode: pointer type not accepted for constant: %u\n", id); |
|
671 |
+ /* don't accept pointer initializers */ |
|
672 |
+ *ok = 0; |
|
673 |
+ return 0; |
|
674 |
+ case DStructType: |
|
675 |
+ case DPackedStructType: |
|
676 |
+ for (i=0;i<ty->numElements;i++) { |
|
677 |
+ sum += type_components(bc, ty->containedTypes[i], ok); |
|
678 |
+ } |
|
679 |
+ return sum; |
|
680 |
+ case DArrayType: |
|
681 |
+ return type_components(bc, ty->containedTypes[0], ok)*ty->numElements; |
|
682 |
+ default: |
|
683 |
+ *ok = 0; |
|
684 |
+ return 0; |
|
685 |
+ } |
|
686 |
+} |
|
687 |
+ |
|
688 |
+static void readConstant(struct cli_bc *bc, unsigned i, unsigned comp, |
|
689 |
+ unsigned char *buffer, unsigned *offset, |
|
690 |
+ unsigned len, char *ok) |
|
691 |
+{ |
|
692 |
+ unsigned j=0; |
|
693 |
+ while (*ok && buffer[*offset] != 0x60) { |
|
694 |
+ if (j > comp) { |
|
695 |
+ cli_errmsg("bytecode: constant has too many subcomponents, expected %u\n", comp); |
|
696 |
+ *ok = 0; |
|
697 |
+ return; |
|
698 |
+ } |
|
699 |
+ buffer[*offset] |= 0x20; |
|
700 |
+ bc->globals[i][j++] = readNumber(buffer, offset, len, ok); |
|
701 |
+ } |
|
702 |
+ if (*ok && j != comp) { |
|
703 |
+ cli_errmsg("bytecode: constant has too few subcomponents: %u < %u\n", j, comp); |
|
704 |
+ } |
|
705 |
+ *offset++; |
|
706 |
+} |
|
707 |
+ |
|
708 |
+/* parse constant globals with constant initializers */ |
|
709 |
+static int parseGlobals(struct cli_bc *bc, unsigned char *buffer) |
|
710 |
+{ |
|
711 |
+ unsigned i, offset = 1, len = strlen((const char*)buffer), numglobals; |
|
712 |
+ char ok=1; |
|
713 |
+ |
|
714 |
+ if (buffer[0] != 'G') { |
|
715 |
+ cli_errmsg("bytecode: Invalid globals header: %c\n", buffer[0]); |
|
716 |
+ return CL_EMALFDB; |
|
717 |
+ } |
|
718 |
+ numglobals = readNumber(buffer, &offset, len, &ok); |
|
719 |
+ bc->globals = cli_calloc(numglobals, sizeof(*bc->globals)); |
|
720 |
+ if (!bc->globals) { |
|
721 |
+ cli_errmsg("bytecode: OOM allocating memory for %u globals\n", numglobals); |
|
722 |
+ return CL_EMEM; |
|
723 |
+ } |
|
724 |
+ bc->globaltys = cli_calloc(numglobals, sizeof(*bc->globaltys)); |
|
725 |
+ if (!bc->globaltys) { |
|
726 |
+ cli_errmsg("bytecode: OOM allocating memory for %u global types\n", numglobals); |
|
727 |
+ return CL_EMEM; |
|
728 |
+ } |
|
729 |
+ bc->num_globals = numglobals; |
|
730 |
+ if (!ok) |
|
731 |
+ return CL_EMALFDB; |
|
732 |
+ for (i=0;i<numglobals;i++) { |
|
733 |
+ unsigned comp; |
|
734 |
+ bc->globaltys[i] = readTypeID(bc, buffer, &offset, len, &ok); |
|
735 |
+ comp = type_components(bc, bc->globaltys[i], &ok); |
|
736 |
+ if (!ok) |
|
737 |
+ return CL_EMALFDB; |
|
738 |
+ bc->globals[i] = cli_malloc(sizeof(bc->globals[0])*comp); |
|
739 |
+ if (!bc->globals[i]) |
|
740 |
+ return CL_EMEM; |
|
741 |
+ readConstant(bc, i, comp, buffer, &offset, len, &ok); |
|
742 |
+ } |
|
743 |
+ if (!ok) |
|
744 |
+ return CL_EMALFDB; |
|
745 |
+ return CL_SUCCESS; |
|
746 |
+} |
|
747 |
+ |
|
655 | 748 |
static int parseFunctionHeader(struct cli_bc *bc, unsigned fn, unsigned char *buffer) |
656 | 749 |
{ |
657 | 750 |
char ok=1; |
... | ... |
@@ -921,6 +1013,7 @@ enum parse_state { |
921 | 921 |
PARSE_BC_HEADER=0, |
922 | 922 |
PARSE_BC_TYPES, |
923 | 923 |
PARSE_BC_APIS, |
924 |
+ PARSE_BC_GLOBALS, |
|
924 | 925 |
PARSE_FUNC_HEADER, |
925 | 926 |
PARSE_BB |
926 | 927 |
}; |
... | ... |
@@ -970,6 +1063,18 @@ int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio) |
970 | 970 |
cli_errmsg("Error at bytecode line %u\n", row); |
971 | 971 |
return rc; |
972 | 972 |
} |
973 |
+ state = PARSE_BC_GLOBALS; |
|
974 |
+ break; |
|
975 |
+ case PARSE_BC_GLOBALS: |
|
976 |
+ rc = parseGlobals(bc, (unsigned char*)buffer); |
|
977 |
+ if (rc == CL_BREAK) /* skip */ { |
|
978 |
+ bc->state = bc_skip; |
|
979 |
+ return CL_SUCCESS; |
|
980 |
+ } |
|
981 |
+ if (rc != CL_SUCCESS) { |
|
982 |
+ cli_errmsg("Error at bytecode line %u\n", row); |
|
983 |
+ return rc; |
|
984 |
+ } |
|
973 | 985 |
state = PARSE_FUNC_HEADER; |
974 | 986 |
break; |
975 | 987 |
case PARSE_FUNC_HEADER: |
... | ... |
@@ -1079,6 +1184,11 @@ void cli_bytecode_destroy(struct cli_bc *bc) |
1079 | 1079 |
free(bc->types[i].containedTypes); |
1080 | 1080 |
} |
1081 | 1081 |
free(bc->types); |
1082 |
+ for (i=0;i<bc->num_globals;i++) { |
|
1083 |
+ free(bc->globals[i]); |
|
1084 |
+ } |
|
1085 |
+ free(bc->globals); |
|
1086 |
+ free(bc->globaltys); |
|
1082 | 1087 |
if (bc->uses_apis) |
1083 | 1088 |
cli_bitset_free(bc->uses_apis); |
1084 | 1089 |
} |
... | ... |
@@ -187,6 +187,7 @@ private: |
187 | 187 |
ExecutionEngine *EE; |
188 | 188 |
TargetFolder Folder; |
189 | 189 |
IRBuilder<false, TargetFolder> Builder; |
190 |
+ std::vector<GlobalVariable*> globals; |
|
190 | 191 |
Value **Values; |
191 | 192 |
FunctionPassManager &PM; |
192 | 193 |
unsigned numLocals; |
... | ... |
@@ -229,6 +230,12 @@ private: |
229 | 229 |
if (operand < func->numValues) |
230 | 230 |
return Builder.CreateLoad(Values[operand]); |
231 | 231 |
|
232 |
+ if (operand & 0x80000000) { |
|
233 |
+ operand &= 0x7fffffff; |
|
234 |
+ assert(operand < globals.size() && "Global index out of range"); |
|
235 |
+ // Global |
|
236 |
+ return globals[operand]; |
|
237 |
+ } |
|
232 | 238 |
// Constant |
233 | 239 |
operand -= func->numValues; |
234 | 240 |
// This was already validated by libclamav. |
... | ... |
@@ -282,6 +289,33 @@ private: |
282 | 282 |
{ |
283 | 283 |
return TypeMap->get(typeID); |
284 | 284 |
} |
285 |
+ |
|
286 |
+ Constant *buildConstant(const Type *Ty, uint64_t *components, unsigned &c) |
|
287 |
+ { |
|
288 |
+ if (isa<IntegerType>(Ty)) { |
|
289 |
+ return ConstantInt::get(Ty, components[c++]); |
|
290 |
+ } |
|
291 |
+ if (const ArrayType *ATy = dyn_cast<ArrayType>(Ty)) { |
|
292 |
+ std::vector<Constant*> elements; |
|
293 |
+ elements.reserve(ATy->getNumElements()); |
|
294 |
+ for (unsigned i=0;i<ATy->getNumElements();i++) { |
|
295 |
+ elements.push_back(buildConstant(ATy->getElementType(), components, c)); |
|
296 |
+ } |
|
297 |
+ return ConstantArray::get(ATy, elements); |
|
298 |
+ } |
|
299 |
+ if (const StructType *STy = dyn_cast<StructType>(Ty)) { |
|
300 |
+ std::vector<Constant*> elements; |
|
301 |
+ elements.reserve(STy->getNumElements()); |
|
302 |
+ for (unsigned i=0;i<STy->getNumElements();i++) { |
|
303 |
+ elements.push_back(buildConstant(STy->getElementType(i), components, c)); |
|
304 |
+ } |
|
305 |
+ return ConstantStruct::get(STy, elements); |
|
306 |
+ } |
|
307 |
+ Ty->dump(); |
|
308 |
+ assert(0 && "Not reached"); |
|
309 |
+ return 0; |
|
310 |
+ } |
|
311 |
+ |
|
285 | 312 |
public: |
286 | 313 |
LLVMCodegen(const struct cli_bc *bc, Module *M, FunctionMapTy &cFuncs, |
287 | 314 |
ExecutionEngine *EE, FunctionPassManager &PM, Function **apiFuncs) |
... | ... |
@@ -302,11 +336,22 @@ public: |
302 | 302 |
FHandler->setDoesNotReturn(); |
303 | 303 |
FHandler->setDoesNotThrow(); |
304 | 304 |
FHandler->addFnAttr(Attribute::NoInline); |
305 |
- EE->addGlobalMapping(FHandler, (void*)jit_exception_handler); |
|
305 |
+ EE->addGlobalMapping(FHandler, (void*)jit_exception_handler); |
|
306 | 306 |
|
307 | 307 |
// The hidden ctx param to all functions |
308 | 308 |
const Type *HiddenCtx = PointerType::getUnqual(Type::getInt8Ty(Context)); |
309 | 309 |
|
310 |
+ globals.reserve(bc->num_globals); |
|
311 |
+ for (unsigned i=0;i<bc->num_globals;i++) { |
|
312 |
+ const Type *Ty = mapType(bc->globaltys[i]); |
|
313 |
+ GlobalVariable *GV = cast<GlobalVariable>(M->getOrInsertGlobal("glob"+i, |
|
314 |
+ Ty)); |
|
315 |
+ // TODO: validate number of components against type_components |
|
316 |
+ unsigned c = 0; |
|
317 |
+ GV->setInitializer(buildConstant(Ty, bc->globals[i], c)); |
|
318 |
+ globals.push_back(GV); |
|
319 |
+ } |
|
320 |
+ |
|
310 | 321 |
Function **Functions = new Function*[bc->num_func]; |
311 | 322 |
for (unsigned j=0;j<bc->num_func;j++) { |
312 | 323 |
PrettyStackTraceString CrashInfo("Generate LLVM IR functions"); |