//===----------------------------------------------------------------------===// // LLVM 'ar' UTILITY // // This utility may be invoked in the following manner: // llvm-ar archivename files.. // //===----------------------------------------------------------------------===// #include "Support/CommandLine.h" #include "llvm/Bytecode/Reader.h" #include "llvm/Module.h" #include #include #include #include #include #include #include #include #include #include using std::string; using std::vector; using std::cout; #define ARFMAG "\n" /* header trailer string */ #define ARMAG "!\n" /* magic string */ #define SARMAG 8 /* length of magic string */ namespace { // Each file member is preceded by a file member header. Which is // of the following format: // // char ar_name[16] - '/' terminated file member name. // If the file name does not fit, a dummy name is used. // char ar_date[12] - file date in decimal // char ar_uid[6] - User id of file owner in decimal. // char ar_gid[6] - Group ID file belongs to in decimal. // char ar_mode[8] - File mode in octal. // char ar_size[10] - Size of file in decimal. // char ar_fmag[2] - Trailer of header file, a newline. struct ar_hdr { char name[16]; char date[12]; char uid[6]; char gid[6]; char mode[8]; char size[10]; char fmag[2]; void init() { memset(name,' ',16); memset(date,' ',12); memset(uid,' ',6); memset(gid,' ',6); memset(mode,' ',8); memset(size,' ',10); memset(fmag,' ',2); } }; } //Option to generate symbol table or not //running llvm-ar -s is the same as ranlib cl::opt SymbolTable ("s", cl::desc("Generate an archive symbol table")); //Archive name cl::opt Archive (cl::Positional, cl::desc(""), cl::Required); //For now we require one or more member files, this should change so //we can just run llvm-ar -s on an archive to generate the symbol //table cl::list Members(cl::ConsumeAfter, cl::desc("...")); static inline bool Error(std::string *ErrorStr, const char *Message) { if (ErrorStr) *ErrorStr = Message; return true; } // WriteSymbolTable - Writes symbol table to ArchiveFile, return false // on errors. Also returns by reference size of symbol table. // // Overview of method: // 1) Generate the header for the symbol table. This is a normal // archive member header, but it has a zero length name. // 2) For each archive member file, stat the file and parse the bytecode // Store cummulative offset (file size + header size). // 3) Loop over all the symbols for the current member file, // add offset entry to offset vector, and add symbol name to its vector. // Note: The symbol name vector is a vector of chars to speed up calculating // the total size of the symbol table. // 4) Update offset vector once we know the total size of symbol table. This is // because the symbol table appears before all archive member file contents. // We add the size of magic string, and size of symbol table to each offset. // 5) If the new updated offset it not even, we add 1 byte to offset because // a newline will be inserted when writing member files. This adjustment is // cummulative (ie. each time we have an odd offset we add 1 to total adjustment). // 6) Lastly, write symbol table to file. // bool WriteSymbolTable(std::ofstream &ArchiveFile) { //Create header for symbol table. This is essentially an empty header with the //name set to a '/' to indicate its a symbol table. ar_hdr Hdr; Hdr.init(); //Name of symbol table is '/' Hdr.name[0] = '/'; Hdr.name[1] = '/0'; //Set the header trailer to a newline memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG)); //Write header to archive file ArchiveFile.write((char*)&Hdr, sizeof(Hdr)); unsigned memoff = 0; //Keep Track of total size of files added to archive vector offsets; //Vector of offsets into archive file vector names; //Vector of characters that are the symbol names. //Loop over archive member files, parse bytecode, and generate symbol table. for(unsigned i=0; ibegin(), E=M->end(); I != E; ++I) { //get function name string NM = ((Function*)I)->getName(); //Loop over the characters in the name and add to symbol name vector for(unsigned i=0; i> 24) & 255; num[1] = (temp >> 16) & 255; num[2] = (temp >> 8) & 255; num[3] = temp & 255; //Write number of symbols to archive file ArchiveFile.write(num,4); //Adjustment to offset to start files on even byte boundaries unsigned adjust = 0; //Update offsets write symbol tabel to archive. for(unsigned i=0; i> 24) & 255; output[1] = (offsets[i] >> 16) & 255; output[2] = (offsets[i] >> 8) & 255; output[3] = offsets[i] & 255; ArchiveFile.write(output,4); } //Write out symbol name vector. for(unsigned i=0; i