tccasm.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. /*
  2. * GAS like assembler for TCC
  3. *
  4. * Copyright (c) 2001-2004 Fabrice Bellard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "tcc.h"
  21. #ifdef CONFIG_TCC_ASM
  22. ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
  23. {
  24. char buf[64];
  25. TokenSym *ts;
  26. snprintf(buf, sizeof(buf), "L..%u", n);
  27. ts = tok_alloc(buf, strlen(buf));
  28. return ts->tok;
  29. }
  30. ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
  31. static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global);
  32. static Sym sym_dot;
  33. /* Return a symbol we can use inside the assembler, having name NAME.
  34. The assembler symbol table is different from the C symbol table
  35. (and the Sym members are used differently). But we must be able
  36. to look up file-global C symbols from inside the assembler, e.g.
  37. for global asm blocks to be able to refer to defined C symbols.
  38. This routine gives back either an existing asm-internal
  39. symbol, or a new one. In the latter case the new asm-internal
  40. symbol is initialized with info from the C symbol table.
  41. If CSYM is non-null we take symbol info from it, otherwise
  42. we look up NAME in the C symbol table and use that. */
  43. ST_FUNC Sym* get_asm_sym(int name, Sym *csym)
  44. {
  45. Sym *sym = label_find(name);
  46. if (!sym) {
  47. sym = label_push(&tcc_state->asm_labels, name, 0);
  48. sym->type.t = VT_VOID | VT_EXTERN;
  49. if (!csym) {
  50. csym = sym_find(name);
  51. /* We might be called for an asm block from inside a C routine
  52. and so might have local decls on the identifier stack. Search
  53. for the first global one. */
  54. while (csym && csym->sym_scope)
  55. csym = csym->prev_tok;
  56. }
  57. /* Now, if we have a defined global symbol copy over
  58. section and offset. */
  59. if (csym &&
  60. ((csym->r & (VT_SYM|VT_CONST)) == (VT_SYM|VT_CONST)) &&
  61. csym->c) {
  62. ElfW(Sym) *esym;
  63. esym = &((ElfW(Sym) *)symtab_section->data)[csym->c];
  64. sym->c = csym->c;
  65. sym->r = esym->st_shndx;
  66. sym->jnext = esym->st_value;
  67. /* XXX can't yet store st_size anywhere. */
  68. sym->type.t &= ~VT_EXTERN;
  69. /* Mark that this asm symbol doesn't need to be fed back. */
  70. sym->a.dllimport = 1;
  71. } else {
  72. sym->type.t |= VT_STATIC;
  73. }
  74. }
  75. return sym;
  76. }
  77. /* We do not use the C expression parser to handle symbols. Maybe the
  78. C expression parser could be tweaked to do so. */
  79. static void asm_expr_unary(TCCState *s1, ExprValue *pe)
  80. {
  81. Sym *sym;
  82. int op, label;
  83. uint64_t n;
  84. const char *p;
  85. switch(tok) {
  86. case TOK_PPNUM:
  87. p = tokc.str.data;
  88. n = strtoull(p, (char **)&p, 0);
  89. if (*p == 'b' || *p == 'f') {
  90. /* backward or forward label */
  91. label = asm_get_local_label_name(s1, n);
  92. sym = label_find(label);
  93. if (*p == 'b') {
  94. /* backward : find the last corresponding defined label */
  95. if (sym && sym->r == 0)
  96. sym = sym->prev_tok;
  97. if (!sym)
  98. tcc_error("local label '%d' not found backward", n);
  99. } else {
  100. /* forward */
  101. if (!sym || sym->r) {
  102. /* if the last label is defined, then define a new one */
  103. sym = label_push(&s1->asm_labels, label, 0);
  104. sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
  105. }
  106. }
  107. pe->v = 0;
  108. pe->sym = sym;
  109. pe->pcrel = 0;
  110. } else if (*p == '\0') {
  111. pe->v = n;
  112. pe->sym = NULL;
  113. pe->pcrel = 0;
  114. } else {
  115. tcc_error("invalid number syntax");
  116. }
  117. next();
  118. break;
  119. case '+':
  120. next();
  121. asm_expr_unary(s1, pe);
  122. break;
  123. case '-':
  124. case '~':
  125. op = tok;
  126. next();
  127. asm_expr_unary(s1, pe);
  128. if (pe->sym)
  129. tcc_error("invalid operation with label");
  130. if (op == '-')
  131. pe->v = -pe->v;
  132. else
  133. pe->v = ~pe->v;
  134. break;
  135. case TOK_CCHAR:
  136. case TOK_LCHAR:
  137. pe->v = tokc.i;
  138. pe->sym = NULL;
  139. pe->pcrel = 0;
  140. next();
  141. break;
  142. case '(':
  143. next();
  144. asm_expr(s1, pe);
  145. skip(')');
  146. break;
  147. case '.':
  148. pe->v = 0;
  149. pe->sym = &sym_dot;
  150. pe->pcrel = 0;
  151. sym_dot.type.t = VT_VOID | VT_STATIC;
  152. sym_dot.r = cur_text_section->sh_num;
  153. sym_dot.jnext = ind;
  154. next();
  155. break;
  156. default:
  157. if (tok >= TOK_IDENT) {
  158. /* label case : if the label was not found, add one */
  159. sym = get_asm_sym(tok, NULL);
  160. if (sym->r == SHN_ABS) {
  161. /* if absolute symbol, no need to put a symbol value */
  162. pe->v = sym->jnext;
  163. pe->sym = NULL;
  164. pe->pcrel = 0;
  165. } else {
  166. pe->v = 0;
  167. pe->sym = sym;
  168. pe->pcrel = 0;
  169. }
  170. next();
  171. } else {
  172. tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
  173. }
  174. break;
  175. }
  176. }
  177. static void asm_expr_prod(TCCState *s1, ExprValue *pe)
  178. {
  179. int op;
  180. ExprValue e2;
  181. asm_expr_unary(s1, pe);
  182. for(;;) {
  183. op = tok;
  184. if (op != '*' && op != '/' && op != '%' &&
  185. op != TOK_SHL && op != TOK_SAR)
  186. break;
  187. next();
  188. asm_expr_unary(s1, &e2);
  189. if (pe->sym || e2.sym)
  190. tcc_error("invalid operation with label");
  191. switch(op) {
  192. case '*':
  193. pe->v *= e2.v;
  194. break;
  195. case '/':
  196. if (e2.v == 0) {
  197. div_error:
  198. tcc_error("division by zero");
  199. }
  200. pe->v /= e2.v;
  201. break;
  202. case '%':
  203. if (e2.v == 0)
  204. goto div_error;
  205. pe->v %= e2.v;
  206. break;
  207. case TOK_SHL:
  208. pe->v <<= e2.v;
  209. break;
  210. default:
  211. case TOK_SAR:
  212. pe->v >>= e2.v;
  213. break;
  214. }
  215. }
  216. }
  217. static void asm_expr_logic(TCCState *s1, ExprValue *pe)
  218. {
  219. int op;
  220. ExprValue e2;
  221. asm_expr_prod(s1, pe);
  222. for(;;) {
  223. op = tok;
  224. if (op != '&' && op != '|' && op != '^')
  225. break;
  226. next();
  227. asm_expr_prod(s1, &e2);
  228. if (pe->sym || e2.sym)
  229. tcc_error("invalid operation with label");
  230. switch(op) {
  231. case '&':
  232. pe->v &= e2.v;
  233. break;
  234. case '|':
  235. pe->v |= e2.v;
  236. break;
  237. default:
  238. case '^':
  239. pe->v ^= e2.v;
  240. break;
  241. }
  242. }
  243. }
  244. static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
  245. {
  246. int op;
  247. ExprValue e2;
  248. asm_expr_logic(s1, pe);
  249. for(;;) {
  250. op = tok;
  251. if (op != '+' && op != '-')
  252. break;
  253. next();
  254. asm_expr_logic(s1, &e2);
  255. if (op == '+') {
  256. if (pe->sym != NULL && e2.sym != NULL)
  257. goto cannot_relocate;
  258. pe->v += e2.v;
  259. if (pe->sym == NULL && e2.sym != NULL)
  260. pe->sym = e2.sym;
  261. } else {
  262. pe->v -= e2.v;
  263. /* NOTE: we are less powerful than gas in that case
  264. because we store only one symbol in the expression */
  265. if (!e2.sym) {
  266. /* OK */
  267. } else if (pe->sym == e2.sym) {
  268. /* OK */
  269. pe->sym = NULL; /* same symbols can be subtracted to NULL */
  270. } else if (pe->sym && pe->sym->r == e2.sym->r && pe->sym->r != 0) {
  271. /* we also accept defined symbols in the same section */
  272. pe->v += pe->sym->jnext - e2.sym->jnext;
  273. pe->sym = NULL;
  274. } else if (e2.sym->r == cur_text_section->sh_num) {
  275. /* When subtracting a defined symbol in current section
  276. this actually makes the value PC-relative. */
  277. pe->v -= e2.sym->jnext - ind - 4;
  278. pe->pcrel = 1;
  279. e2.sym = NULL;
  280. } else {
  281. cannot_relocate:
  282. tcc_error("invalid operation with label");
  283. }
  284. }
  285. }
  286. }
  287. static inline void asm_expr_cmp(TCCState *s1, ExprValue *pe)
  288. {
  289. int op;
  290. ExprValue e2;
  291. asm_expr_sum(s1, pe);
  292. for(;;) {
  293. op = tok;
  294. if (op != TOK_EQ && op != TOK_NE
  295. && (op > TOK_GT || op < TOK_ULE))
  296. break;
  297. next();
  298. asm_expr_sum(s1, &e2);
  299. if (pe->sym || e2.sym)
  300. tcc_error("invalid operation with label");
  301. switch(op) {
  302. case TOK_EQ:
  303. pe->v = pe->v == e2.v;
  304. break;
  305. case TOK_NE:
  306. pe->v = pe->v != e2.v;
  307. break;
  308. case TOK_LT:
  309. pe->v = (int64_t)pe->v < (int64_t)e2.v;
  310. break;
  311. case TOK_GE:
  312. pe->v = (int64_t)pe->v >= (int64_t)e2.v;
  313. break;
  314. case TOK_LE:
  315. pe->v = (int64_t)pe->v <= (int64_t)e2.v;
  316. break;
  317. case TOK_GT:
  318. pe->v = (int64_t)pe->v > (int64_t)e2.v;
  319. break;
  320. default:
  321. break;
  322. }
  323. /* GAS compare results are -1/0 not 1/0. */
  324. pe->v = -(int64_t)pe->v;
  325. }
  326. }
  327. ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
  328. {
  329. asm_expr_cmp(s1, pe);
  330. }
  331. ST_FUNC int asm_int_expr(TCCState *s1)
  332. {
  333. ExprValue e;
  334. asm_expr(s1, &e);
  335. if (e.sym)
  336. expect("constant");
  337. return e.v;
  338. }
  339. /* NOTE: the same name space as C labels is used to avoid using too
  340. much memory when storing labels in TokenStrings */
  341. static Sym* asm_new_label1(TCCState *s1, int label, int is_local,
  342. int sh_num, int value)
  343. {
  344. Sym *sym;
  345. sym = label_find(label);
  346. if (sym) {
  347. /* A VT_EXTERN symbol, even if it has a section is considered
  348. overridable. This is how we "define" .set targets. Real
  349. definitions won't have VT_EXTERN set. */
  350. if (sym->r && !(sym->type.t & VT_EXTERN)) {
  351. /* the label is already defined */
  352. if (!is_local) {
  353. tcc_error("assembler label '%s' already defined",
  354. get_tok_str(label, NULL));
  355. } else {
  356. /* redefinition of local labels is possible */
  357. goto new_label;
  358. }
  359. }
  360. } else {
  361. new_label:
  362. sym = label_push(&s1->asm_labels, label, 0);
  363. /* If we need a symbol to hold a value, mark it as
  364. tentative only (for .set). If this is for a real label
  365. we'll remove VT_EXTERN. */
  366. sym->type.t = VT_STATIC | VT_VOID | VT_EXTERN;
  367. }
  368. sym->r = sh_num;
  369. sym->jnext = value;
  370. return sym;
  371. }
  372. static Sym* asm_new_label(TCCState *s1, int label, int is_local)
  373. {
  374. return asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
  375. }
  376. /* Set the value of LABEL to that of some expression (possibly
  377. involving other symbols). LABEL can be overwritten later still. */
  378. static Sym* set_symbol(TCCState *s1, int label)
  379. {
  380. long n;
  381. ExprValue e;
  382. next();
  383. asm_expr(s1, &e);
  384. n = e.v;
  385. if (e.sym)
  386. n += e.sym->jnext;
  387. return asm_new_label1(s1, label, 0, e.sym ? e.sym->r : SHN_ABS, n);
  388. }
  389. static void asm_free_labels(TCCState *st)
  390. {
  391. Sym *s, *s1;
  392. Section *sec;
  393. for(s = st->asm_labels; s != NULL; s = s1) {
  394. s1 = s->prev;
  395. /* define symbol value in object file */
  396. s->type.t &= ~VT_EXTERN;
  397. if (s->r && !s->a.dllimport) {
  398. if (s->r == SHN_ABS)
  399. sec = SECTION_ABS;
  400. else
  401. sec = st->sections[s->r];
  402. put_extern_sym2(s, sec, s->jnext, 0, 0);
  403. }
  404. /* remove label */
  405. table_ident[s->v - TOK_IDENT]->sym_label = NULL;
  406. sym_free(s);
  407. }
  408. st->asm_labels = NULL;
  409. }
  410. static void use_section1(TCCState *s1, Section *sec)
  411. {
  412. cur_text_section->data_offset = ind;
  413. cur_text_section = sec;
  414. ind = cur_text_section->data_offset;
  415. }
  416. static void use_section(TCCState *s1, const char *name)
  417. {
  418. Section *sec;
  419. sec = find_section(s1, name);
  420. use_section1(s1, sec);
  421. }
  422. static void push_section(TCCState *s1, const char *name)
  423. {
  424. Section *sec = find_section(s1, name);
  425. sec->prev = cur_text_section;
  426. use_section1(s1, sec);
  427. }
  428. static void pop_section(TCCState *s1)
  429. {
  430. Section *prev = cur_text_section->prev;
  431. if (!prev)
  432. tcc_error(".popsection without .pushsection");
  433. cur_text_section->prev = NULL;
  434. use_section1(s1, prev);
  435. }
  436. static void asm_parse_directive(TCCState *s1, int global)
  437. {
  438. int n, offset, v, size, tok1;
  439. Section *sec;
  440. uint8_t *ptr;
  441. /* assembler directive */
  442. sec = cur_text_section;
  443. switch(tok) {
  444. case TOK_ASMDIR_align:
  445. case TOK_ASMDIR_balign:
  446. case TOK_ASMDIR_p2align:
  447. case TOK_ASMDIR_skip:
  448. case TOK_ASMDIR_space:
  449. tok1 = tok;
  450. next();
  451. n = asm_int_expr(s1);
  452. if (tok1 == TOK_ASMDIR_p2align)
  453. {
  454. if (n < 0 || n > 30)
  455. tcc_error("invalid p2align, must be between 0 and 30");
  456. n = 1 << n;
  457. tok1 = TOK_ASMDIR_align;
  458. }
  459. if (tok1 == TOK_ASMDIR_align || tok1 == TOK_ASMDIR_balign) {
  460. if (n < 0 || (n & (n-1)) != 0)
  461. tcc_error("alignment must be a positive power of two");
  462. offset = (ind + n - 1) & -n;
  463. size = offset - ind;
  464. /* the section must have a compatible alignment */
  465. if (sec->sh_addralign < n)
  466. sec->sh_addralign = n;
  467. } else {
  468. if (n < 0)
  469. n = 0;
  470. size = n;
  471. }
  472. v = 0;
  473. if (tok == ',') {
  474. next();
  475. v = asm_int_expr(s1);
  476. }
  477. zero_pad:
  478. if (sec->sh_type != SHT_NOBITS) {
  479. sec->data_offset = ind;
  480. ptr = section_ptr_add(sec, size);
  481. memset(ptr, v, size);
  482. }
  483. ind += size;
  484. break;
  485. case TOK_ASMDIR_quad:
  486. #ifdef TCC_TARGET_X86_64
  487. size = 8;
  488. goto asm_data;
  489. #else
  490. next();
  491. for(;;) {
  492. uint64_t vl;
  493. const char *p;
  494. p = tokc.str.data;
  495. if (tok != TOK_PPNUM) {
  496. error_constant:
  497. tcc_error("64 bit constant");
  498. }
  499. vl = strtoll(p, (char **)&p, 0);
  500. if (*p != '\0')
  501. goto error_constant;
  502. next();
  503. if (sec->sh_type != SHT_NOBITS) {
  504. /* XXX: endianness */
  505. gen_le32(vl);
  506. gen_le32(vl >> 32);
  507. } else {
  508. ind += 8;
  509. }
  510. if (tok != ',')
  511. break;
  512. next();
  513. }
  514. break;
  515. #endif
  516. case TOK_ASMDIR_byte:
  517. size = 1;
  518. goto asm_data;
  519. case TOK_ASMDIR_word:
  520. case TOK_ASMDIR_short:
  521. size = 2;
  522. goto asm_data;
  523. case TOK_ASMDIR_long:
  524. case TOK_ASMDIR_int:
  525. size = 4;
  526. asm_data:
  527. next();
  528. for(;;) {
  529. ExprValue e;
  530. asm_expr(s1, &e);
  531. if (sec->sh_type != SHT_NOBITS) {
  532. if (size == 4) {
  533. gen_expr32(&e);
  534. #ifdef TCC_TARGET_X86_64
  535. } else if (size == 8) {
  536. gen_expr64(&e);
  537. #endif
  538. } else {
  539. if (e.sym)
  540. expect("constant");
  541. if (size == 1)
  542. g(e.v);
  543. else
  544. gen_le16(e.v);
  545. }
  546. } else {
  547. ind += size;
  548. }
  549. if (tok != ',')
  550. break;
  551. next();
  552. }
  553. break;
  554. case TOK_ASMDIR_fill:
  555. {
  556. int repeat, size, val, i, j;
  557. uint8_t repeat_buf[8];
  558. next();
  559. repeat = asm_int_expr(s1);
  560. if (repeat < 0) {
  561. tcc_error("repeat < 0; .fill ignored");
  562. break;
  563. }
  564. size = 1;
  565. val = 0;
  566. if (tok == ',') {
  567. next();
  568. size = asm_int_expr(s1);
  569. if (size < 0) {
  570. tcc_error("size < 0; .fill ignored");
  571. break;
  572. }
  573. if (size > 8)
  574. size = 8;
  575. if (tok == ',') {
  576. next();
  577. val = asm_int_expr(s1);
  578. }
  579. }
  580. /* XXX: endianness */
  581. repeat_buf[0] = val;
  582. repeat_buf[1] = val >> 8;
  583. repeat_buf[2] = val >> 16;
  584. repeat_buf[3] = val >> 24;
  585. repeat_buf[4] = 0;
  586. repeat_buf[5] = 0;
  587. repeat_buf[6] = 0;
  588. repeat_buf[7] = 0;
  589. for(i = 0; i < repeat; i++) {
  590. for(j = 0; j < size; j++) {
  591. g(repeat_buf[j]);
  592. }
  593. }
  594. }
  595. break;
  596. case TOK_ASMDIR_rept:
  597. {
  598. int repeat;
  599. TokenString *init_str;
  600. next();
  601. repeat = asm_int_expr(s1);
  602. init_str = tok_str_alloc();
  603. while (next(), tok != TOK_ASMDIR_endr) {
  604. if (tok == CH_EOF)
  605. tcc_error("we at end of file, .endr not found");
  606. tok_str_add_tok(init_str);
  607. }
  608. tok_str_add(init_str, -1);
  609. tok_str_add(init_str, 0);
  610. begin_macro(init_str, 1);
  611. while (repeat-- > 0) {
  612. tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS),
  613. global);
  614. macro_ptr = init_str->str;
  615. }
  616. end_macro();
  617. next();
  618. break;
  619. }
  620. case TOK_ASMDIR_org:
  621. {
  622. unsigned long n;
  623. ExprValue e;
  624. next();
  625. asm_expr(s1, &e);
  626. n = e.v;
  627. if (e.sym) {
  628. if (e.sym->r != cur_text_section->sh_num)
  629. expect("constant or same-section symbol");
  630. n += e.sym->jnext;
  631. }
  632. if (n < ind)
  633. tcc_error("attempt to .org backwards");
  634. v = 0;
  635. size = n - ind;
  636. goto zero_pad;
  637. }
  638. break;
  639. case TOK_ASMDIR_set:
  640. next();
  641. tok1 = tok;
  642. next();
  643. /* Also accept '.set stuff', but don't do anything with this.
  644. It's used in GAS to set various features like '.set mips16'. */
  645. if (tok == ',')
  646. set_symbol(s1, tok1);
  647. break;
  648. case TOK_ASMDIR_globl:
  649. case TOK_ASMDIR_global:
  650. case TOK_ASMDIR_weak:
  651. case TOK_ASMDIR_hidden:
  652. tok1 = tok;
  653. do {
  654. Sym *sym;
  655. next();
  656. sym = get_asm_sym(tok, NULL);
  657. if (tok1 != TOK_ASMDIR_hidden)
  658. sym->type.t &= ~VT_STATIC;
  659. if (tok1 == TOK_ASMDIR_weak)
  660. sym->a.weak = 1;
  661. else if (tok1 == TOK_ASMDIR_hidden)
  662. sym->a.visibility = STV_HIDDEN;
  663. next();
  664. } while (tok == ',');
  665. break;
  666. case TOK_ASMDIR_string:
  667. case TOK_ASMDIR_ascii:
  668. case TOK_ASMDIR_asciz:
  669. {
  670. const uint8_t *p;
  671. int i, size, t;
  672. t = tok;
  673. next();
  674. for(;;) {
  675. if (tok != TOK_STR)
  676. expect("string constant");
  677. p = tokc.str.data;
  678. size = tokc.str.size;
  679. if (t == TOK_ASMDIR_ascii && size > 0)
  680. size--;
  681. for(i = 0; i < size; i++)
  682. g(p[i]);
  683. next();
  684. if (tok == ',') {
  685. next();
  686. } else if (tok != TOK_STR) {
  687. break;
  688. }
  689. }
  690. }
  691. break;
  692. case TOK_ASMDIR_text:
  693. case TOK_ASMDIR_data:
  694. case TOK_ASMDIR_bss:
  695. {
  696. char sname[64];
  697. tok1 = tok;
  698. n = 0;
  699. next();
  700. if (tok != ';' && tok != TOK_LINEFEED) {
  701. n = asm_int_expr(s1);
  702. next();
  703. }
  704. if (n)
  705. sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
  706. else
  707. sprintf(sname, "%s", get_tok_str(tok1, NULL));
  708. use_section(s1, sname);
  709. }
  710. break;
  711. case TOK_ASMDIR_file:
  712. {
  713. char filename[512];
  714. filename[0] = '\0';
  715. next();
  716. if (tok == TOK_STR)
  717. pstrcat(filename, sizeof(filename), tokc.str.data);
  718. else
  719. pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
  720. if (s1->warn_unsupported)
  721. tcc_warning("ignoring .file %s", filename);
  722. next();
  723. }
  724. break;
  725. case TOK_ASMDIR_ident:
  726. {
  727. char ident[256];
  728. ident[0] = '\0';
  729. next();
  730. if (tok == TOK_STR)
  731. pstrcat(ident, sizeof(ident), tokc.str.data);
  732. else
  733. pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
  734. if (s1->warn_unsupported)
  735. tcc_warning("ignoring .ident %s", ident);
  736. next();
  737. }
  738. break;
  739. case TOK_ASMDIR_size:
  740. {
  741. Sym *sym;
  742. next();
  743. sym = label_find(tok);
  744. if (!sym) {
  745. tcc_error("label not found: %s", get_tok_str(tok, NULL));
  746. }
  747. /* XXX .size name,label2-label1 */
  748. if (s1->warn_unsupported)
  749. tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
  750. next();
  751. skip(',');
  752. while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
  753. next();
  754. }
  755. }
  756. break;
  757. case TOK_ASMDIR_type:
  758. {
  759. Sym *sym;
  760. const char *newtype;
  761. next();
  762. sym = get_asm_sym(tok, NULL);
  763. next();
  764. skip(',');
  765. if (tok == TOK_STR) {
  766. newtype = tokc.str.data;
  767. } else {
  768. if (tok == '@' || tok == '%')
  769. next();
  770. newtype = get_tok_str(tok, NULL);
  771. }
  772. if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
  773. sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC;
  774. }
  775. else if (s1->warn_unsupported)
  776. tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
  777. get_tok_str(sym->v, NULL), sym->type.t, newtype);
  778. next();
  779. }
  780. break;
  781. case TOK_ASMDIR_pushsection:
  782. case TOK_ASMDIR_section:
  783. {
  784. char sname[256];
  785. int old_nb_section = s1->nb_sections;
  786. tok1 = tok;
  787. /* XXX: support more options */
  788. next();
  789. sname[0] = '\0';
  790. while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
  791. if (tok == TOK_STR)
  792. pstrcat(sname, sizeof(sname), tokc.str.data);
  793. else
  794. pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
  795. next();
  796. }
  797. if (tok == ',') {
  798. /* skip section options */
  799. next();
  800. if (tok != TOK_STR)
  801. expect("string constant");
  802. next();
  803. if (tok == ',') {
  804. next();
  805. if (tok == '@' || tok == '%')
  806. next();
  807. next();
  808. }
  809. }
  810. last_text_section = cur_text_section;
  811. if (tok1 == TOK_ASMDIR_section)
  812. use_section(s1, sname);
  813. else
  814. push_section(s1, sname);
  815. /* If we just allocated a new section reset its alignment to
  816. 1. new_section normally acts for GCC compatibility and
  817. sets alignment to PTR_SIZE. The assembler behaves different. */
  818. if (old_nb_section != s1->nb_sections)
  819. cur_text_section->sh_addralign = 1;
  820. }
  821. break;
  822. case TOK_ASMDIR_previous:
  823. {
  824. Section *sec;
  825. next();
  826. if (!last_text_section)
  827. tcc_error("no previous section referenced");
  828. sec = cur_text_section;
  829. use_section1(s1, last_text_section);
  830. last_text_section = sec;
  831. }
  832. break;
  833. case TOK_ASMDIR_popsection:
  834. next();
  835. pop_section(s1);
  836. break;
  837. #ifdef TCC_TARGET_I386
  838. case TOK_ASMDIR_code16:
  839. {
  840. next();
  841. s1->seg_size = 16;
  842. }
  843. break;
  844. case TOK_ASMDIR_code32:
  845. {
  846. next();
  847. s1->seg_size = 32;
  848. }
  849. break;
  850. #endif
  851. #ifdef TCC_TARGET_X86_64
  852. /* added for compatibility with GAS */
  853. case TOK_ASMDIR_code64:
  854. next();
  855. break;
  856. #endif
  857. default:
  858. tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
  859. break;
  860. }
  861. }
  862. /* assemble a file */
  863. static int tcc_assemble_internal(TCCState *s1, int do_preprocess, int global)
  864. {
  865. int opcode;
  866. int saved_parse_flags = parse_flags;
  867. /* XXX: undefine C labels */
  868. parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
  869. if (do_preprocess)
  870. parse_flags |= PARSE_FLAG_PREPROCESS;
  871. for(;;) {
  872. next();
  873. if (tok == TOK_EOF)
  874. break;
  875. /* generate line number info */
  876. if (global && s1->do_debug)
  877. tcc_debug_line(s1);
  878. parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
  879. redo:
  880. if (tok == '#') {
  881. /* horrible gas comment */
  882. while (tok != TOK_LINEFEED)
  883. next();
  884. } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
  885. asm_parse_directive(s1, global);
  886. } else if (tok == TOK_PPNUM) {
  887. Sym *sym;
  888. const char *p;
  889. int n;
  890. p = tokc.str.data;
  891. n = strtoul(p, (char **)&p, 10);
  892. if (*p != '\0')
  893. expect("':'");
  894. /* new local label */
  895. sym = asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
  896. /* Remove the marker for tentative definitions. */
  897. sym->type.t &= ~VT_EXTERN;
  898. next();
  899. skip(':');
  900. goto redo;
  901. } else if (tok >= TOK_IDENT) {
  902. /* instruction or label */
  903. opcode = tok;
  904. next();
  905. if (tok == ':') {
  906. /* handle "extern void vide(void); __asm__("vide: ret");" as
  907. "__asm__("globl vide\nvide: ret");" */
  908. Sym *sym = sym_find(opcode);
  909. if (sym && (sym->type.t & VT_EXTERN) && global) {
  910. sym = label_find(opcode);
  911. if (!sym) {
  912. sym = label_push(&s1->asm_labels, opcode, 0);
  913. sym->type.t = VT_VOID | VT_EXTERN;
  914. }
  915. }
  916. /* new label */
  917. sym = asm_new_label(s1, opcode, 0);
  918. sym->type.t &= ~VT_EXTERN;
  919. next();
  920. goto redo;
  921. } else if (tok == '=') {
  922. set_symbol(s1, opcode);
  923. goto redo;
  924. } else {
  925. asm_opcode(s1, opcode);
  926. }
  927. }
  928. /* end of line */
  929. if (tok != ';' && tok != TOK_LINEFEED)
  930. expect("end of line");
  931. parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
  932. }
  933. asm_free_labels(s1);
  934. parse_flags = saved_parse_flags;
  935. return 0;
  936. }
  937. /* Assemble the current file */
  938. ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
  939. {
  940. int ret;
  941. tcc_debug_start(s1);
  942. /* default section is text */
  943. cur_text_section = text_section;
  944. ind = cur_text_section->data_offset;
  945. nocode_wanted = 0;
  946. ret = tcc_assemble_internal(s1, do_preprocess, 1);
  947. cur_text_section->data_offset = ind;
  948. tcc_debug_end(s1);
  949. return ret;
  950. }
  951. /********************************************************************/
  952. /* GCC inline asm support */
  953. /* assemble the string 'str' in the current C compilation unit without
  954. C preprocessing. NOTE: str is modified by modifying the '\0' at the
  955. end */
  956. static void tcc_assemble_inline(TCCState *s1, char *str, int len, int global)
  957. {
  958. const int *saved_macro_ptr = macro_ptr;
  959. int dotid = set_idnum('.', IS_ID);
  960. tcc_open_bf(s1, ":asm:", len);
  961. memcpy(file->buffer, str, len);
  962. macro_ptr = NULL;
  963. tcc_assemble_internal(s1, 0, global);
  964. tcc_close();
  965. set_idnum('.', dotid);
  966. macro_ptr = saved_macro_ptr;
  967. }
  968. /* find a constraint by its number or id (gcc 3 extended
  969. syntax). return -1 if not found. Return in *pp in char after the
  970. constraint */
  971. ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands,
  972. const char *name, const char **pp)
  973. {
  974. int index;
  975. TokenSym *ts;
  976. const char *p;
  977. if (isnum(*name)) {
  978. index = 0;
  979. while (isnum(*name)) {
  980. index = (index * 10) + (*name) - '0';
  981. name++;
  982. }
  983. if ((unsigned)index >= nb_operands)
  984. index = -1;
  985. } else if (*name == '[') {
  986. name++;
  987. p = strchr(name, ']');
  988. if (p) {
  989. ts = tok_alloc(name, p - name);
  990. for(index = 0; index < nb_operands; index++) {
  991. if (operands[index].id == ts->tok)
  992. goto found;
  993. }
  994. index = -1;
  995. found:
  996. name = p + 1;
  997. } else {
  998. index = -1;
  999. }
  1000. } else {
  1001. index = -1;
  1002. }
  1003. if (pp)
  1004. *pp = name;
  1005. return index;
  1006. }
  1007. static void subst_asm_operands(ASMOperand *operands, int nb_operands,
  1008. CString *out_str, CString *in_str)
  1009. {
  1010. int c, index, modifier;
  1011. const char *str;
  1012. ASMOperand *op;
  1013. SValue sv;
  1014. cstr_new(out_str);
  1015. str = in_str->data;
  1016. for(;;) {
  1017. c = *str++;
  1018. if (c == '%') {
  1019. if (*str == '%') {
  1020. str++;
  1021. goto add_char;
  1022. }
  1023. modifier = 0;
  1024. if (*str == 'c' || *str == 'n' ||
  1025. *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
  1026. *str == 'q' ||
  1027. /* P in GCC would add "@PLT" to symbol refs in PIC mode,
  1028. and make literal operands not be decorated with '$'. */
  1029. *str == 'P')
  1030. modifier = *str++;
  1031. index = find_constraint(operands, nb_operands, str, &str);
  1032. if (index < 0)
  1033. tcc_error("invalid operand reference after %%");
  1034. op = &operands[index];
  1035. sv = *op->vt;
  1036. if (op->reg >= 0) {
  1037. sv.r = op->reg;
  1038. if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
  1039. sv.r |= VT_LVAL;
  1040. }
  1041. subst_asm_operand(out_str, &sv, modifier);
  1042. } else {
  1043. add_char:
  1044. cstr_ccat(out_str, c);
  1045. if (c == '\0')
  1046. break;
  1047. }
  1048. }
  1049. }
  1050. static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
  1051. int is_output)
  1052. {
  1053. ASMOperand *op;
  1054. int nb_operands;
  1055. if (tok != ':') {
  1056. nb_operands = *nb_operands_ptr;
  1057. for(;;) {
  1058. CString astr;
  1059. if (nb_operands >= MAX_ASM_OPERANDS)
  1060. tcc_error("too many asm operands");
  1061. op = &operands[nb_operands++];
  1062. op->id = 0;
  1063. if (tok == '[') {
  1064. next();
  1065. if (tok < TOK_IDENT)
  1066. expect("identifier");
  1067. op->id = tok;
  1068. next();
  1069. skip(']');
  1070. }
  1071. parse_mult_str(&astr, "string constant");
  1072. op->constraint = tcc_malloc(astr.size);
  1073. strcpy(op->constraint, astr.data);
  1074. cstr_free(&astr);
  1075. skip('(');
  1076. gexpr();
  1077. if (is_output) {
  1078. if (!(vtop->type.t & VT_ARRAY))
  1079. test_lvalue();
  1080. } else {
  1081. /* we want to avoid LLOCAL case, except when the 'm'
  1082. constraint is used. Note that it may come from
  1083. register storage, so we need to convert (reg)
  1084. case */
  1085. if ((vtop->r & VT_LVAL) &&
  1086. ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
  1087. (vtop->r & VT_VALMASK) < VT_CONST) &&
  1088. !strchr(op->constraint, 'm')) {
  1089. gv(RC_INT);
  1090. }
  1091. }
  1092. op->vt = vtop;
  1093. skip(')');
  1094. if (tok == ',') {
  1095. next();
  1096. } else {
  1097. break;
  1098. }
  1099. }
  1100. *nb_operands_ptr = nb_operands;
  1101. }
  1102. }
  1103. /* parse the GCC asm() instruction */
  1104. ST_FUNC void asm_instr(void)
  1105. {
  1106. CString astr, astr1;
  1107. ASMOperand operands[MAX_ASM_OPERANDS];
  1108. int nb_outputs, nb_operands, i, must_subst, out_reg;
  1109. uint8_t clobber_regs[NB_ASM_REGS];
  1110. next();
  1111. /* since we always generate the asm() instruction, we can ignore
  1112. volatile */
  1113. if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
  1114. next();
  1115. }
  1116. parse_asm_str(&astr);
  1117. nb_operands = 0;
  1118. nb_outputs = 0;
  1119. must_subst = 0;
  1120. memset(clobber_regs, 0, sizeof(clobber_regs));
  1121. if (tok == ':') {
  1122. next();
  1123. must_subst = 1;
  1124. /* output args */
  1125. parse_asm_operands(operands, &nb_operands, 1);
  1126. nb_outputs = nb_operands;
  1127. if (tok == ':') {
  1128. next();
  1129. if (tok != ')') {
  1130. /* input args */
  1131. parse_asm_operands(operands, &nb_operands, 0);
  1132. if (tok == ':') {
  1133. /* clobber list */
  1134. /* XXX: handle registers */
  1135. next();
  1136. for(;;) {
  1137. if (tok != TOK_STR)
  1138. expect("string constant");
  1139. asm_clobber(clobber_regs, tokc.str.data);
  1140. next();
  1141. if (tok == ',') {
  1142. next();
  1143. } else {
  1144. break;
  1145. }
  1146. }
  1147. }
  1148. }
  1149. }
  1150. }
  1151. skip(')');
  1152. /* NOTE: we do not eat the ';' so that we can restore the current
  1153. token after the assembler parsing */
  1154. if (tok != ';')
  1155. expect("';'");
  1156. /* save all values in the memory */
  1157. save_regs(0);
  1158. /* compute constraints */
  1159. asm_compute_constraints(operands, nb_operands, nb_outputs,
  1160. clobber_regs, &out_reg);
  1161. /* substitute the operands in the asm string. No substitution is
  1162. done if no operands (GCC behaviour) */
  1163. #ifdef ASM_DEBUG
  1164. printf("asm: \"%s\"\n", (char *)astr.data);
  1165. #endif
  1166. if (must_subst) {
  1167. subst_asm_operands(operands, nb_operands, &astr1, &astr);
  1168. cstr_free(&astr);
  1169. } else {
  1170. astr1 = astr;
  1171. }
  1172. #ifdef ASM_DEBUG
  1173. printf("subst_asm: \"%s\"\n", (char *)astr1.data);
  1174. #endif
  1175. /* generate loads */
  1176. asm_gen_code(operands, nb_operands, nb_outputs, 0,
  1177. clobber_regs, out_reg);
  1178. /* assemble the string with tcc internal assembler */
  1179. tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1, 0);
  1180. /* restore the current C token */
  1181. next();
  1182. /* store the output values if needed */
  1183. asm_gen_code(operands, nb_operands, nb_outputs, 1,
  1184. clobber_regs, out_reg);
  1185. /* free everything */
  1186. for(i=0;i<nb_operands;i++) {
  1187. ASMOperand *op;
  1188. op = &operands[i];
  1189. tcc_free(op->constraint);
  1190. vpop();
  1191. }
  1192. cstr_free(&astr1);
  1193. }
  1194. ST_FUNC void asm_global_instr(void)
  1195. {
  1196. CString astr;
  1197. int saved_nocode_wanted = nocode_wanted;
  1198. /* Global asm blocks are always emitted. */
  1199. nocode_wanted = 0;
  1200. next();
  1201. parse_asm_str(&astr);
  1202. skip(')');
  1203. /* NOTE: we do not eat the ';' so that we can restore the current
  1204. token after the assembler parsing */
  1205. if (tok != ';')
  1206. expect("';'");
  1207. #ifdef ASM_DEBUG
  1208. printf("asm_global: \"%s\"\n", (char *)astr.data);
  1209. #endif
  1210. cur_text_section = text_section;
  1211. ind = cur_text_section->data_offset;
  1212. /* assemble the string with tcc internal assembler */
  1213. tcc_assemble_inline(tcc_state, astr.data, astr.size - 1, 1);
  1214. cur_text_section->data_offset = ind;
  1215. /* restore the current C token */
  1216. next();
  1217. cstr_free(&astr);
  1218. nocode_wanted = saved_nocode_wanted;
  1219. }
  1220. #endif /* CONFIG_TCC_ASM */