1 //===-- ExternalFunctions.cpp - Implement External Functions --------------===// 2 // 3 // This file contains both code to deal with invoking "external" functions, but 4 // also contains code that implements "exported" external functions. 5 // 6 // External functions in LLI are implemented by dlopen'ing the lli executable 7 // and using dlsym to look op the functions that we want to invoke. If a 8 // function is found, then the arguments are mangled and passed in to the 9 // function call. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "Interpreter.h" 14 #include "ExecutionAnnotations.h" 15 #include "llvm/Module.h" 16 #include "llvm/DerivedTypes.h" 17 #include "llvm/SymbolTable.h" 18 #include "llvm/Target/TargetData.h" 19 #include <map> 20 #include <dlfcn.h> 21 #include <link.h> 22 #include <math.h> 23 #include <stdio.h> 24 using std::vector; 25 using std::cout; 26 27 typedef GenericValue (*ExFunc)(FunctionType *, const vector<GenericValue> &); 28 static std::map<const Function *, ExFunc> Functions; 29 static std::map<std::string, ExFunc> FuncNames; 30 31 static Interpreter *TheInterpreter; 32 33 // getCurrentExecutablePath() - Return the directory that the lli executable 34 // lives in. 35 // 36 std::string Interpreter::getCurrentExecutablePath() const { 37 Dl_info Info; 38 if (dladdr(&TheInterpreter, &Info) == 0) return ""; 39 40 std::string LinkAddr(Info.dli_fname); 41 unsigned SlashPos = LinkAddr.rfind('/'); 42 if (SlashPos != std::string::npos) 43 LinkAddr.resize(SlashPos); // Trim the executable name off... 44 45 return LinkAddr; 46 } 47 48 49 static char getTypeID(const Type *Ty) { 50 switch (Ty->getPrimitiveID()) { 51 case Type::VoidTyID: return 'V'; 52 case Type::BoolTyID: return 'o'; 53 case Type::UByteTyID: return 'B'; 54 case Type::SByteTyID: return 'b'; 55 case Type::UShortTyID: return 'S'; 56 case Type::ShortTyID: return 's'; 57 case Type::UIntTyID: return 'I'; 58 case Type::IntTyID: return 'i'; 59 case Type::ULongTyID: return 'L'; 60 case Type::LongTyID: return 'l'; 61 case Type::FloatTyID: return 'F'; 62 case Type::DoubleTyID: return 'D'; 63 case Type::PointerTyID: return 'P'; 64 case Type::FunctionTyID: return 'M'; 65 case Type::StructTyID: return 'T'; 66 case Type::ArrayTyID: return 'A'; 67 case Type::OpaqueTyID: return 'O'; 68 default: return 'U'; 69 } 70 } 71 72 static ExFunc lookupFunction(const Function *M) { 73 // Function not found, look it up... start by figuring out what the 74 // composite function name should be. 75 std::string ExtName = "lle_"; 76 const FunctionType *MT = M->getFunctionType(); 77 for (unsigned i = 0; const Type *Ty = MT->getContainedType(i); ++i) 78 ExtName += getTypeID(Ty); 79 ExtName += "_" + M->getName(); 80 81 //cout << "Tried: '" << ExtName << "'\n"; 82 ExFunc FnPtr = FuncNames[ExtName]; 83 if (FnPtr == 0) 84 FnPtr = (ExFunc)dlsym(RTLD_DEFAULT, ExtName.c_str()); 85 if (FnPtr == 0) 86 FnPtr = FuncNames["lle_X_"+M->getName()]; 87 if (FnPtr == 0) // Try calling a generic function... if it exists... 88 FnPtr = (ExFunc)dlsym(RTLD_DEFAULT, ("lle_X_"+M->getName()).c_str()); 89 if (FnPtr != 0) 90 Functions.insert(std::make_pair(M, FnPtr)); // Cache for later 91 return FnPtr; 92 } 93 94 GenericValue Interpreter::callExternalMethod(Function *M, 95 const vector<GenericValue> &ArgVals) { 96 TheInterpreter = this; 97 98 // Do a lookup to see if the function is in our cache... this should just be a 99 // defered annotation! 100 std::map<const Function *, ExFunc>::iterator FI = Functions.find(M); 101 ExFunc Fn = (FI == Functions.end()) ? lookupFunction(M) : FI->second; 102 if (Fn == 0) { 103 cout << "Tried to execute an unknown external function: " 104 << M->getType()->getDescription() << " " << M->getName() << "\n"; 105 return GenericValue(); 106 } 107 108 // TODO: FIXME when types are not const! 109 GenericValue Result = Fn(const_cast<FunctionType*>(M->getFunctionType()), 110 ArgVals); 111 return Result; 112 } 113 114 115 //===----------------------------------------------------------------------===// 116 // Functions "exported" to the running application... 117 // 118 extern "C" { // Don't add C++ manglings to llvm mangling :) 119 120 // Implement void printstr([ubyte {x N}] *) 121 GenericValue lle_VP_printstr(FunctionType *M, 122 const vector<GenericValue> &ArgVal){ 123 assert(ArgVal.size() == 1 && "printstr only takes one argument!"); 124 cout << (char*)GVTOP(ArgVal[0]); 125 return GenericValue(); 126 } 127 128 // Implement 'void print(X)' for every type... 129 GenericValue lle_X_print(FunctionType *M, const vector<GenericValue> &ArgVals) { 130 assert(ArgVals.size() == 1 && "generic print only takes one argument!"); 131 132 Interpreter::print(M->getParamTypes()[0], ArgVals[0]); 133 return GenericValue(); 134 } 135 136 // Implement 'void printVal(X)' for every type... 137 GenericValue lle_X_printVal(FunctionType *M, 138 const vector<GenericValue> &ArgVal) { 139 assert(ArgVal.size() == 1 && "generic print only takes one argument!"); 140 141 // Specialize print([ubyte {x N} ] *) and print(sbyte *) 142 if (const PointerType *PTy = 143 dyn_cast<PointerType>(M->getParamTypes()[0].get())) 144 if (PTy->getElementType() == Type::SByteTy || 145 isa<ArrayType>(PTy->getElementType())) { 146 return lle_VP_printstr(M, ArgVal); 147 } 148 149 Interpreter::printValue(M->getParamTypes()[0], ArgVal[0]); 150 return GenericValue(); 151 } 152 153 // Implement 'void printString(X)' 154 // Argument must be [ubyte {x N} ] * or sbyte * 155 GenericValue lle_X_printString(FunctionType *M, 156 const vector<GenericValue> &ArgVal) { 157 assert(ArgVal.size() == 1 && "generic print only takes one argument!"); 158 return lle_VP_printstr(M, ArgVal); 159 } 160 161 // Implement 'void print<TYPE>(X)' for each primitive type or pointer type 162 #define PRINT_TYPE_FUNC(TYPENAME,TYPEID) \ 163 GenericValue lle_X_print##TYPENAME(FunctionType *M,\ 164 const vector<GenericValue> &ArgVal) {\ 165 assert(ArgVal.size() == 1 && "generic print only takes one argument!");\ 166 assert(M->getParamTypes()[0].get()->getPrimitiveID() == Type::TYPEID);\ 167 Interpreter::printValue(M->getParamTypes()[0], ArgVal[0]);\ 168 return GenericValue();\ 169 } 170 171 PRINT_TYPE_FUNC(SByte, SByteTyID) 172 PRINT_TYPE_FUNC(UByte, UByteTyID) 173 PRINT_TYPE_FUNC(Short, ShortTyID) 174 PRINT_TYPE_FUNC(UShort, UShortTyID) 175 PRINT_TYPE_FUNC(Int, IntTyID) 176 PRINT_TYPE_FUNC(UInt, UIntTyID) 177 PRINT_TYPE_FUNC(Long, LongTyID) 178 PRINT_TYPE_FUNC(ULong, ULongTyID) 179 PRINT_TYPE_FUNC(Float, FloatTyID) 180 PRINT_TYPE_FUNC(Double, DoubleTyID) 181 PRINT_TYPE_FUNC(Pointer, PointerTyID) 182 183 184 // void putchar(sbyte) 185 GenericValue lle_Vb_putchar(FunctionType *M, const vector<GenericValue> &Args) { 186 cout << Args[0].SByteVal; 187 return GenericValue(); 188 } 189 190 // int putchar(int) 191 GenericValue lle_ii_putchar(FunctionType *M, const vector<GenericValue> &Args) { 192 cout << ((char)Args[0].IntVal) << std::flush; 193 return Args[0]; 194 } 195 196 // void putchar(ubyte) 197 GenericValue lle_VB_putchar(FunctionType *M, const vector<GenericValue> &Args) { 198 cout << Args[0].SByteVal << std::flush; 199 return Args[0]; 200 } 201 202 // void __main() 203 GenericValue lle_V___main(FunctionType *M, const vector<GenericValue> &Args) { 204 return GenericValue(); 205 } 206 207 // void exit(int) 208 GenericValue lle_X_exit(FunctionType *M, const vector<GenericValue> &Args) { 209 TheInterpreter->exitCalled(Args[0]); 210 return GenericValue(); 211 } 212 213 // void abort(void) 214 GenericValue lle_X_abort(FunctionType *M, const vector<GenericValue> &Args) { 215 std::cerr << "***PROGRAM ABORTED***!\n"; 216 GenericValue GV; 217 GV.IntVal = 1; 218 TheInterpreter->exitCalled(GV); 219 return GenericValue(); 220 } 221 222 // void *malloc(uint) 223 GenericValue lle_X_malloc(FunctionType *M, const vector<GenericValue> &Args) { 224 assert(Args.size() == 1 && "Malloc expects one argument!"); 225 return PTOGV(malloc(Args[0].UIntVal)); 226 } 227 228 // void free(void *) 229 GenericValue lle_X_free(FunctionType *M, const vector<GenericValue> &Args) { 230 assert(Args.size() == 1); 231 free(GVTOP(Args[0])); 232 return GenericValue(); 233 } 234 235 // int atoi(char *) 236 GenericValue lle_X_atoi(FunctionType *M, const vector<GenericValue> &Args) { 237 assert(Args.size() == 1); 238 GenericValue GV; 239 GV.IntVal = atoi((char*)GVTOP(Args[0])); 240 return GV; 241 } 242 243 // double pow(double, double) 244 GenericValue lle_X_pow(FunctionType *M, const vector<GenericValue> &Args) { 245 assert(Args.size() == 2); 246 GenericValue GV; 247 GV.DoubleVal = pow(Args[0].DoubleVal, Args[1].DoubleVal); 248 return GV; 249 } 250 251 // double exp(double) 252 GenericValue lle_X_exp(FunctionType *M, const vector<GenericValue> &Args) { 253 assert(Args.size() == 1); 254 GenericValue GV; 255 GV.DoubleVal = exp(Args[0].DoubleVal); 256 return GV; 257 } 258 259 // double sqrt(double) 260 GenericValue lle_X_sqrt(FunctionType *M, const vector<GenericValue> &Args) { 261 assert(Args.size() == 1); 262 GenericValue GV; 263 GV.DoubleVal = sqrt(Args[0].DoubleVal); 264 return GV; 265 } 266 267 // double log(double) 268 GenericValue lle_X_log(FunctionType *M, const vector<GenericValue> &Args) { 269 assert(Args.size() == 1); 270 GenericValue GV; 271 GV.DoubleVal = log(Args[0].DoubleVal); 272 return GV; 273 } 274 275 // int isnan(double value); 276 GenericValue lle_X_isnan(FunctionType *F, const vector<GenericValue> &Args) { 277 assert(Args.size() == 1); 278 GenericValue GV; 279 GV.IntVal = isnan(Args[0].DoubleVal); 280 return GV; 281 } 282 283 // double floor(double) 284 GenericValue lle_X_floor(FunctionType *M, const vector<GenericValue> &Args) { 285 assert(Args.size() == 1); 286 GenericValue GV; 287 GV.DoubleVal = floor(Args[0].DoubleVal); 288 return GV; 289 } 290 291 // double drand48() 292 GenericValue lle_X_drand48(FunctionType *M, const vector<GenericValue> &Args) { 293 assert(Args.size() == 0); 294 GenericValue GV; 295 GV.DoubleVal = drand48(); 296 return GV; 297 } 298 299 // long lrand48() 300 GenericValue lle_X_lrand48(FunctionType *M, const vector<GenericValue> &Args) { 301 assert(Args.size() == 0); 302 GenericValue GV; 303 GV.IntVal = lrand48(); 304 return GV; 305 } 306 307 // void srand48(long) 308 GenericValue lle_X_srand48(FunctionType *M, const vector<GenericValue> &Args) { 309 assert(Args.size() == 1); 310 srand48(Args[0].IntVal); 311 return GenericValue(); 312 } 313 314 // void srand(uint) 315 GenericValue lle_X_srand(FunctionType *M, const vector<GenericValue> &Args) { 316 assert(Args.size() == 1); 317 srand(Args[0].UIntVal); 318 return GenericValue(); 319 } 320 321 // int puts(const char*) 322 GenericValue lle_X_puts(FunctionType *M, const vector<GenericValue> &Args) { 323 assert(Args.size() == 1); 324 GenericValue GV; 325 GV.IntVal = puts((char*)GVTOP(Args[0])); 326 return GV; 327 } 328 329 // int sprintf(sbyte *, sbyte *, ...) - a very rough implementation to make 330 // output useful. 331 GenericValue lle_X_sprintf(FunctionType *M, const vector<GenericValue> &Args) { 332 char *OutputBuffer = (char *)GVTOP(Args[0]); 333 const char *FmtStr = (const char *)GVTOP(Args[1]); 334 unsigned ArgNo = 2; 335 336 // printf should return # chars printed. This is completely incorrect, but 337 // close enough for now. 338 GenericValue GV; GV.IntVal = strlen(FmtStr); 339 while (1) { 340 switch (*FmtStr) { 341 case 0: return GV; // Null terminator... 342 default: // Normal nonspecial character 343 sprintf(OutputBuffer++, "%c", *FmtStr++); 344 break; 345 case '\\': { // Handle escape codes 346 sprintf(OutputBuffer, "%c%c", *FmtStr, *(FmtStr+1)); 347 FmtStr += 2; OutputBuffer += 2; 348 break; 349 } 350 case '%': { // Handle format specifiers 351 char FmtBuf[100] = "", Buffer[1000] = ""; 352 char *FB = FmtBuf; 353 *FB++ = *FmtStr++; 354 char Last = *FB++ = *FmtStr++; 355 unsigned HowLong = 0; 356 while (Last != 'c' && Last != 'd' && Last != 'i' && Last != 'u' && 357 Last != 'o' && Last != 'x' && Last != 'X' && Last != 'e' && 358 Last != 'E' && Last != 'g' && Last != 'G' && Last != 'f' && 359 Last != 'p' && Last != 's' && Last != '%') { 360 if (Last == 'l' || Last == 'L') HowLong++; // Keep track of l's 361 Last = *FB++ = *FmtStr++; 362 } 363 *FB = 0; 364 365 switch (Last) { 366 case '%': 367 sprintf(Buffer, FmtBuf); break; 368 case 'c': 369 sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break; 370 case 'd': case 'i': 371 case 'u': case 'o': 372 case 'x': case 'X': 373 if (HowLong >= 1) { 374 if (HowLong == 1) { 375 // Make sure we use %lld with a 64 bit argument because we might be 376 // compiling LLI on a 32 bit compiler. 377 unsigned Size = strlen(FmtBuf); 378 FmtBuf[Size] = FmtBuf[Size-1]; 379 FmtBuf[Size+1] = 0; 380 FmtBuf[Size-1] = 'l'; 381 } 382 sprintf(Buffer, FmtBuf, Args[ArgNo++].ULongVal); 383 } else 384 sprintf(Buffer, FmtBuf, Args[ArgNo++].IntVal); break; 385 case 'e': case 'E': case 'g': case 'G': case 'f': 386 sprintf(Buffer, FmtBuf, Args[ArgNo++].DoubleVal); break; 387 case 'p': 388 sprintf(Buffer, FmtBuf, (void*)GVTOP(Args[ArgNo++])); break; 389 case 's': 390 sprintf(Buffer, FmtBuf, (char*)GVTOP(Args[ArgNo++])); break; 391 default: cout << "<unknown printf code '" << *FmtStr << "'!>"; 392 ArgNo++; break; 393 } 394 strcpy(OutputBuffer, Buffer); 395 OutputBuffer += strlen(Buffer); 396 } 397 break; 398 } 399 } 400 } 401 402 // int printf(sbyte *, ...) - a very rough implementation to make output useful. 403 GenericValue lle_X_printf(FunctionType *M, const vector<GenericValue> &Args) { 404 char Buffer[10000]; 405 vector<GenericValue> NewArgs; 406 NewArgs.push_back(PTOGV(Buffer)); 407 NewArgs.insert(NewArgs.end(), Args.begin(), Args.end()); 408 GenericValue GV = lle_X_sprintf(M, NewArgs); 409 cout << Buffer; 410 return GV; 411 } 412 413 static void ByteswapSCANFResults(const char *Fmt, void *Arg0, void *Arg1, 414 void *Arg2, void *Arg3, void *Arg4, void *Arg5, 415 void *Arg6, void *Arg7, void *Arg8) { 416 void *Args[] = { Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, 0 }; 417 418 // Loop over the format string, munging read values as appropriate (performs 419 // byteswaps as neccesary). 420 unsigned ArgNo = 0; 421 while (*Fmt) { 422 if (*Fmt++ == '%') { 423 // Read any flag characters that may be present... 424 bool Suppress = false; 425 bool Half = false; 426 bool Long = false; 427 bool LongLong = false; // long long or long double 428 429 while (1) { 430 switch (*Fmt++) { 431 case '*': Suppress = true; break; 432 case 'a': /*Allocate = true;*/ break; // We don't need to track this 433 case 'h': Half = true; break; 434 case 'l': Long = true; break; 435 case 'q': 436 case 'L': LongLong = true; break; 437 default: 438 if (Fmt[-1] > '9' || Fmt[-1] < '0') // Ignore field width specs 439 goto Out; 440 } 441 } 442 Out: 443 444 // Read the conversion character 445 if (!Suppress && Fmt[-1] != '%') { // Nothing to do? 446 unsigned Size = 0; 447 const Type *Ty = 0; 448 449 switch (Fmt[-1]) { 450 case 'i': case 'o': case 'u': case 'x': case 'X': case 'n': case 'p': 451 case 'd': 452 if (Long || LongLong) { 453 Size = 8; Ty = Type::ULongTy; 454 } else if (Half) { 455 Size = 4; Ty = Type::UShortTy; 456 } else { 457 Size = 4; Ty = Type::UIntTy; 458 } 459 break; 460 461 case 'e': case 'g': case 'E': 462 case 'f': 463 if (Long || LongLong) { 464 Size = 8; Ty = Type::DoubleTy; 465 } else { 466 Size = 4; Ty = Type::FloatTy; 467 } 468 break; 469 470 case 's': case 'c': case '[': // No byteswap needed 471 Size = 1; 472 Ty = Type::SByteTy; 473 break; 474 475 default: break; 476 } 477 478 if (Size) { 479 GenericValue GV; 480 void *Arg = Args[ArgNo++]; 481 memcpy(&GV, Arg, Size); 482 TheInterpreter->StoreValueToMemory(GV, (GenericValue*)Arg, Ty); 483 } 484 } 485 } 486 } 487 } 488 489 // int sscanf(const char *format, ...); 490 GenericValue lle_X_sscanf(FunctionType *M, const vector<GenericValue> &args) { 491 assert(args.size() < 10 && "Only handle up to 10 args to sscanf right now!"); 492 493 char *Args[10]; 494 for (unsigned i = 0; i < args.size(); ++i) 495 Args[i] = (char*)GVTOP(args[i]); 496 497 GenericValue GV; 498 GV.IntVal = sscanf(Args[0], Args[1], Args[2], Args[3], Args[4], 499 Args[5], Args[6], Args[7], Args[8], Args[9]); 500 ByteswapSCANFResults(Args[1], Args[2], Args[3], Args[4], 501 Args[5], Args[6], Args[7], Args[8], Args[9], 0); 502 return GV; 503 } 504 505 // int scanf(const char *format, ...); 506 GenericValue lle_X_scanf(FunctionType *M, const vector<GenericValue> &args) { 507 assert(args.size() < 10 && "Only handle up to 10 args to scanf right now!"); 508 509 char *Args[10]; 510 for (unsigned i = 0; i < args.size(); ++i) 511 Args[i] = (char*)GVTOP(args[i]); 512 513 GenericValue GV; 514 GV.IntVal = scanf(Args[0], Args[1], Args[2], Args[3], Args[4], 515 Args[5], Args[6], Args[7], Args[8], Args[9]); 516 ByteswapSCANFResults(Args[0], Args[1], Args[2], Args[3], Args[4], 517 Args[5], Args[6], Args[7], Args[8], Args[9]); 518 return GV; 519 } 520 521 522 // int clock(void) - Profiling implementation 523 GenericValue lle_i_clock(FunctionType *M, const vector<GenericValue> &Args) { 524 extern int clock(void); 525 GenericValue GV; GV.IntVal = clock(); 526 return GV; 527 } 528 529 //===----------------------------------------------------------------------===// 530 // IO Functions... 531 //===----------------------------------------------------------------------===// 532 533 // getFILE - Turn a pointer in the host address space into a legit pointer in 534 // the interpreter address space. For the most part, this is an identity 535 // transformation, but if the program refers to stdio, stderr, stdin then they 536 // have pointers that are relative to the __iob array. If this is the case, 537 // change the FILE into the REAL stdio stream. 538 // 539 static FILE *getFILE(void *Ptr) { 540 static Module *LastMod = 0; 541 static PointerTy IOBBase = 0; 542 static unsigned FILESize; 543 544 if (LastMod != &TheInterpreter->getModule()) { // Module change or initialize? 545 Module *M = LastMod = &TheInterpreter->getModule(); 546 547 // Check to see if the currently loaded module contains an __iob symbol... 548 GlobalVariable *IOB = 0; 549 SymbolTable &ST = M->getSymbolTable(); 550 for (SymbolTable::iterator I = ST.begin(), E = ST.end(); I != E; ++I) { 551 SymbolTable::VarMap &M = I->second; 552 for (SymbolTable::VarMap::iterator J = M.begin(), E = M.end(); 553 J != E; ++J) 554 if (J->first == "__iob") 555 if ((IOB = dyn_cast<GlobalVariable>(J->second))) 556 break; 557 if (IOB) break; 558 } 559 560 #if 0 /// FIXME! __iob support for LLI 561 // If we found an __iob symbol now, find out what the actual address it's 562 // held in is... 563 if (IOB) { 564 // Get the address the array lives in... 565 GlobalAddress *Address = 566 (GlobalAddress*)IOB->getOrCreateAnnotation(GlobalAddressAID); 567 IOBBase = (PointerTy)(GenericValue*)Address->Ptr; 568 569 // Figure out how big each element of the array is... 570 const ArrayType *AT = 571 dyn_cast<ArrayType>(IOB->getType()->getElementType()); 572 if (AT) 573 FILESize = TD.getTypeSize(AT->getElementType()); 574 else 575 FILESize = 16*8; // Default size 576 } 577 #endif 578 } 579 580 // Check to see if this is a reference to __iob... 581 if (IOBBase) { 582 unsigned FDNum = ((unsigned long)Ptr-IOBBase)/FILESize; 583 if (FDNum == 0) 584 return stdin; 585 else if (FDNum == 1) 586 return stdout; 587 else if (FDNum == 2) 588 return stderr; 589 } 590 591 return (FILE*)Ptr; 592 } 593 594 595 // FILE *fopen(const char *filename, const char *mode); 596 GenericValue lle_X_fopen(FunctionType *M, const vector<GenericValue> &Args) { 597 assert(Args.size() == 2); 598 return PTOGV(fopen((const char *)GVTOP(Args[0]), 599 (const char *)GVTOP(Args[1]))); 600 } 601 602 // int fclose(FILE *F); 603 GenericValue lle_X_fclose(FunctionType *M, const vector<GenericValue> &Args) { 604 assert(Args.size() == 1); 605 GenericValue GV; 606 GV.IntVal = fclose(getFILE(GVTOP(Args[0]))); 607 return GV; 608 } 609 610 // int feof(FILE *stream); 611 GenericValue lle_X_feof(FunctionType *M, const vector<GenericValue> &Args) { 612 assert(Args.size() == 1); 613 GenericValue GV; 614 615 GV.IntVal = feof(getFILE(GVTOP(Args[0]))); 616 return GV; 617 } 618 619 // size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream); 620 GenericValue lle_X_fread(FunctionType *M, const vector<GenericValue> &Args) { 621 assert(Args.size() == 4); 622 GenericValue GV; 623 624 GV.UIntVal = fread((void*)GVTOP(Args[0]), Args[1].UIntVal, 625 Args[2].UIntVal, getFILE(GVTOP(Args[3]))); 626 return GV; 627 } 628 629 // size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream); 630 GenericValue lle_X_fwrite(FunctionType *M, const vector<GenericValue> &Args) { 631 assert(Args.size() == 4); 632 GenericValue GV; 633 634 GV.UIntVal = fwrite((void*)GVTOP(Args[0]), Args[1].UIntVal, 635 Args[2].UIntVal, getFILE(GVTOP(Args[3]))); 636 return GV; 637 } 638 639 // char *fgets(char *s, int n, FILE *stream); 640 GenericValue lle_X_fgets(FunctionType *M, const vector<GenericValue> &Args) { 641 assert(Args.size() == 3); 642 return GVTOP(fgets((char*)GVTOP(Args[0]), Args[1].IntVal, 643 getFILE(GVTOP(Args[2])))); 644 } 645 646 // FILE *freopen(const char *path, const char *mode, FILE *stream); 647 GenericValue lle_X_freopen(FunctionType *M, const vector<GenericValue> &Args) { 648 assert(Args.size() == 3); 649 return PTOGV(freopen((char*)GVTOP(Args[0]), (char*)GVTOP(Args[1]), 650 getFILE(GVTOP(Args[2])))); 651 } 652 653 // int fflush(FILE *stream); 654 GenericValue lle_X_fflush(FunctionType *M, const vector<GenericValue> &Args) { 655 assert(Args.size() == 1); 656 GenericValue GV; 657 GV.IntVal = fflush(getFILE(GVTOP(Args[0]))); 658 return GV; 659 } 660 661 // int getc(FILE *stream); 662 GenericValue lle_X_getc(FunctionType *M, const vector<GenericValue> &Args) { 663 assert(Args.size() == 1); 664 GenericValue GV; 665 GV.IntVal = getc(getFILE(GVTOP(Args[0]))); 666 return GV; 667 } 668 669 // int fputc(int C, FILE *stream); 670 GenericValue lle_X_fputc(FunctionType *M, const vector<GenericValue> &Args) { 671 assert(Args.size() == 2); 672 GenericValue GV; 673 GV.IntVal = fputc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); 674 return GV; 675 } 676 677 // int ungetc(int C, FILE *stream); 678 GenericValue lle_X_ungetc(FunctionType *M, const vector<GenericValue> &Args) { 679 assert(Args.size() == 2); 680 GenericValue GV; 681 GV.IntVal = ungetc(Args[0].IntVal, getFILE(GVTOP(Args[1]))); 682 return GV; 683 } 684 685 // int fprintf(FILE *,sbyte *, ...) - a very rough implementation to make output 686 // useful. 687 GenericValue lle_X_fprintf(FunctionType *M, const vector<GenericValue> &Args) { 688 assert(Args.size() > 2); 689 char Buffer[10000]; 690 vector<GenericValue> NewArgs; 691 NewArgs.push_back(PTOGV(Buffer)); 692 NewArgs.insert(NewArgs.end(), Args.begin()+1, Args.end()); 693 GenericValue GV = lle_X_sprintf(M, NewArgs); 694 695 fputs(Buffer, getFILE(GVTOP(Args[0]))); 696 return GV; 697 } 698 699 } // End extern "C" 700 701 702 void Interpreter::initializeExternalMethods() { 703 FuncNames["lle_VP_printstr"] = lle_VP_printstr; 704 FuncNames["lle_X_print"] = lle_X_print; 705 FuncNames["lle_X_printVal"] = lle_X_printVal; 706 FuncNames["lle_X_printString"] = lle_X_printString; 707 FuncNames["lle_X_printUByte"] = lle_X_printUByte; 708 FuncNames["lle_X_printSByte"] = lle_X_printSByte; 709 FuncNames["lle_X_printUShort"] = lle_X_printUShort; 710 FuncNames["lle_X_printShort"] = lle_X_printShort; 711 FuncNames["lle_X_printInt"] = lle_X_printInt; 712 FuncNames["lle_X_printUInt"] = lle_X_printUInt; 713 FuncNames["lle_X_printLong"] = lle_X_printLong; 714 FuncNames["lle_X_printULong"] = lle_X_printULong; 715 FuncNames["lle_X_printFloat"] = lle_X_printFloat; 716 FuncNames["lle_X_printDouble"] = lle_X_printDouble; 717 FuncNames["lle_X_printPointer"] = lle_X_printPointer; 718 FuncNames["lle_Vb_putchar"] = lle_Vb_putchar; 719 FuncNames["lle_ii_putchar"] = lle_ii_putchar; 720 FuncNames["lle_VB_putchar"] = lle_VB_putchar; 721 FuncNames["lle_V___main"] = lle_V___main; 722 FuncNames["lle_X_exit"] = lle_X_exit; 723 FuncNames["lle_X_abort"] = lle_X_abort; 724 FuncNames["lle_X_malloc"] = lle_X_malloc; 725 FuncNames["lle_X_free"] = lle_X_free; 726 FuncNames["lle_X_atoi"] = lle_X_atoi; 727 FuncNames["lle_X_pow"] = lle_X_pow; 728 FuncNames["lle_X_exp"] = lle_X_exp; 729 FuncNames["lle_X_log"] = lle_X_log; 730 FuncNames["lle_X_isnan"] = lle_X_isnan; 731 FuncNames["lle_X_floor"] = lle_X_floor; 732 FuncNames["lle_X_srand"] = lle_X_srand; 733 FuncNames["lle_X_drand48"] = lle_X_drand48; 734 FuncNames["lle_X_srand48"] = lle_X_srand48; 735 FuncNames["lle_X_lrand48"] = lle_X_lrand48; 736 FuncNames["lle_X_sqrt"] = lle_X_sqrt; 737 FuncNames["lle_X_puts"] = lle_X_puts; 738 FuncNames["lle_X_printf"] = lle_X_printf; 739 FuncNames["lle_X_sprintf"] = lle_X_sprintf; 740 FuncNames["lle_X_sscanf"] = lle_X_sscanf; 741 FuncNames["lle_X_scanf"] = lle_X_scanf; 742 FuncNames["lle_i_clock"] = lle_i_clock; 743 FuncNames["lle_X_fopen"] = lle_X_fopen; 744 FuncNames["lle_X_fclose"] = lle_X_fclose; 745 FuncNames["lle_X_feof"] = lle_X_feof; 746 FuncNames["lle_X_fread"] = lle_X_fread; 747 FuncNames["lle_X_fwrite"] = lle_X_fwrite; 748 FuncNames["lle_X_fgets"] = lle_X_fgets; 749 FuncNames["lle_X_fflush"] = lle_X_fflush; 750 FuncNames["lle_X_fgetc"] = lle_X_getc; 751 FuncNames["lle_X_getc"] = lle_X_getc; 752 FuncNames["lle_X_fputc"] = lle_X_fputc; 753 FuncNames["lle_X_ungetc"] = lle_X_ungetc; 754 FuncNames["lle_X_fprintf"] = lle_X_fprintf; 755 FuncNames["lle_X_freopen"] = lle_X_freopen; 756 } 757