BeefLink.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "BeefySysLib/Common.h"
  2. #include <stdio.h>
  3. #include <iostream>
  4. #include <vector>
  5. #pragma warning(disable:4996)
  6. USING_NS_BF;
  7. #define BF_IMPORT extern "C" __declspec(dllimport)
  8. class BlContext;
  9. bool gFailed = false;
  10. BF_IMPORT BlContext* BF_CALLTYPE BlContext_Create();
  11. BF_IMPORT void BF_CALLTYPE BlContext_Delete(BlContext* blContext);
  12. BF_IMPORT void BF_CALLTYPE BlContext_Init(BlContext* blContext, bool is64Bit, bool isDebug);
  13. BF_IMPORT void BF_CALLTYPE BlContext_AddSearchPath(BlContext* blContext, const char* directory);
  14. BF_IMPORT void BF_CALLTYPE BlContext_AddFile(BlContext* blContext, const char* fileName);
  15. BF_IMPORT bool BF_CALLTYPE BlContext_Link(BlContext* blContext);
  16. BF_IMPORT bool BF_CALLTYPE BlContext_SetOutName(BlContext* blContext, const char* outName);
  17. BF_IMPORT bool BF_CALLTYPE BlContext_SetEntryPoint(BlContext* blContext, const char* outName);
  18. BF_IMPORT bool BF_CALLTYPE BlContext_SetImpLib(BlContext* blContext, const char* impLibName);
  19. BF_IMPORT void BF_CALLTYPE BlContext_SetDebug(BlContext* blContext, int debugMode);
  20. BF_IMPORT void BF_CALLTYPE BlContext_SetPDBName(BlContext* blContext, const char* pdbPath);
  21. BF_IMPORT void BF_CALLTYPE BlContext_SetIsDLL(BlContext* blContext);
  22. BF_IMPORT void BF_CALLTYPE BlContext_SetVerbose(BlContext* blContext, bool enabled);
  23. BF_IMPORT void BF_CALLTYPE BlContext_SetNoDefaultLib(BlContext* blContext, bool enabled);
  24. BF_IMPORT void BF_CALLTYPE BlContext_AddNoDefaultLib(BlContext* blContext, const char* name);
  25. BF_IMPORT void BF_CALLTYPE BlContext_AddDefaultLib(BlContext* blContext, const char* name);
  26. BF_IMPORT void BF_CALLTYPE BlContext_SetImageBase(BlContext* blContext, int64 imageBase);
  27. BF_IMPORT void BF_CALLTYPE BlContext_SetFixedBase(BlContext* blContext, bool enabled);
  28. BF_IMPORT void BF_CALLTYPE BlContext_SetDynamicBase(BlContext* blContext, bool enabled);
  29. BF_IMPORT void BF_CALLTYPE BlContext_SetHighEntropyVA(BlContext* blContext, bool enabled);
  30. BF_IMPORT void BF_CALLTYPE BlContext_ManifestUAC(BlContext* blContext, const char* manifestUAC);
  31. BF_IMPORT void BF_CALLTYPE BlContext_SetSubsystem(BlContext* blContext, int subsystem);
  32. BF_IMPORT void BF_CALLTYPE BlContext_SetStack(BlContext* blContext, int reserve, int commit);
  33. BF_IMPORT void BF_CALLTYPE BlContext_SetHeap(BlContext* blContext, int reserve, int commit);
  34. void Fail(const std::string& name)
  35. {
  36. gFailed = true;
  37. std::cerr << "ERROR: " << name.c_str() << std::endl;
  38. }
  39. static bool CheckBoolean(const std::string& arg)
  40. {
  41. if (stricmp(arg.c_str(), "YES") == 0)
  42. return true;
  43. if (stricmp(arg.c_str(), "NO") == 0)
  44. return false;
  45. Fail(StrFormat("Invalid boolean argument: %s", arg.c_str()));
  46. return false;
  47. }
  48. BlContext* blContext;
  49. std::vector<std::string> fileNames;
  50. std::string defFileName;
  51. std::string outPath;
  52. bool HandleParam(const std::string& arg, bool isFirstArg = false)
  53. {
  54. if ((arg[0] == '-') || (arg[0] == '/'))
  55. {
  56. int colonPos = (int)arg.find(':');
  57. if (colonPos != -1)
  58. {
  59. std::string argName = ToUpper(arg.substr(1, colonPos - 1));
  60. std::string argParam = arg.substr(colonPos + 1);
  61. if (argName == "OUT")
  62. {
  63. outPath = argParam;
  64. BlContext_SetOutName(blContext, outPath.c_str());
  65. }
  66. else if (argName == "ERRORREPORT")
  67. {
  68. }
  69. else if (argName == "MANIFEST")
  70. {
  71. }
  72. else if (argName == "MANIFESTUAC")
  73. {
  74. BlContext_ManifestUAC(blContext, argParam.c_str());
  75. }
  76. else if (argName == "UIACCESS")
  77. {
  78. }
  79. else if (argName == "DEBUG")
  80. {
  81. if (ToUpper(argParam) == "NONE")
  82. BlContext_SetDebug(blContext, 0);
  83. else
  84. BlContext_SetDebug(blContext, 1);
  85. }
  86. else if (argName == "DEBUGTYPE")
  87. {
  88. }
  89. else if (argName == "PDB")
  90. {
  91. BlContext_SetPDBName(blContext, argParam.c_str());
  92. }
  93. else if (argName == "ENTRY")
  94. {
  95. BlContext_SetEntryPoint(blContext, argParam.c_str());
  96. }
  97. else if (argName == "SUBSYSTEM")
  98. {
  99. std::string subsysName = ToUpper(argParam);
  100. if (subsysName == "WINDOWS")
  101. BlContext_SetSubsystem(blContext, IMAGE_SUBSYSTEM_WINDOWS_GUI);
  102. else if (subsysName == "CONSOLE")
  103. BlContext_SetSubsystem(blContext, IMAGE_SUBSYSTEM_WINDOWS_CUI);
  104. else
  105. Fail("Specified subsystem not supported");
  106. }
  107. else if (argName == "TLBID")
  108. {
  109. }
  110. else if (argName == "IMPLIB")
  111. {
  112. BlContext_SetImpLib(blContext, argParam.c_str());
  113. }
  114. else if (argName == "MACHINE")
  115. {
  116. if (argParam != "X64")
  117. {
  118. Fail("Only X64 is currently supported");
  119. }
  120. }
  121. else if (argName == "HEAP")
  122. {
  123. int commaPos = (int)argParam.find(',');
  124. if (commaPos > 0)
  125. BlContext_SetHeap(blContext, strtol(argParam.c_str(), NULL, 0), strtol(argParam.c_str() + commaPos + 1, NULL, 0));
  126. else
  127. BlContext_SetHeap(blContext, strtol(argParam.c_str(), NULL, 0), 0);
  128. }
  129. else if (argName == "STACK")
  130. {
  131. int commaPos = (int)argParam.find(',');
  132. if (commaPos > 0)
  133. BlContext_SetStack(blContext, strtol(argParam.c_str(), NULL, 0), strtol(argParam.c_str() + commaPos + 1, NULL, 0));
  134. else
  135. BlContext_SetStack(blContext, strtol(argParam.c_str(), NULL, 0), 0);
  136. }
  137. else if (argName == "LIBPATH")
  138. {
  139. BlContext_AddSearchPath(blContext, argParam.c_str());
  140. }
  141. else if (argName == "VERBOSE")
  142. {
  143. BlContext_SetVerbose(blContext, CheckBoolean(argParam));
  144. }
  145. else if (argName == "NODEFAULTLIB")
  146. {
  147. BlContext_AddNoDefaultLib(blContext, argParam.c_str());
  148. }
  149. else if (argName == "BASE")
  150. {
  151. int64 imageBase = 0;
  152. imageBase = strtoll(argParam.c_str(), NULL, 0);
  153. if (imageBase != 0)
  154. BlContext_SetImageBase(blContext, imageBase);
  155. }
  156. else if (argName == "FIXED")
  157. {
  158. BlContext_SetFixedBase(blContext, CheckBoolean(argParam));
  159. }
  160. else if (argName == "DYNAMICBASE")
  161. {
  162. BlContext_SetDynamicBase(blContext, CheckBoolean(argParam));
  163. }
  164. else if (argName == "HIGHENTROPYVA")
  165. {
  166. BlContext_SetHighEntropyVA(blContext, CheckBoolean(argParam));
  167. }
  168. else if (argName == "DEF")
  169. {
  170. defFileName = argParam;
  171. }
  172. else if (argName == "INCREMENTAL")
  173. {
  174. }
  175. else if (argName == "DEFAULTLIB")
  176. {
  177. BlContext_AddDefaultLib(blContext, argParam.c_str());
  178. }
  179. else
  180. {
  181. Fail(StrFormat("Invalid argument: %s", arg.c_str()));
  182. return 1;
  183. }
  184. }
  185. else
  186. {
  187. std::string argName = ToUpper(arg.substr(1));
  188. if (argName == "NODEFAULTLIB")
  189. {
  190. BlContext_SetNoDefaultLib(blContext, true);
  191. }
  192. if (argName == "VERBOSE")
  193. {
  194. BlContext_SetVerbose(blContext, true);
  195. }
  196. else if (argName == "NOLOGO")
  197. {
  198. }
  199. else if (argName == "MANIFEST")
  200. {
  201. }
  202. else if (argName == "DEBUG")
  203. {
  204. BlContext_SetDebug(blContext, 1);
  205. }
  206. else if (argName == "NXCOMPAT")
  207. {
  208. }
  209. else if (argName == "DLL")
  210. {
  211. BlContext_SetIsDLL(blContext);
  212. }
  213. else if (argName == "FIXED")
  214. {
  215. BlContext_SetFixedBase(blContext, true);
  216. }
  217. else if (argName == "DYNAMICBASE")
  218. {
  219. BlContext_SetDynamicBase(blContext, true);
  220. }
  221. else if (argName == "INCREMENTAL")
  222. {
  223. }
  224. else
  225. {
  226. Fail(StrFormat("Invalid argument: %s", arg.c_str()));
  227. return false;
  228. }
  229. }
  230. }
  231. else if (arg[0] == '@')
  232. {
  233. char* cmdData = LoadTextData(arg.substr(1), NULL);
  234. if (cmdData == NULL)
  235. {
  236. Fail(StrFormat("Failed to load command file: \"%s\"", arg.substr(1).c_str()));
  237. return false;
  238. }
  239. std::string curArg;
  240. bool inQuote = false;
  241. bool prevSlash = false;
  242. for (char* cPtr = cmdData; true; cPtr++)
  243. {
  244. char c = *cPtr;
  245. if (c == 0)
  246. {
  247. if (!curArg.empty())
  248. HandleParam(curArg);
  249. break;
  250. }
  251. if (c == '"')
  252. {
  253. inQuote = !inQuote;
  254. }
  255. else if ((isspace(c)) && (!inQuote))
  256. {
  257. if (!curArg.empty())
  258. {
  259. HandleParam(curArg);
  260. curArg.clear();
  261. }
  262. }
  263. else
  264. curArg += c;
  265. }
  266. delete cmdData;
  267. }
  268. else if (!isFirstArg)
  269. {
  270. fileNames.push_back(arg.c_str());
  271. }
  272. return true;
  273. }
  274. int main(int argc, char* argv[])
  275. {
  276. int startTick = GetTickCount();
  277. blContext = BlContext_Create();
  278. // C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\x86_amd64\link.exe /ERRORREPORT:PROMPT /OUT:"C:\proj\TestCPP\x64\Debug\TestCPP.exe" /INCREMENTAL /NOLOGO /MANIFEST /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG /PDB:"C:\proj\TestCPP\x64\Debug\TestCPP.pdb" /SUBSYSTEM:CONSOLE /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"C:\proj\TestCPP\x64\Debug\TestCPP.lib" /MACHINE:X64 kernel32.lib user32.lib advapi32.lib shell32.lib x64\Debug\main.obj
  279. bool success = true;
  280. for (int argIdx = 0; argIdx < argc; argIdx++)
  281. {
  282. if (!HandleParam(argv[argIdx], argIdx == 0))
  283. break;
  284. }
  285. if (gFailed)
  286. success = false;
  287. if (success)
  288. {
  289. BlContext_Init(blContext, true, true);
  290. for (auto fileName : fileNames)
  291. BlContext_AddFile(blContext, fileName.c_str());
  292. // Process DEF first. Relies on LIFO ordering
  293. if (!defFileName.empty())
  294. BlContext_AddFile(blContext, defFileName.c_str());
  295. success &= BlContext_Link(blContext);
  296. }
  297. BlContext_Delete(blContext);
  298. printf("Total Time: %dms\n", GetTickCount() - startTick);
  299. if (success)
  300. return 0;
  301. return 2;
  302. }