//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Builds up standard unix archive files (.a) containing LLVM bytecode. // //===----------------------------------------------------------------------===// #include "llvm/Module.h" #include "llvm/Bytecode/Reader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/System/Signals.h" #include #include #include #include #include #include #include #include #include using namespace llvm; using std::string; #define ARFMAG "\n" /* header trailer string */ #define ARMAG "!\n" /* magic string */ #define SARMAG 8 /* length of magic string */ #define VERSION "llvm-ar is a part of the LLVM compiler infrastructure.\nPlease see http://llvm.cs.uiuc.edu for more information.\n"; // 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 for X32_64, not used but must allow it to be present. cl::opt X32Option ("X32_64", cl::desc("Ignored option spelt -X32_64, for compatibility with AIX"), cl::Optional); //llvm-ar options cl::opt Options(cl::Positional, cl::desc("{dmpqrstx}[abcfilNoPsSuvV] "), cl::Required); //llvm-ar options cl::list RestofArgs(cl::Positional, cl::desc("[relpos] [count]] [members..]"), cl::Optional); //booleans to represent Operation, only one can be preformed at a time bool Print, Delete, Move, QuickAppend, InsertWithReplacement, DisplayTable; bool Extract; //Modifiers to follow operation to vary behavior bool AddAfter, AddBefore, Create, TruncateNames, InsertBefore, UseCount; bool OriginalDates, FullPath, SymTable, OnlyUpdate, Verbose; //Realtive Pos Arg string RelPos; //Count, use for multiple entries in the archive with the same name int Count; //Archive string Archive; //Member Files std::vector Members; // 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 cumulative 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 std::vector offsets; //Vector of offsets into archive file std::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 table 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 0) { RelPos = RestofArgs[0]; RestofArgs.erase(RestofArgs.begin()); } //Throw error if needed and not present else printUse(); } //Extract count from the command line void getCount() { if(RestofArgs.size() > 0) { Count = atoi(RestofArgs[0].c_str()); RestofArgs.erase(RestofArgs.begin()); } //Throw error if needed and not present else printUse(); } //Get the Archive File Name from the command line void getArchive() { std::cerr << RestofArgs.size() << "\n"; if(RestofArgs.size() > 0) { Archive = RestofArgs[0]; RestofArgs.erase(RestofArgs.begin()); } //Throw error if needed and not present else printUse(); } //Copy over remaining items in RestofArgs to our Member File vector. //This is just for clarity. void getMembers() { std::cerr << RestofArgs.size() << "\n"; if(RestofArgs.size() > 0) Members = std::vector(RestofArgs); } // Parse the operations and operation modifiers // FIXME: Not all of these options has been implemented, but we still // do all the command line parsing for them. void parseCL() { //Keep track of number of operations. We can only specify one //per execution unsigned NumOperations = 0; for(unsigned i=0; i 1) printUse(); getArchive(); getMembers(); } int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); sys::PrintStackTraceOnErrorSignal(); parseCL(); //Create archive! if(Create) CreateArchive(); return 0; }