tcctools.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /* -------------------------------------------------------------- */
  2. /*
  3. * TCC - Tiny C Compiler
  4. *
  5. * tcctools.c - extra tools and and -m32/64 support
  6. *
  7. */
  8. /* -------------------------------------------------------------- */
  9. /*
  10. * This program is for making libtcc1.a without ar
  11. * tiny_libmaker - tiny elf lib maker
  12. * usage: tiny_libmaker [lib] files...
  13. * Copyright (c) 2007 Timppa
  14. *
  15. * This library is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU Lesser General Public
  17. * License as published by the Free Software Foundation; either
  18. * version 2 of the License, or (at your option) any later version.
  19. *
  20. * This library is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  23. * Lesser General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU Lesser General Public
  26. * License along with this library; if not, write to the Free Software
  27. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
  28. */
  29. #include "tcc.h"
  30. //#define ARMAG "!<arch>\n"
  31. #define ARFMAG "`\n"
  32. typedef struct {
  33. char ar_name[16];
  34. char ar_date[12];
  35. char ar_uid[6];
  36. char ar_gid[6];
  37. char ar_mode[8];
  38. char ar_size[10];
  39. char ar_fmag[2];
  40. } ArHdr;
  41. static unsigned long le2belong(unsigned long ul) {
  42. return ((ul & 0xFF0000)>>8)+((ul & 0xFF000000)>>24) +
  43. ((ul & 0xFF)<<24)+((ul & 0xFF00)<<8);
  44. }
  45. /* Returns 1 if s contains any of the chars of list, else 0 */
  46. static int contains_any(const char *s, const char *list) {
  47. const char *l;
  48. for (; *s; s++) {
  49. for (l = list; *l; l++) {
  50. if (*s == *l)
  51. return 1;
  52. }
  53. }
  54. return 0;
  55. }
  56. static int ar_usage(int ret) {
  57. fprintf(stderr, "usage: tcc -ar [rcsv] lib file...\n");
  58. fprintf(stderr, "create library ([abdioptxN] not supported).\n");
  59. return ret;
  60. }
  61. ST_FUNC int tcc_tool_ar(TCCState *s1, int argc, char **argv)
  62. {
  63. static ArHdr arhdr = {
  64. "/ ",
  65. " ",
  66. "0 ",
  67. "0 ",
  68. "0 ",
  69. " ",
  70. ARFMAG
  71. };
  72. static ArHdr arhdro = {
  73. " ",
  74. " ",
  75. "0 ",
  76. "0 ",
  77. "0 ",
  78. " ",
  79. ARFMAG
  80. };
  81. FILE *fi, *fh = NULL, *fo = NULL;
  82. ElfW(Ehdr) *ehdr;
  83. ElfW(Shdr) *shdr;
  84. ElfW(Sym) *sym;
  85. int i, fsize, i_lib, i_obj;
  86. char *buf, *shstr, *symtab = NULL, *strtab = NULL;
  87. int symtabsize = 0;//, strtabsize = 0;
  88. char *anames = NULL;
  89. int *afpos = NULL;
  90. int istrlen, strpos = 0, fpos = 0, funccnt = 0, funcmax, hofs;
  91. char tfile[260], stmp[20];
  92. char *file, *name;
  93. int ret = 2;
  94. const char *ops_conflict = "habdioptxN"; // unsupported but destructive if ignored.
  95. int verbose = 0;
  96. i_lib = 0; i_obj = 0; // will hold the index of the lib and first obj
  97. for (i = 1; i < argc; i++) {
  98. const char *a = argv[i];
  99. if (*a == '-' && strstr(a, "."))
  100. ret = 1; // -x.y is always invalid (same as gnu ar)
  101. if ((*a == '-') || (i == 1 && !strstr(a, "."))) { // options argument
  102. if (contains_any(a, ops_conflict))
  103. ret = 1;
  104. if (strstr(a, "v"))
  105. verbose = 1;
  106. } else { // lib or obj files: don't abort - keep validating all args.
  107. if (!i_lib) // first file is the lib
  108. i_lib = i;
  109. else if (!i_obj) // second file is the first obj
  110. i_obj = i;
  111. }
  112. }
  113. if (!i_obj) // i_obj implies also i_lib. we require both.
  114. ret = 1;
  115. if (ret == 1)
  116. return ar_usage(ret);
  117. if ((fh = fopen(argv[i_lib], "wb")) == NULL)
  118. {
  119. fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_lib]);
  120. goto the_end;
  121. }
  122. sprintf(tfile, "%s.tmp", argv[i_lib]);
  123. if ((fo = fopen(tfile, "wb+")) == NULL)
  124. {
  125. fprintf(stderr, "tcc: ar: can't create temporary file %s\n", tfile);
  126. goto the_end;
  127. }
  128. funcmax = 250;
  129. afpos = tcc_realloc(NULL, funcmax * sizeof *afpos); // 250 func
  130. memcpy(&arhdro.ar_mode, "100666", 6);
  131. // i_obj = first input object file
  132. while (i_obj < argc)
  133. {
  134. if (*argv[i_obj] == '-') { // by now, all options start with '-'
  135. i_obj++;
  136. continue;
  137. }
  138. if ((fi = fopen(argv[i_obj], "rb")) == NULL) {
  139. fprintf(stderr, "tcc: ar: can't open file %s \n", argv[i_obj]);
  140. goto the_end;
  141. }
  142. if (verbose)
  143. printf("a - %s\n", argv[i_obj]);
  144. fseek(fi, 0, SEEK_END);
  145. fsize = ftell(fi);
  146. fseek(fi, 0, SEEK_SET);
  147. buf = tcc_malloc(fsize + 1);
  148. fread(buf, fsize, 1, fi);
  149. fclose(fi);
  150. // elf header
  151. ehdr = (ElfW(Ehdr) *)buf;
  152. if (ehdr->e_ident[4] != ELFCLASSW)
  153. {
  154. fprintf(stderr, "tcc: ar: Unsupported Elf Class: %s\n", argv[i_obj]);
  155. goto the_end;
  156. }
  157. shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + ehdr->e_shstrndx * ehdr->e_shentsize);
  158. shstr = (char *)(buf + shdr->sh_offset);
  159. for (i = 0; i < ehdr->e_shnum; i++)
  160. {
  161. shdr = (ElfW(Shdr) *) (buf + ehdr->e_shoff + i * ehdr->e_shentsize);
  162. if (!shdr->sh_offset)
  163. continue;
  164. if (shdr->sh_type == SHT_SYMTAB)
  165. {
  166. symtab = (char *)(buf + shdr->sh_offset);
  167. symtabsize = shdr->sh_size;
  168. }
  169. if (shdr->sh_type == SHT_STRTAB)
  170. {
  171. if (!strcmp(shstr + shdr->sh_name, ".strtab"))
  172. {
  173. strtab = (char *)(buf + shdr->sh_offset);
  174. //strtabsize = shdr->sh_size;
  175. }
  176. }
  177. }
  178. if (symtab && symtabsize)
  179. {
  180. int nsym = symtabsize / sizeof(ElfW(Sym));
  181. //printf("symtab: info size shndx name\n");
  182. for (i = 1; i < nsym; i++)
  183. {
  184. sym = (ElfW(Sym) *) (symtab + i * sizeof(ElfW(Sym)));
  185. if (sym->st_shndx &&
  186. (sym->st_info == 0x10
  187. || sym->st_info == 0x11
  188. || sym->st_info == 0x12
  189. )) {
  190. //printf("symtab: %2Xh %4Xh %2Xh %s\n", sym->st_info, sym->st_size, sym->st_shndx, strtab + sym->st_name);
  191. istrlen = strlen(strtab + sym->st_name)+1;
  192. anames = tcc_realloc(anames, strpos+istrlen);
  193. strcpy(anames + strpos, strtab + sym->st_name);
  194. strpos += istrlen;
  195. if (++funccnt >= funcmax) {
  196. funcmax += 250;
  197. afpos = tcc_realloc(afpos, funcmax * sizeof *afpos); // 250 func more
  198. }
  199. afpos[funccnt] = fpos;
  200. }
  201. }
  202. }
  203. file = argv[i_obj];
  204. for (name = strchr(file, 0);
  205. name > file && name[-1] != '/' && name[-1] != '\\';
  206. --name);
  207. istrlen = strlen(name);
  208. if (istrlen >= sizeof(arhdro.ar_name))
  209. istrlen = sizeof(arhdro.ar_name) - 1;
  210. memset(arhdro.ar_name, ' ', sizeof(arhdro.ar_name));
  211. memcpy(arhdro.ar_name, name, istrlen);
  212. arhdro.ar_name[istrlen] = '/';
  213. sprintf(stmp, "%-10d", fsize);
  214. memcpy(&arhdro.ar_size, stmp, 10);
  215. fwrite(&arhdro, sizeof(arhdro), 1, fo);
  216. fwrite(buf, fsize, 1, fo);
  217. tcc_free(buf);
  218. i_obj++;
  219. fpos += (fsize + sizeof(arhdro));
  220. }
  221. hofs = 8 + sizeof(arhdr) + strpos + (funccnt+1) * sizeof(int);
  222. fpos = 0;
  223. if ((hofs & 1)) // align
  224. hofs++, fpos = 1;
  225. // write header
  226. fwrite("!<arch>\n", 8, 1, fh);
  227. sprintf(stmp, "%-10d", (int)(strpos + (funccnt+1) * sizeof(int)));
  228. memcpy(&arhdr.ar_size, stmp, 10);
  229. fwrite(&arhdr, sizeof(arhdr), 1, fh);
  230. afpos[0] = le2belong(funccnt);
  231. for (i=1; i<=funccnt; i++)
  232. afpos[i] = le2belong(afpos[i] + hofs);
  233. fwrite(afpos, (funccnt+1) * sizeof(int), 1, fh);
  234. fwrite(anames, strpos, 1, fh);
  235. if (fpos)
  236. fwrite("", 1, 1, fh);
  237. // write objects
  238. fseek(fo, 0, SEEK_END);
  239. fsize = ftell(fo);
  240. fseek(fo, 0, SEEK_SET);
  241. buf = tcc_malloc(fsize + 1);
  242. fread(buf, fsize, 1, fo);
  243. fwrite(buf, fsize, 1, fh);
  244. tcc_free(buf);
  245. ret = 0;
  246. the_end:
  247. if (anames)
  248. tcc_free(anames);
  249. if (afpos)
  250. tcc_free(afpos);
  251. if (fh)
  252. fclose(fh);
  253. if (fo)
  254. fclose(fo), remove(tfile);
  255. return ret;
  256. }
  257. /* -------------------------------------------------------------- */
  258. /*
  259. * tiny_impdef creates an export definition file (.def) from a dll
  260. * on MS-Windows. Usage: tiny_impdef library.dll [-o outputfile]"
  261. *
  262. * Copyright (c) 2005,2007 grischka
  263. *
  264. * This program is free software; you can redistribute it and/or modify
  265. * it under the terms of the GNU General Public License as published by
  266. * the Free Software Foundation; either version 2 of the License, or
  267. * (at your option) any later version.
  268. *
  269. * This program is distributed in the hope that it will be useful,
  270. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  271. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  272. * GNU General Public License for more details.
  273. *
  274. * You should have received a copy of the GNU General Public License
  275. * along with this program; if not, write to the Free Software
  276. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  277. */
  278. #ifdef TCC_TARGET_PE
  279. ST_FUNC int tcc_tool_impdef(TCCState *s1, int argc, char **argv)
  280. {
  281. int ret, v, i;
  282. char infile[260];
  283. char outfile[260];
  284. const char *file;
  285. char *p, *q;
  286. FILE *fp, *op;
  287. #ifdef _WIN32
  288. char path[260];
  289. #endif
  290. infile[0] = outfile[0] = 0;
  291. fp = op = NULL;
  292. ret = 1;
  293. p = NULL;
  294. v = 0;
  295. for (i = 1; i < argc; ++i) {
  296. const char *a = argv[i];
  297. if ('-' == a[0]) {
  298. if (0 == strcmp(a, "-v")) {
  299. v = 1;
  300. } else if (0 == strcmp(a, "-o")) {
  301. if (++i == argc)
  302. goto usage;
  303. strcpy(outfile, argv[i]);
  304. } else
  305. goto usage;
  306. } else if (0 == infile[0])
  307. strcpy(infile, a);
  308. else
  309. goto usage;
  310. }
  311. if (0 == infile[0]) {
  312. usage:
  313. fprintf(stderr,
  314. "usage: tcc -impdef library.dll [-v] [-o outputfile]\n"
  315. "create export definition file (.def) from dll\n"
  316. );
  317. goto the_end;
  318. }
  319. if (0 == outfile[0]) {
  320. strcpy(outfile, tcc_basename(infile));
  321. q = strrchr(outfile, '.');
  322. if (NULL == q)
  323. q = strchr(outfile, 0);
  324. strcpy(q, ".def");
  325. }
  326. file = infile;
  327. #ifdef _WIN32
  328. if (SearchPath(NULL, file, ".dll", sizeof path, path, NULL))
  329. file = path;
  330. #endif
  331. ret = tcc_get_dllexports(file, &p);
  332. if (ret || !p) {
  333. fprintf(stderr, "tcc: impdef: %s '%s'\n",
  334. ret == -1 ? "can't find file" :
  335. ret == 1 ? "can't read symbols" :
  336. ret == 0 ? "no symbols found in" :
  337. "unknown file type", file);
  338. ret = 1;
  339. goto the_end;
  340. }
  341. if (v)
  342. printf("-> %s\n", file);
  343. op = fopen(outfile, "w");
  344. if (NULL == op) {
  345. fprintf(stderr, "tcc: impdef: could not create output file: %s\n", outfile);
  346. goto the_end;
  347. }
  348. fprintf(op, "LIBRARY %s\n\nEXPORTS\n", tcc_basename(file));
  349. for (q = p, i = 0; *q; ++i) {
  350. fprintf(op, "%s\n", q);
  351. q += strlen(q) + 1;
  352. }
  353. if (v)
  354. printf("<- %s (%d symbol%s)\n", outfile, i, &"s"[i<2]);
  355. ret = 0;
  356. the_end:
  357. /* cannot free memory received from tcc_get_dllexports
  358. if it came from a dll */
  359. /* if (p)
  360. tcc_free(p); */
  361. if (fp)
  362. fclose(fp);
  363. if (op)
  364. fclose(op);
  365. return ret;
  366. }
  367. #endif /* TCC_TARGET_PE */
  368. /* -------------------------------------------------------------- */
  369. /*
  370. * TCC - Tiny C Compiler
  371. *
  372. * Copyright (c) 2001-2004 Fabrice Bellard
  373. *
  374. * This library is free software; you can redistribute it and/or
  375. * modify it under the terms of the GNU Lesser General Public
  376. * License as published by the Free Software Foundation; either
  377. * version 2 of the License, or (at your option) any later version.
  378. *
  379. * This library is distributed in the hope that it will be useful,
  380. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  381. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  382. * Lesser General Public License for more details.
  383. *
  384. * You should have received a copy of the GNU Lesser General Public
  385. * License along with this library; if not, write to the Free Software
  386. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  387. */
  388. /* re-execute the i386/x86_64 cross-compilers with tcc -m32/-m64: */
  389. #if !defined TCC_TARGET_I386 && !defined TCC_TARGET_X86_64
  390. ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int option)
  391. {
  392. tcc_error("-m%d not implemented.", option);
  393. }
  394. #else
  395. #ifdef _WIN32
  396. #include <process.h>
  397. static char *str_replace(const char *str, const char *p, const char *r)
  398. {
  399. const char *s, *s0;
  400. char *d, *d0;
  401. int sl, pl, rl;
  402. sl = strlen(str);
  403. pl = strlen(p);
  404. rl = strlen(r);
  405. for (d0 = NULL;; d0 = tcc_malloc(sl + 1)) {
  406. for (d = d0, s = str; s0 = s, s = strstr(s, p), s; s += pl) {
  407. if (d) {
  408. memcpy(d, s0, sl = s - s0), d += sl;
  409. memcpy(d, r, rl), d += rl;
  410. } else
  411. sl += rl - pl;
  412. }
  413. if (d) {
  414. strcpy(d, s0);
  415. return d0;
  416. }
  417. }
  418. }
  419. static int execvp_win32(const char *prog, char **argv)
  420. {
  421. int ret; char **p;
  422. /* replace all " by \" */
  423. for (p = argv; *p; ++p)
  424. if (strchr(*p, '"'))
  425. *p = str_replace(*p, "\"", "\\\"");
  426. ret = _spawnvp(P_NOWAIT, prog, (const char *const*)argv);
  427. if (-1 == ret)
  428. return ret;
  429. _cwait(&ret, ret, WAIT_CHILD);
  430. exit(ret);
  431. }
  432. #define execvp execvp_win32
  433. #endif /* _WIN32 */
  434. ST_FUNC void tcc_tool_cross(TCCState *s, char **argv, int target)
  435. {
  436. char program[4096];
  437. char *a0 = argv[0];
  438. int prefix = tcc_basename(a0) - a0;
  439. snprintf(program, sizeof program,
  440. "%.*s%s"
  441. #ifdef TCC_TARGET_PE
  442. "-win32"
  443. #endif
  444. "-tcc"
  445. #ifdef _WIN32
  446. ".exe"
  447. #endif
  448. , prefix, a0, target == 64 ? "x86_64" : "i386");
  449. if (strcmp(a0, program))
  450. execvp(argv[0] = program, argv);
  451. tcc_error("could not run '%s'", program);
  452. }
  453. #endif /* TCC_TARGET_I386 && TCC_TARGET_X86_64 */
  454. /* -------------------------------------------------------------- */
  455. /* enable commandline wildcard expansion (tcc -o x.exe *.c) */
  456. #ifdef _WIN32
  457. int _CRT_glob = 1;
  458. #ifndef _CRT_glob
  459. int _dowildcard = 1;
  460. #endif
  461. #endif
  462. /* -------------------------------------------------------------- */
  463. /* generate xxx.d file */
  464. ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
  465. {
  466. FILE *depout;
  467. char buf[1024];
  468. int i;
  469. if (!filename) {
  470. /* compute filename automatically: dir/file.o -> dir/file.d */
  471. snprintf(buf, sizeof buf, "%.*s.d",
  472. (int)(tcc_fileextension(target) - target), target);
  473. filename = buf;
  474. }
  475. if (s->verbose)
  476. printf("<- %s\n", filename);
  477. /* XXX return err codes instead of error() ? */
  478. depout = fopen(filename, "w");
  479. if (!depout)
  480. tcc_error("could not open '%s'", filename);
  481. fprintf(depout, "%s: \\\n", target);
  482. for (i=0; i<s->nb_target_deps; ++i)
  483. fprintf(depout, " %s \\\n", s->target_deps[i]);
  484. fprintf(depout, "\n");
  485. fclose(depout);
  486. }
  487. /* -------------------------------------------------------------- */