1 //===-- tools/llvm-ar/llvm-ar.cpp - LLVM archive librarian utility --------===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
10 // Builds up standard unix archive files (.a) containing LLVM bytecode.
12 //===----------------------------------------------------------------------===//
14 #include "Support/CommandLine.h"
15 #include "llvm/Bytecode/Reader.h"
16 #include "llvm/Module.h"
23 #include <sys/types.h>
33 #define ARFMAG "\n" /* header trailer string */
34 #define ARMAG "!<arch>\n" /* magic string */
35 #define SARMAG 8 /* length of magic string */
39 // Each file member is preceded by a file member header. Which is
40 // of the following format:
42 // char ar_name[16] - '/' terminated file member name.
43 // If the file name does not fit, a dummy name is used.
44 // char ar_date[12] - file date in decimal
45 // char ar_uid[6] - User id of file owner in decimal.
46 // char ar_gid[6] - Group ID file belongs to in decimal.
47 // char ar_mode[8] - File mode in octal.
48 // char ar_size[10] - Size of file in decimal.
49 // char ar_fmag[2] - Trailer of header file, a newline.
70 //Option to generate symbol table or not
71 //running llvm-ar -s is the same as ranlib
72 cl::opt<bool> SymbolTable ("s", cl::desc("Generate an archive symbol table"));
75 cl::opt<string> Archive (cl::Positional, cl::desc("<archive file>"),
78 //For now we require one or more member files, this should change so
79 //we can just run llvm-ar -s on an archive to generate the symbol
81 cl::list<string> Members(cl::ConsumeAfter, cl::desc("<archive members>..."));
84 static inline bool Error(std::string *ErrorStr, const char *Message) {
85 if (ErrorStr) *ErrorStr = Message;
90 // WriteSymbolTable - Writes symbol table to ArchiveFile, return false
91 // on errors. Also returns by reference size of symbol table.
93 // Overview of method:
94 // 1) Generate the header for the symbol table. This is a normal
95 // archive member header, but it has a zero length name.
96 // 2) For each archive member file, stat the file and parse the bytecode
97 // Store cumulative offset (file size + header size).
98 // 3) Loop over all the symbols for the current member file,
99 // add offset entry to offset vector, and add symbol name to its vector.
100 // Note: The symbol name vector is a vector of chars to speed up calculating
101 // the total size of the symbol table.
102 // 4) Update offset vector once we know the total size of symbol table. This is
103 // because the symbol table appears before all archive member file contents.
104 // We add the size of magic string, and size of symbol table to each offset.
105 // 5) If the new updated offset it not even, we add 1 byte to offset because
106 // a newline will be inserted when writing member files. This adjustment is
107 // cummulative (ie. each time we have an odd offset we add 1 to total adjustment).
108 // 6) Lastly, write symbol table to file.
110 bool WriteSymbolTable(std::ofstream &ArchiveFile) {
112 //Create header for symbol table. This is essentially an empty header with the
113 //name set to a '/' to indicate its a symbol table.
117 //Name of symbol table is '/'
121 //Set the header trailer to a newline
122 memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
125 //Write header to archive file
126 ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
129 unsigned memoff = 0; //Keep Track of total size of files added to archive
130 vector<unsigned> offsets; //Vector of offsets into archive file
131 vector<char> names; //Vector of characters that are the symbol names.
133 //Loop over archive member files, parse bytecode, and generate symbol table.
134 for(unsigned i=0; i<Members.size(); ++i) {
136 //Open Member file for reading and copy to buffer
137 int FD = open(Members[i].c_str(),O_RDONLY);
139 //Check for errors opening the file.
141 std::cerr << "Error opening file!\n";
145 //Stat the file to get its size.
147 if (stat(Members[i].c_str(), &StatBuf) == -1 || StatBuf.st_size == 0) {
148 std::cerr << "Error stating file\n";
153 unsigned Length = StatBuf.st_size;
155 //Read in file into a buffer.
156 unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
159 //Check if mmap failed.
160 if (buf == (unsigned char*)MAP_FAILED) {
161 std::cerr << "Error mmapping file!\n";
165 //Parse the bytecode file and get all the symbols.
167 Module *M = ParseBytecodeBuffer(buf,Length,Members[i],&ErrorStr);
169 //Check for errors parsing bytecode.
171 //std::cerr << "Error Parsing Bytecode\n";
175 //Loop over function names and global vars and add to symbol maps
176 for(Module::iterator I = M->begin(), E=M->end(); I != E; ++I) {
179 string NM = ((Function*)I)->getName();
181 //Loop over the characters in the name and add to symbol name vector
182 for(unsigned i=0; i<NM.size(); ++i)
183 names.push_back(NM[i]);
185 //Each symbol is null terminated.
186 names.push_back('\0');
188 //Add offset to vector of offsets
189 offsets.push_back(memoff);
192 memoff += Length + sizeof(Hdr);
195 //Determine how large our symbol table is.
196 unsigned symbolTableSize = sizeof(Hdr) + 4 + 4*(offsets.size()) + names.size();
197 cout << "Symbol Table Size: " << symbolTableSize << "\n";
199 //Number of symbols should be in network byte order as well
201 unsigned temp = offsets.size();
202 num[0] = (temp >> 24) & 255;
203 num[1] = (temp >> 16) & 255;
204 num[2] = (temp >> 8) & 255;
207 //Write number of symbols to archive file
208 ArchiveFile.write(num,4);
210 //Adjustment to offset to start files on even byte boundaries
213 //Update offsets write symbol table to archive.
214 for(unsigned i=0; i<offsets.size(); ++i) {
216 offsets[i] = offsets[i] + symbolTableSize + SARMAG;
217 offsets[i] += adjust;
218 if((offsets[i] % 2 != 0)) {
220 offsets[i] += adjust;
223 cout << "Offset: " << offsets[i] << "\n";
224 output[0] = (offsets[i] >> 24) & 255;
225 output[1] = (offsets[i] >> 16) & 255;
226 output[2] = (offsets[i] >> 8) & 255;
227 output[3] = offsets[i] & 255;
228 ArchiveFile.write(output,4);
232 //Write out symbol name vector.
233 for(unsigned i=0; i<names.size(); ++i)
234 ArchiveFile << names[i];
239 // AddMemberToArchive - Writes member file to archive. Returns false on errors.
241 // Overview of method:
242 // 1) Open file, and stat it.
243 // 2) Fill out header using stat information. If name is longer then 15
244 // characters, use "dummy" name.
245 // 3) Write header and file contents to disk.
246 // 4) Keep track of total offset into file, and insert a newline if it is odd.
248 bool AddMemberToArchive(string Member, std::ofstream &ArchiveFile) {
250 ar_hdr Hdr; //Header for archive member file.
252 //stat the file to get info
254 if (stat(Member.c_str(), &StatBuf) == -1 || StatBuf.st_size == 0)
259 //set name to white spaces
260 memset(Hdr.name,' ', sizeof(Hdr.name));
262 //check the size of the name, if less than 15, we can copy it directly
263 //otherwise we give it a dummy name for now
264 if(Member.length() < 16)
265 memcpy(Hdr.name,Member.c_str(),Member.length());
267 memcpy(Hdr.name, "Dummy", 5);
269 //terminate name with forward slash
272 //file member size in decimal
273 unsigned Length = StatBuf.st_size;
274 sprintf(Hdr.size,"%d", Length);
275 cout << "Size: " << Length << "\n";
277 //file member user id in decimal
278 sprintf(Hdr.uid, "%d", StatBuf.st_uid);
280 //file member group id in decimal
281 sprintf(Hdr.gid, "%d", StatBuf.st_gid);
283 //file member date in decimal
284 sprintf(Hdr.date,"%d", (int)StatBuf.st_mtime);
286 //file member mode in OCTAL
287 sprintf(Hdr.mode,"%d", StatBuf.st_mode);
289 //add our header trailer
290 memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG));
292 //write header to archive file
293 ArchiveFile.write((char*)&Hdr, sizeof(Hdr));
295 //open Member file for reading and copy to buffer
296 int FD = open(Member.c_str(),O_RDONLY);
298 std::cerr << "Error opening file!\n";
302 unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ,
305 //check if mmap failed
306 if (buf == (unsigned char*)MAP_FAILED) {
307 std::cerr << "Error mmapping file!\n";
311 //write to archive file
312 ArchiveFile.write((char*)buf,Length);
314 // Unmmap the memberfile
315 munmap((char*)buf, Length);
321 // CreateArchive - Generates archive with or without symbol table.
323 void CreateArchive() {
325 //Create archive file for output.
326 std::ofstream ArchiveFile(Archive.c_str());
328 //Check for errors opening or creating archive file.
329 if(!ArchiveFile.is_open() || ArchiveFile.bad() ) {
330 std::cerr << "Error opening Archive File\n";
334 //Write magic string to archive.
335 ArchiveFile << ARMAG;
337 //If the '-s' option was specified, generate symbol table.
339 cout << "Symbol Table Start: " << ArchiveFile.tellp() << "\n";
340 if(!WriteSymbolTable(ArchiveFile)) {
341 std::cerr << "Error creating symbol table. Exiting program.";
344 cout << "Symbol Table End: " << ArchiveFile.tellp() << "\n";
346 //Loop over all member files, and add to the archive.
347 for(unsigned i=0; i<Members.size(); ++i) {
348 if(ArchiveFile.tellp() % 2 != 0)
349 ArchiveFile << ARFMAG;
351 cout << "Member File Start: " << ArchiveFile.tellp() << "\n";
353 if(AddMemberToArchive(Members[i],ArchiveFile) != true) {
354 std::cerr << "Error adding file to archive. Exiting program.";
357 cout << "Member File End: " << ArchiveFile.tellp() << "\n";
360 //Close archive file.
365 int main(int argc, char **argv) {
367 //Parse Command line options
368 cl::ParseCommandLineOptions(argc, argv, " llvm-ar\n");