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