// dump2def.cpp - Written and placed in public domain by Jeffrey Walton // Create a module definitions file from a dumpbin file. // dump2def can be used to create a list of exports from // a static library. Then, the exports can used to build // a dynamic link library with the same exports. // // If you wish to compile this source file using cl.exe, then: // cl.exe /DNDEBUG /Oi /Oy /O2 /Zi /TP /GR /EHsc /MT dump2def.cpp // // The intended workflow in Crypto++ is: // // 1. Open a Developer Prompt // 2. CD to cryptopp/ directory // 3. nmake /f cryptest.nmake cryptopp.dll // // The cryptopp.dll recipe first builds cryptlib.lib. Then it calls // dumpbin.exe to export all symbols from cryptlib.lib and writes them // to cryptopp.dump. The recipe then calls dump2def.exe to create a // module definition file. Finally, the recipe builds cryptopp.dll // using the module definition file cryptopp.def. The linker creates // the import lib cryptopp.lib and export cryptopp.exp automatically. // // This is only "half the problem solved" for those who wish to use // a DLL. The program must import the import lib cryptopp.lib. Then // the program must ensure the library headers export the symbol or // class with CRYPTOPP_DLL. CRYPTOPP_DLL is only present on some classes // because the FIPS module only allowed approved algorithms like AES and // SHA. Other classes like Base64Encoder and HexEncoder lack CRYPTOPP_DLL. // // CRYPTOPP_DLL simply adds declspec(dllimport) when CRYPTOPP_IMPORTS is // defined. The limitation of requiring declspec(dllimport) is imposed by // Microsoft. Microsoft does not allow a program to "import everything". // // If you would like to read more about the FIPS module and the pain it // causes then see https://www.cryptopp.com/wiki/FIPS_DLL. In fact we // recommend you delete the CryptDll and DllTest projects from the // Visual Studio solution file. #include #include #include #include #include #include // Friendly name #define LIBRARY_DESC "Crypto++ Library" typedef std::set SymbolMap; const int ErrorSuccess = 0; const int ErrorDumpExtension = 1; const int ErrorTooFewOpts = 2; const int ErrorTooManyOpts = 3; const int ErrorOpenInputFailed = 4; const int ErrorOpenOutputFailed = 5; const int ErrorReadException = 6; const int ErrorWriteException = 7; void PrintHelpAndExit(int code) { std::cout << "dump2def - create a module definitions file from a dumpbin file" << std::endl; std::cout << " Written and placed in public domain by Jeffrey Walton" << std::endl; std::cout << std::endl; switch (code) { case ErrorDumpExtension: std::cout << "Error: input file is missing \".dump\" extension.\n" << std::endl; break; case ErrorTooFewOpts: std::cout << "Error: Too few options were supplied.\n" << std::endl; break; case ErrorTooManyOpts: std::cout << "Error: Too many options were supplied.\n" << std::endl; break; case ErrorOpenInputFailed: std::cout << "Error: Failed to open input file.\n" << std::endl; break; case ErrorOpenOutputFailed: std::cout << "Error: Failed to open output file.\n" << std::endl; break; default: ;; } std::cout << "Usage: " << std::endl; std::cout << " dump2def " << std::endl; std::cout << " - Create a def file from and write it to a file with" << std::endl; std::cout << " the same name as but using the .def extension" << std::endl; std::cout << " dump2def " << std::endl; std::cout << " - Create a def file from and write it to " << std::endl; std::exit((code == ErrorSuccess ? 0 : 1)); } int main(int argc, char* argv[]) { // ******************** Handle Options ******************** // // Convenience item std::vector opts; for (size_t i=0; i 1 ? opts[1].substr(0,2) : ""); if (opt == "/h" || opt == "-h" || opt == "/?" || opt == "-?") PrintHelpAndExit(ErrorSuccess); // Add as needed if (opts.size() == 2) { std::string outfile = opts[1]; std::string::size_type pos = outfile.length() < 5 ? std::string::npos : outfile.length() - 5; if (pos == std::string::npos || outfile.substr(pos) != ".dump") PrintHelpAndExit(ErrorDumpExtension); outfile.replace(pos, 5, ".def"); opts.push_back(outfile); } // Check or exit if (opts.size() < 2) PrintHelpAndExit(ErrorTooFewOpts); if (opts.size() > 3) PrintHelpAndExit(ErrorTooManyOpts); // ******************** Read MAP file ******************** // SymbolMap symbols; try { std::ifstream infile(opts[1].c_str()); if (infile.is_open() == false) PrintHelpAndExit(ErrorOpenInputFailed); std::string::size_type pos; std::string line; // Find start of the symbol table while (std::getline(infile, line)) { pos = line.find("public symbols"); if (pos == std::string::npos) { continue; } // Eat the whitespace after the table heading infile >> std::ws; break; } while (std::getline(infile, line)) { // End of table if (line.empty()) { break; } std::istringstream iss(line); std::string address, symbol; iss >> address >> symbol; symbols.insert(symbol); } } catch (const std::exception& ex) { std::cerr << "Unexpected exception:" << std::endl; std::cerr << ex.what() << std::endl; std::cerr << std::endl; PrintHelpAndExit(ErrorReadException); } // ******************** Write DEF file ******************** // try { std::ofstream outfile(opts[2].c_str()); if (outfile.is_open() == false) PrintHelpAndExit(ErrorOpenOutputFailed); // Library name, cryptopp.dll std::string name = opts[2]; std::string::size_type pos = name.find_last_of("."); if (pos != std::string::npos) name.erase(pos); outfile << "LIBRARY " << name << std::endl; outfile << "DESCRIPTION \"" << LIBRARY_DESC << "\"" << std::endl; outfile << "EXPORTS" << std::endl; outfile << std::endl; outfile << "\t;; " << symbols.size() << " symbols" << std::endl; // Symbols from our object files SymbolMap::const_iterator it = symbols.begin(); for ( ; it != symbols.end(); ++it) outfile << "\t" << *it << std::endl; } catch (const std::exception& ex) { std::cerr << "Unexpected exception:" << std::endl; std::cerr << ex.what() << std::endl; std::cerr << std::endl; PrintHelpAndExit(ErrorWriteException); } return 0; }