History

ARM target support (Daniel Glockner) - allow unsigned char as default on ARM (Daniel Glockner) - fixed small ld script support (Daniel Glockner)

bellard committed 23 years ago

Commit 4df5bd21 parent 44cea6a5 files · +1526 −18Browse files

Unified · Split

5 files
  1. arm-gen.c +1293 −0
  2. i386-gen.c +11 −1
  3. tcc.c +95 −9
  4. tccelf.c +116 −8
  5. tcctok.h +11 −0
arm-gen.c+1293−0
@@ -0,0 +1,1293 @@
1+/*
2+ * ARMv4 code generator for TCC
3+ *
4+ * Copyright (c) 2003 Daniel Gl�ckner
5+ *
6+ * Based on i386-gen.c by Fabrice Bellard
7+ *
8+ * This library is free software; you can redistribute it and/or
9+ * modify it under the terms of the GNU Lesser General Public
10+ * License as published by the Free Software Foundation; either
11+ * version 2 of the License, or (at your option) any later version.
12+ *
13+ * This library is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+ * Lesser General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU Lesser General Public
19+ * License along with this library; if not, write to the Free Software
20+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21+ */
22+
23+/* number of available registers */
24+#define NB_REGS 9
25+
26+/* a register can belong to several classes. The classes must be
27+ sorted from more general to more precise (see gv2() code which does
28+ assumptions on it). */
29+#define RC_INT 0x0001 /* generic integer register */
30+#define RC_FLOAT 0x0002 /* generic float register */
31+#define RC_R0 0x0004
32+#define RC_R1 0x0008
33+#define RC_R2 0x0010
34+#define RC_R3 0x0020
35+#define RC_R12 0x0040
36+#define RC_F0 0x0080
37+#define RC_F1 0x0100
38+#define RC_F2 0x0200
39+#define RC_F3 0x0400
40+#define RC_IRET RC_R0 /* function return: integer register */
41+#define RC_LRET RC_R1 /* function return: second integer register */
42+#define RC_FRET RC_F0 /* function return: float register */
43+
44+/* pretty names for the registers */
45+enum {
46+ TREG_R0 = 0,
47+ TREG_R1,
48+ TREG_R2,
49+ TREG_R3,
50+ TREG_R12,
51+ TREG_F0,
52+ TREG_F1,
53+ TREG_F2,
54+ TREG_F3,
55+};
56+
57+int reg_classes[NB_REGS] = {
58+ /* r0 */ RC_INT | RC_R0,
59+ /* r1 */ RC_INT | RC_R1,
60+ /* r2 */ RC_INT | RC_R2,
61+ /* r3 */ RC_INT | RC_R3,
62+ /* r12 */ RC_INT | RC_R12,
63+ /* f0 */ RC_FLOAT | RC_F0,
64+ /* f1 */ RC_FLOAT | RC_F1,
65+ /* f2 */ RC_FLOAT | RC_F2,
66+ /* f3 */ RC_FLOAT | RC_F3,
67+};
68+
69+static int two2mask(int a,int b) {
70+ return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);
71+}
72+
73+static int regmask(int r) {
74+ return reg_classes[r]&~(RC_INT|RC_FLOAT);
75+}
76+
77+/* return registers for function */
78+#define REG_IRET TREG_R0 /* single word int return register */
79+#define REG_LRET TREG_R1 /* second word return register (for long long) */
80+#define REG_FRET TREG_F0 /* float return register */
81+
82+/* defined if function parameters must be evaluated in reverse order */
83+#define INVERT_FUNC_PARAMS
84+
85+/* defined if structures are passed as pointers. Otherwise structures
86+ are directly pushed on stack. */
87+//#define FUNC_STRUCT_PARAM_AS_PTR
88+
89+/* pointer size, in bytes */
90+#define PTR_SIZE 4
91+
92+/* long double size and alignment, in bytes */
93+#define LDOUBLE_SIZE 8
94+#define LDOUBLE_ALIGN 4
95+/* maximum alignment (for aligned attribute support) */
96+#define MAX_ALIGN 8
97+
98+#define CHAR_IS_UNSIGNED
99+
100+/******************************************************/
101+/* ELF defines */
102+
103+#define EM_TCC_TARGET EM_ARM
104+
105+/* relocation type for 32 bit data relocation */
106+#define R_DATA_32 R_ARM_ABS32
107+#define R_JMP_SLOT R_ARM_JUMP_SLOT
108+#define R_COPY R_ARM_COPY
109+
110+#define ELF_START_ADDR 0x00008000
111+#define ELF_PAGE_SIZE 0x1000
112+
113+/******************************************************/
114+static unsigned long func_sub_sp_offset,last_itod_magic;
115+
116+void o(unsigned long i)
117+{
118+ /* this is a good place to start adding big-endian support*/
119+ int ind1;
120+
121+ ind1 = ind + 4;
122+ if (ind1 > cur_text_section->data_allocated)
123+ section_realloc(cur_text_section, ind1);
124+ cur_text_section->data[ind++] = i&255;
125+ i>>=8;
126+ cur_text_section->data[ind++] = i&255;
127+ i>>=8;
128+ cur_text_section->data[ind++] = i&255;
129+ i>>=8;
130+ cur_text_section->data[ind++] = i;
131+}
132+
133+static unsigned long stuff_const(unsigned long op,unsigned long c)
134+{
135+ int try_neg=0;
136+ unsigned long nc,negop;
137+ switch(op&0x1F00000)
138+ {
139+ case 0x800000: //add
140+ case 0x400000: //sub
141+ try_neg=1;
142+ negop=op^0xC00000;
143+ nc=-c;
144+ break;
145+ case 0x1A00000: //mov
146+ case 0x1E00000: //mvn
147+ try_neg=1;
148+ negop=op^0x400000;
149+ nc=~c;
150+ break;
151+ case 0x200000: //xor
152+ if(c==~0)
153+ return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000;
154+ break;
155+ case 0x0: //and
156+ if(c==~0)
157+ return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000;
158+ case 0x1C00000: //bic
159+ try_neg=1;
160+ negop=op^0x1C00000;
161+ nc=~c;
162+ break;
163+ case 0x1800000: //orr
164+ if(c==~0)
165+ return (op&0xFFF0FFFF)|0x1E00000;
166+ break;
167+ }
168+ do {
169+ unsigned long m;
170+ int i;
171+ if(c<256) /* catch undefined <<32 */
172+ return op|c;
173+ for(i=2;i<32;i+=2) {
174+ m=(0xff>>i)|(0xff<<(32-i));
175+ if(!(c&~m))
176+ return op|(i<<7)|(c<<i)|(c>>(32-i));
177+ }
178+ op=negop;
179+ c=nc;
180+ } while(try_neg--);
181+ return 0;
182+}
183+
184+
185+//only add,sub
186+void stuff_const_harder(unsigned long op,unsigned long v) {
187+ unsigned long x;
188+ x=stuff_const(op,v);
189+ if(x)
190+ o(x);
191+ else {
192+ unsigned long a[16],nv,no,o2,n2;
193+ int i,j,k;
194+ a[0]=0xff;
195+ o2=(op&0xfff0ffff)|((op&0xf000)<<4);;
196+ for(i=1;i<16;i++)
197+ a[i]=(a[i-1]>>2)|(a[i-1]<<30);
198+ for(i=0;i<12;i++)
199+ for(j=i+4;i<13+i;i++)
200+ if((v&(a[i]|a[j]))==v) {
201+ o(stuff_const(op,v&a[i]));
202+ o(stuff_const(o2,v&a[j]));
203+ return;
204+ }
205+ no=op^0xC00000;
206+ n2=o2^0xC00000;
207+ nv=-v;
208+ for(i=0;i<12;i++)
209+ for(j=i+4;i<13+i;i++)
210+ if((nv&(a[i]|a[j]))==nv) {
211+ o(stuff_const(no,nv&a[i]));
212+ o(stuff_const(n2,nv&a[j]));
213+ return;
214+ }
215+ for(i=0;i<8;i++)
216+ for(j=i+4;i<12;i++)
217+ for(k=j+4;k<13+i;i++)
218+ if((v&(a[i]|a[j]|a[k]))==v) {
219+ o(stuff_const(op,v&a[i]));
220+ o(stuff_const(o2,v&a[j]));
221+ o(stuff_const(o2,v&a[k]));
222+ return;
223+ }
224+ no=op^0xC00000;
225+ nv=-v;
226+ for(i=0;i<8;i++)
227+ for(j=i+4;i<12;i++)
228+ for(k=j+4;k<13+i;i++)
229+ if((nv&(a[i]|a[j]|a[k]))==nv) {
230+ o(stuff_const(no,nv&a[i]));
231+ o(stuff_const(n2,nv&a[j]));
232+ o(stuff_const(n2,nv&a[k]));
233+ return;
234+ }
235+ o(stuff_const(op,v&a[0]));
236+ o(stuff_const(o2,v&a[4]));
237+ o(stuff_const(o2,v&a[8]));
238+ o(stuff_const(o2,v&a[12]));
239+ }
240+}
241+
242+unsigned long encbranch(int pos,int addr,int fail)
243+{
244+ addr-=pos+8;
245+ addr/=4;
246+ if(addr>=0x1000000 || addr<-0x1000000) {
247+ if(fail)
248+ error("FIXME: function bigger than 32MB");
249+ return 0;
250+ }
251+ return 0x0A000000|(addr&0xffffff);
252+}
253+
254+int decbranch(int pos)
255+{
256+ int x;
257+ x=*(int *)(cur_text_section->data + pos);
258+ x&=0x00ffffff;
259+ if(x&0x800000)
260+ x-=0x1000000;
261+ return x*4+pos+8;
262+}
263+
264+/* output a symbol and patch all calls to it */
265+void gsym_addr(int t, int a)
266+{
267+ unsigned long *x;
268+ int lt;
269+ while(t) {
270+ x=(unsigned long *)(cur_text_section->data + t);
271+ t=decbranch(lt=t);
272+ if(a==lt+4)
273+ *x=0xE1A00000; // nop
274+ else {
275+ *x &= 0xff000000;
276+ *x |= encbranch(lt,a,1);
277+ }
278+ }
279+}
280+
281+void gsym(int t)
282+{
283+ gsym_addr(t, ind);
284+}
285+
286+static unsigned long fpr(int r)
287+{
288+ return r-5;
289+}
290+
291+static unsigned long intr(int r)
292+{
293+ return r==4?12:r;
294+}
295+
296+static void calcaddr(unsigned long *base,int *off,int *sgn,int maxoff,unsigned shift)
297+{
298+ if(*off>maxoff || *off&((1<<shift)-1)) {
299+ unsigned long x,y;
300+ x=0xE280E000;
301+ if(*sgn)
302+ x=0xE240E000;
303+ x|=(*base)<<16;
304+ *base=14; // lr
305+ y=stuff_const(x,*off&~maxoff);
306+ if(y) {
307+ o(y);
308+ *off&=maxoff;
309+ return;
310+ }
311+ y=stuff_const(x,(*off+maxoff)&~maxoff);
312+ if(y) {
313+ o(y);
314+ *sgn=!*sgn;
315+ *off=((*off+maxoff)&~maxoff)-*off;
316+ return;
317+ }
318+ stuff_const_harder(x,*off&~maxoff);
319+ *off&=maxoff;
320+ }
321+}
322+
323+static unsigned long mapcc(int cc)
324+{
325+ switch(cc)
326+ {
327+ case TOK_ULT:
328+ return 0x30000000;
329+ case TOK_UGE:
330+ return 0x20000000;
331+ case TOK_EQ:
332+ return 0x00000000;
333+ case TOK_NE:
334+ return 0x10000000;
335+ case TOK_ULE:
336+ return 0x90000000;
337+ case TOK_UGT:
338+ return 0x80000000;
339+ case TOK_LT:
340+ return 0xB0000000;
341+ case TOK_GE:
342+ return 0xA0000000;
343+ case TOK_LE:
344+ return 0xD0000000;
345+ case TOK_GT:
346+ return 0xC0000000;
347+ }
348+ error("unexpected condition code");
349+ return 0xE0000000;
350+}
351+
352+static int negcc(int cc)
353+{
354+ switch(cc)
355+ {
356+ case TOK_ULT:
357+ return TOK_UGE;
358+ case TOK_UGE:
359+ return TOK_ULT;
360+ case TOK_EQ:
361+ return TOK_NE;
362+ case TOK_NE:
363+ return TOK_EQ;
364+ case TOK_ULE:
365+ return TOK_UGT;
366+ case TOK_UGT:
367+ return TOK_ULE;
368+ case TOK_LT:
369+ return TOK_GE;
370+ case TOK_GE:
371+ return TOK_LT;
372+ case TOK_LE:
373+ return TOK_GT;
374+ case TOK_GT:
375+ return TOK_LE;
376+ }
377+ error("unexpected condition code");
378+ return TOK_NE;
379+}
380+
381+/* load 'r' from value 'sv' */
382+void load(int r, SValue *sv)
383+{
384+ int v, ft, fc, fr, sign;
385+ unsigned long op;
386+ SValue v1;
387+
388+ fr = sv->r;
389+ ft = sv->type.t;
390+ fc = sv->c.ul;
391+
392+ if(fc>=0)
393+ sign=0;
394+ else {
395+ sign=1;
396+ fc=-fc;
397+ }
398+
399+ v = fr & VT_VALMASK;
400+ if (fr & VT_LVAL) {
401+ unsigned long base=0xB; // fp
402+ if(v == VT_LLOCAL) {
403+ v1.type.t = VT_PTR;
404+ v1.r = VT_LOCAL | VT_LVAL;
405+ v1.c.ul = sv->c.ul;
406+ load(base=14 /* lr */, &v1);
407+ fc=sign=0;
408+ v=VT_LOCAL;
409+ } else if(v == VT_CONST) {
410+ v1.type.t = VT_PTR;
411+ v1.r = fr&~VT_LVAL;
412+ v1.c.ul = sv->c.ul;
413+ v1.sym=sv->sym;
414+ load(base=14, &v1);
415+ fc=sign=0;
416+ v=VT_LOCAL;
417+ } else if(v < VT_CONST) {
418+ base=intr(v);
419+ fc=sign=0;
420+ v=VT_LOCAL;
421+ }
422+ if(v == VT_LOCAL) {
423+ if(is_float(ft)) {
424+ calcaddr(&base,&fc,&sign,1020,2);
425+ op=0xED100100;
426+ if(!sign)
427+ op|=0x800000;
428+ if ((ft & VT_BTYPE) != VT_FLOAT)
429+ op|=0x8000;
430+ o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
431+ } else if((ft & VT_TYPE) == VT_BYTE || (ft & VT_BTYPE) == VT_SHORT) {
432+ calcaddr(&base,&fc,&sign,255,0);
433+ op=0xE1500090;
434+ if ((ft & VT_BTYPE) == VT_SHORT)
435+ op|=0x20;
436+ if ((ft & VT_UNSIGNED) == 0)
437+ op|=0x40;
438+ if(!sign)
439+ op|=0x800000;
440+ o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
441+ } else {
442+ calcaddr(&base,&fc,&sign,4095,0);
443+ op=0xE5100000;
444+ if(!sign)
445+ op|=0x800000;
446+ if ((ft & VT_BTYPE) == VT_BYTE)
447+ op|=0x400000;
448+ o(op|(intr(r)<<12)|fc|(base<<16));
449+ }
450+ return;
451+ }
452+ } else {
453+ if (v == VT_CONST) {
454+ op=stuff_const(0xE3A00000|(intr(r)<<12),sv->c.ul);
455+ if (fr & VT_SYM || !op) {
456+ o(0xE59F0000|(intr(r)<<12));
457+ o(0xEA000000);
458+ if(fr & VT_SYM)
459+ greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
460+ o(sv->c.ul);
461+ } else
462+ o(op);
463+ return;
464+ } else if (v == VT_LOCAL) {
465+ op=stuff_const(0xE28B0000|(intr(r)<<12),sv->c.ul);
466+ if (fr & VT_SYM || !op) {
467+ o(0xE59F0000|(intr(r)<<12));
468+ o(0xEA000000);
469+ if(fr & VT_SYM) // needed ?
470+ greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32);
471+ o(sv->c.ul);
472+ o(0xE08B0000|(intr(r)<<12)|intr(r));
473+ } else
474+ o(op);
475+ return;
476+ } else if(v == VT_CMP) {
477+ o(mapcc(sv->c.ul)|0x3A00001|(intr(r)<<12));
478+ o(mapcc(negcc(sv->c.ul))|0x3A00000|(intr(r)<<12));
479+ return;
480+ } else if (v == VT_JMP || v == VT_JMPI) {
481+ int t;
482+ t = v & 1;
483+ o(0xE3A00000|(intr(r)<<12)|t);
484+ o(0xEA000000);
485+ gsym(sv->c.ul);
486+ o(0xE3A00000|(intr(r)<<12)|(t^1));
487+ return;
488+ } else if (v < VT_CONST) {
489+ if(is_float(ft))
490+ o(0xEE008180|(fpr(r)<<12)|fpr(v));
491+ else
492+ o(0xE1A00000|(intr(r)<<12)|intr(v));
493+ return;
494+ }
495+ }
496+ error("load unimplemented!");
497+}
498+
499+/* store register 'r' in lvalue 'v' */
500+void store(int r, SValue *sv)
501+{
502+ SValue v1;
503+ int v, ft, fc, fr, sign;
504+ unsigned long op;
505+
506+ fr = sv->r;
507+ ft = sv->type.t;
508+ fc = sv->c.ul;
509+
510+ if(fc>=0)
511+ sign=0;
512+ else {
513+ sign=1;
514+ fc=-fc;
515+ }
516+
517+ v = fr & VT_VALMASK;
518+ if (fr & VT_LVAL || fr == VT_LOCAL) {
519+ unsigned long base=0xb;
520+ if(v < VT_CONST) {
521+ base=intr(v);
522+ v=VT_LOCAL;
523+ fc=sign=0;
524+ } else if(v == VT_CONST) {
525+ v1.type.t = ft;
526+ v1.r = fr&~VT_LVAL;
527+ v1.c.ul = sv->c.ul;
528+ v1.sym=sv->sym;
529+ load(base=14, &v1);
530+ fc=sign=0;
531+ v=VT_LOCAL;
532+ }
533+ if(v == VT_LOCAL) {
534+ if(is_float(ft)) {
535+ calcaddr(&base,&fc,&sign,1020,2);
536+ op=0xED000100;
537+ if(!sign)
538+ op|=0x800000;
539+ if ((ft & VT_BTYPE) != VT_FLOAT)
540+ op|=0x8000;
541+ o(op|(fpr(r)<<12)|(fc>>2)|(base<<16));
542+ return;
543+ } else if((ft & VT_BTYPE) == VT_SHORT) {
544+ calcaddr(&base,&fc,&sign,255,0);
545+ op=0xE14000B0;
546+ if(!sign)
547+ op|=0x800000;
548+ o(op|(intr(r)<<12)|(base<<16)|((fc&0xf0)<<4)|(fc&0xf));
549+ } else {
550+ calcaddr(&base,&fc,&sign,4095,0);
551+ op=0xE5000000;
552+ if(!sign)
553+ op|=0x800000;
554+ if ((ft & VT_BTYPE) == VT_BYTE)
555+ op|=0x400000;
556+ o(op|(intr(r)<<12)|fc|(base<<16));
557+ }
558+ return;
559+ }
560+ }
561+ error("store unimplemented");
562+}
563+
564+static void gadd_sp(int val)
565+{
566+ stuff_const_harder(0xE28DD000,val);
567+}
568+
569+/* 'is_jmp' is '1' if it is a jump */
570+static void gcall_or_jmp(int is_jmp)
571+{
572+ int r;
573+ if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
574+ unsigned long x;
575+ /* constant case */
576+ x=encbranch(ind,ind+vtop->c.ul,0);
577+ if(x) {
578+ if (vtop->r & VT_SYM) {
579+ /* relocation case */
580+ greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
581+ } else
582+ put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
583+ o(x|(is_jmp?0xE0000000:0xE1000000));
584+ } else {
585+ if(!is_jmp)
586+ o(0xE28FE004); // add lr,pc,#4
587+ o(0xE51FF004); // ldr pc,[pc,#-4]
588+ if (vtop->r & VT_SYM)
589+ greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
590+ o(vtop->c.ul);
591+ }
592+ } else {
593+ /* otherwise, indirect call */
594+ r = gv(RC_INT);
595+ if(!is_jmp)
596+ o(0xE1A0E00F); // mov lr,pc
597+ o(0xE1A0F000|intr(r)); // mov pc,r
598+ }
599+}
600+
601+/* Generate function call. The function address is pushed first, then
602+ all the parameters in call order. This functions pops all the
603+ parameters and the function address. */
604+void gfunc_call(int nb_args)
605+{
606+ int size, align, r, args_size, i;
607+ Sym *func_sym;
608+
609+ args_size = 0;
610+ for(i = 0;i < nb_args; i++) {
611+ if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
612+ size = type_size(&vtop->type, &align);
613+ /* align to stack align size */
614+ size = (size + 3) & ~3;
615+ /* allocate the necessary size on stack */
616+ gadd_sp(-size);
617+ /* generate structure store */
618+ r = get_reg(RC_INT);
619+ o(0xE1A0000D|(intr(r)<<12));
620+ vset(&vtop->type, r | VT_LVAL, 0);
621+ vswap();
622+ vstore();
623+ args_size += size;
624+ } else if (is_float(vtop->type.t)) {
625+ r=fpr(gv(RC_FLOAT))<<12;
626+ if ((vtop->type.t & VT_BTYPE) == VT_FLOAT)
627+ size = 4;
628+ else if ((vtop->type.t & VT_BTYPE) == VT_DOUBLE)
629+ size = 8;
630+ else
631+ size = LDOUBLE_SIZE;
632+
633+ if (size == 12)
634+ r|=0x400000;
635+ else if(size == 8)
636+ r|=0x8000;
637+
638+ o(0xED2D0100|r);
639+ args_size += size;
640+ } else {
641+ /* simple type (currently always same size) */
642+ /* XXX: implicit cast ? */
643+ r = gv(RC_INT);
644+ if ((vtop->type.t & VT_BTYPE) == VT_LLONG) {
645+ size = 8;
646+ o(0xE52D0004|(intr(vtop->r2)<<12)); /* str r2,[sp,#-4]! */
647+ } else {
648+ size = 4;
649+ }
650+ o(0xE52D0004|(intr(vtop->r)<<12)); /* str r,[sp,#-4]! */
651+ args_size += size;
652+ }
653+ vtop--;
654+ }
655+ save_regs(0); /* save used temporary registers */
656+ if(args_size) {
657+ int n;
658+ n=args_size/4;
659+ if(n>4)
660+ n=4;
661+ o(0xE8BD0000|((1<<n)-1));
662+ args_size-=n*4;
663+ }
664+ func_sym = vtop->type.ref;
665+ gcall_or_jmp(0);
666+ if (args_size)
667+ gadd_sp(args_size);
668+ vtop--;
669+}
670+
671+/* generate function prolog of type 't' */
672+void gfunc_prolog(CType *func_type)
673+{
674+ Sym *sym,*sym2;
675+ int n,addr,size,align;
676+
677+ sym = func_type->ref;
678+ func_vt = sym->type;
679+
680+ n=0;
681+ addr=12;
682+ if((func_vt.t & VT_BTYPE) == VT_STRUCT) {
683+ func_vc = addr;
684+ addr += 4;
685+ n++;
686+ }
687+ for(sym2=sym->next;sym2 && n<4;sym2=sym2->next) {
688+ size = type_size(&sym2->type, &align);
689+ size = (size + 3) & ~3;
690+ n+=size/4;
691+ }
692+ o(0xE1A0C00D); /* mov ip,sp */
693+ if(func_type->ref->c == FUNC_ELLIPSIS)
694+ n=4;
695+ if(n) {
696+ if(n>4)
697+ n=4;
698+ o(0xE92D0000|((1<<n)-1)); /* save r0-r4 on stack if needed */
699+ }
700+ o(0xE92D5800); /* save fp, ip, lr*/
701+ o(0xE1A0B00D); /* mov fp,sp */
702+ func_sub_sp_offset = ind;
703+ o(0xE1A00000); /* nop, leave space for stack adjustment */
704+ while ((sym = sym->next)) {
705+ CType *type;
706+ type = &sym->type;
707+ sym_push(sym->v & ~SYM_FIELD, type, VT_LOCAL | VT_LVAL, addr);
708+ size = type_size(type, &align);
709+ size = (size + 3) & ~3;
710+ addr += size;
711+ }
712+ last_itod_magic=0;
713+}
714+
715+/* generate function epilog */
716+void gfunc_epilog(void)
717+{
718+ unsigned long x;
719+ o(0xE89BA800); /* restore fp, sp, pc */
720+ if(loc) {
721+ x=stuff_const(0xE24DD000, (-loc + 3) & -4); /* sub sp,sp,# */
722+ if(x)
723+ *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = x;
724+ else {
725+ unsigned long addr;
726+ addr=ind;
727+ o(0xE59FC004); /* ldr ip,[pc+4] */
728+ o(0xE04DD00C); /* sub sp,sp,ip */
729+ o(0xE1A0F00E); /* mov pc,lr */
730+ o((-loc + 3) & -4);
731+ *(unsigned long *)(cur_text_section->data + func_sub_sp_offset) = 0xE1000000|encbranch(func_sub_sp_offset,addr,1);
732+ }
733+ }
734+}
735+
736+/* generate a jump to a label */
737+int gjmp(int t)
738+{
739+ int r;
740+ r=ind;
741+ o(0xE0000000|encbranch(r,t,1));
742+ return r;
743+}
744+
745+/* generate a jump to a fixed address */
746+void gjmp_addr(int a)
747+{
748+ gjmp(a);
749+}
750+
751+/* generate a test. set 'inv' to invert test. Stack entry is popped */
752+int gtst(int inv, int t)
753+{
754+ int v, r;
755+ unsigned long op;
756+ v = vtop->r & VT_VALMASK;
757+ r=ind;
758+ if (v == VT_CMP) {
759+ op=mapcc(inv?negcc(vtop->c.i):vtop->c.i);
760+ op|=encbranch(r,t,1);
761+ o(op);
762+ t=r;
763+ } else if (v == VT_JMP || v == VT_JMPI) {
764+ if ((v & 1) == inv) {
765+ if(!vtop->c.i)
766+ vtop->c.i=t;
767+ else {
768+ unsigned long *x;
769+ int p,lp;
770+ if(t) {
771+ p = vtop->c.i;
772+ do {
773+ p = decbranch(lp=p);
774+ } while(p);
775+ x = (unsigned long *)(cur_text_section->data + lp);
776+ *x &= 0xff000000;
777+ *x |= encbranch(lp,t,1);
778+ }
779+ t = vtop->c.i;
780+ }
781+ } else {
782+ t = gjmp(t);
783+ gsym(vtop->c.i);
784+ }
785+ } else {
786+ if (is_float(vtop->type.t)) {
787+ r=gv(RC_FLOAT);
788+ o(0xEE90F118|fpr(r)<<16);
789+ vtop->r = VT_CMP;
790+ vtop->c.i = TOK_NE;
791+ return gtst(inv, t);
792+ } else if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
793+ /* constant jmp optimization */
794+ if ((vtop->c.i != 0) != inv)
795+ t = gjmp(t);
796+ } else {
797+ v = gv(RC_INT);
798+ o(0xE3300000|(intr(v)<<16));
799+ vtop->r = VT_CMP;
800+ vtop->c.i = TOK_NE;
801+ return gtst(inv, t);
802+ }
803+ }
804+ vtop--;
805+ return t;
806+}
807+
808+/* generate an integer binary operation */
809+void gen_opi(int op)
810+{
811+ int c, func;
812+ unsigned long opc,r,fr;
813+
814+ c=0;
815+ switch(op) {
816+ case '+':
817+ opc = 0x8;
818+ c=1;
819+ break;
820+ case TOK_ADDC1: /* add with carry generation */
821+ opc = 0x9;
822+ c=1;
823+ break;
824+ case '-':
825+ opc = 0x4;
826+ c=1;
827+ break;
828+ case TOK_SUBC1: /* sub with carry generation */
829+ opc = 0x5;
830+ c=1;
831+ break;
832+ case TOK_ADDC2: /* add with carry use */
833+ opc = 0xA;
834+ c=1;
835+ break;
836+ case TOK_SUBC2: /* sub with carry use */
837+ opc = 0xC;
838+ c=1;
839+ break;
840+ case '&':
841+ opc = 0x0;
842+ c=1;
843+ break;
844+ case '^':
845+ opc = 0x2;
846+ c=1;
847+ break;
848+ case '|':
849+ opc = 0x18;
850+ c=1;
851+ break;
852+ case '*':
853+ gv2(RC_INT, RC_INT);
854+ r = vtop[-1].r;
855+ fr = vtop[0].r;
856+ vtop--;
857+ o(0xE0000090|(intr(r)<<16)|(intr(r)<<8)|intr(fr));
858+ return;
859+ case TOK_SHL:
860+ opc = 0;
861+ c=2;
862+ break;
863+ case TOK_SHR:
864+ opc = 1;
865+ c=2;
866+ break;
867+ case TOK_SAR:
868+ opc = 2;
869+ c=2;
870+ break;
871+ case '/':
872+ case TOK_PDIV:
873+ func=TOK___divsi3;
874+ c=3;
875+ break;
876+ case TOK_UDIV:
877+ func=TOK___udivsi3;
878+ c=3;
879+ break;
880+ case '%':
881+ func=TOK___modsi3;
882+ c=3;
883+ break;
884+ case TOK_UMOD:
885+ func=TOK___umodsi3;
886+ c=3;
887+ break;
888+ case TOK_UMULL:
889+ gv2(RC_INT, RC_INT);
890+ r=intr(vtop[-1].r2=get_reg(RC_INT));
891+ c=vtop[-1].r;
892+ vtop[-1].r=get_reg_ex(RC_INT,regmask(c));
893+ vtop--;
894+ o(0xE0800090|(r<<16)|(intr(vtop->r)<<12)|(intr(c)<<8)|intr(vtop[1].r));
895+ return;
896+ default:
897+ opc = 0x15;
898+ c=1;
899+ }
900+ switch(c) {
901+ case 1:
902+ if((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
903+ if(opc == 4 || opc == 5 || opc == 0xc) {
904+ vswap();
905+ opc|=2; // sub -> rsb
906+ }
907+ }
908+ vswap();
909+ c=intr(gv(RC_INT));
910+ vswap();
911+ opc=0xE0000000|(opc<<20)|(c<<16);
912+ if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
913+ unsigned long x;
914+ x=stuff_const(opc|0x2000000,vtop->c.i);
915+ if(x) {
916+ r=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
917+ o(x|(r<<12));
918+ goto done;
919+ }
920+ }
921+ fr=intr(gv(RC_INT));
922+ r=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
923+ o(opc|(r<<12)|fr);
924+done:
925+ vtop--;
926+ if (op >= TOK_ULT && op <= TOK_GT) {
927+ vtop->r = VT_CMP;
928+ vtop->c.i = op;
929+ }
930+ break;
931+ case 2:
932+ opc=0xE1A00000|(opc<<5);
933+ vswap();
934+ r=intr(gv(RC_INT));
935+ vswap();
936+ opc|=r;
937+ if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
938+ fr=intr(vtop[-1].r=get_reg_ex(RC_INT,regmask(vtop[-1].r)));
939+ c = vtop->c.i & 0x1f;
940+ o(opc|(c<<7)|(fr<<12));
941+ } else {
942+ fr=intr(gv(RC_INT));
943+ c=intr(vtop[-1].r=get_reg_ex(RC_INT,two2mask(vtop->r,vtop[-1].r)));
944+ o(opc|(c<<12)|(fr<<8)|0x10);
945+ }
946+ vtop--;
947+ break;
948+ case 3:
949+ vpush_global_sym(&func_old_type, func);
950+ vrott(3);
951+ gfunc_call(2);
952+ vpushi(0);
953+ vtop->r = REG_IRET;
954+ break;
955+ default:
956+ error("gen_opi %i unimplemented!",op);
957+ }
958+}
959+
960+static int is_fconst()
961+{
962+ long double f;
963+ int r;
964+ if((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) != VT_CONST)
965+ return 0;
966+ if (vtop->type.t == VT_FLOAT)
967+ f = vtop->c.f;
968+ else if (vtop->type.t == VT_DOUBLE)
969+ f = vtop->c.d;
970+ else
971+ f = vtop->c.ld;
972+ if(!ieee_finite(f))
973+ return 0;
974+ r=0x8;
975+ if(f<0.0) {
976+ r=0x18;
977+ f=-f;
978+ }
979+ if(f==0.0)
980+ return r;
981+ if(f==1.0)
982+ return r|1;
983+ if(f==2.0)
984+ return r|2;
985+ if(f==3.0)
986+ return r|3;
987+ if(f==4.0)
988+ return r|4;
989+ if(f==5.0)
990+ return r|5;
991+ if(f==0.5)
992+ return r|6;
993+ if(f==10.0)
994+ return r|7;
995+ return 0;
996+}
997+
998+/* generate a floating point operation 'v = t1 op t2' instruction. The
999+ two operands are guaranted to have the same floating point type */
1000+void gen_opf(int op)
1001+{
1002+ unsigned long x;
1003+ int r,r2,c1,c2;
1004+ //fputs("gen_opf\n",stderr);
1005+ vswap();
1006+ c1 = is_fconst();
1007+ vswap();
1008+ c2 = is_fconst();
1009+ x=0xEE000180;
1010+ switch(op)
1011+ {
1012+ case '+':
1013+ if(!c2) {
1014+ vswap();
1015+ c2=c1;
1016+ }
1017+ vswap();
1018+ r=fpr(gv(RC_FLOAT));
1019+ vswap();
1020+ if(c2) {
1021+ if(c2>0xf)
1022+ x|=0x200000; // suf
1023+ r2=c2&0xf;
1024+ } else {
1025+ r2=fpr(gv(RC_FLOAT));
1026+ }
1027+ break;
1028+ case '-':
1029+ if(c2) {
1030+ if(c2<=0xf)
1031+ x|=0x200000; // suf
1032+ r2=c2&0xf;
1033+ vswap();
1034+ r=fpr(gv(RC_FLOAT));
1035+ vswap();
1036+ } else if(c1 && c1<=0xf) {
1037+ x|=0x300000; // rsf
1038+ r2=c1;
1039+ r=fpr(gv(RC_FLOAT));
1040+ vswap();
1041+ } else {
1042+ x|=0x200000; // suf
1043+ vswap();
1044+ r=fpr(gv(RC_FLOAT));
1045+ vswap();
1046+ r2=fpr(gv(RC_FLOAT));
1047+ }
1048+ break;
1049+ case '*':
1050+ if(!c2 || c2>0xf) {
1051+ vswap();
1052+ c2=c1;
1053+ }
1054+ vswap();
1055+ r=fpr(gv(RC_FLOAT));
1056+ vswap();
1057+ if(c2 && c2<=0xf)
1058+ r2=c2;
1059+ else
1060+ r2=fpr(gv(RC_FLOAT));
1061+ x|=0x100000; // muf
1062+ break;
1063+ case '/':
1064+ if(c2 && c2<=0xf) {
1065+ x|=0x400000; // dvf
1066+ r2=c2;
1067+ vswap();
1068+ r=fpr(gv(RC_FLOAT));
1069+ vswap();
1070+ } else if(c1 && c1<=0xf) {
1071+ x|=0x500000; // rdf
1072+ r2=c1;
1073+ r=fpr(gv(RC_FLOAT));
1074+ vswap();
1075+ } else {
1076+ x|=0x400000; // dvf
1077+ vswap();
1078+ r=fpr(gv(RC_FLOAT));
1079+ vswap();
1080+ r2=fpr(gv(RC_FLOAT));
1081+ }
1082+ break;
1083+ default:
1084+ if(op >= TOK_ULT && op <= TOK_GT) {
1085+ switch(op) {
1086+ case TOK_ULT:
1087+ case TOK_UGE:
1088+ case TOK_ULE:
1089+ case TOK_UGT:
1090+ fputs("unsigned comparision on floats?\n",stderr);
1091+ break;
1092+ case TOK_LT:
1093+ op=TOK_ULT;
1094+ break;
1095+ case TOK_GE:
1096+ op=TOK_UGE;
1097+ break;
1098+ case TOK_LE:
1099+ op=TOK_ULE;
1100+ break;
1101+ case TOK_GT:
1102+ op=TOK_UGT;
1103+ break;
1104+ }
1105+ x|=0x90f110;
1106+ if(c1 && !c2) {
1107+ c2=c1;
1108+ vswap();
1109+ switch(op) {
1110+ case TOK_ULT:
1111+ op=TOK_UGT;
1112+ break;
1113+ case TOK_UGE:
1114+ op=TOK_ULE;
1115+ break;
1116+ case TOK_ULE:
1117+ op=TOK_UGE;
1118+ break;
1119+ case TOK_UGT:
1120+ op=TOK_ULT;
1121+ break;
1122+ }
1123+ }
1124+ vswap();
1125+ r=fpr(gv(RC_FLOAT));
1126+ vswap();
1127+ if(c2) {
1128+ if(c2>0xf)
1129+ x|=0x200000;
1130+ r2=c2&0xf;
1131+ } else {
1132+ r2=fpr(gv(RC_FLOAT));
1133+ }
1134+ vtop[-1].r = VT_CMP;
1135+ vtop[-1].c.i = op;
1136+ } else {
1137+ error("unknown fp op %x!\n",op);
1138+ return;
1139+ }
1140+ }
1141+ if(vtop[-1].r == VT_CMP)
1142+ c1=15;
1143+ else {
1144+ c1=vtop->r;
1145+ if(r2&0x8)
1146+ c1=vtop[-1].r;
1147+ vtop[-1].r=get_reg_ex(RC_FLOAT,two2mask(vtop[-1].r,c1));
1148+ c1=fpr(vtop[-1].r);
1149+ }
1150+ vtop--;
1151+ o(x|(r<<16)|(c1<<12)|r2);
1152+}
1153+
1154+/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
1155+ and 'long long' cases. */
1156+void gen_cvt_itof(int t)
1157+{
1158+ int r,r2,bt;
1159+ r=intr(gv(RC_INT));
1160+ r2=fpr(vtop->r=get_reg(RC_FLOAT));
1161+ bt=vtop->type.t & VT_BTYPE;
1162+ if(bt == VT_INT || bt == VT_SHORT || bt == VT_BYTE) {
1163+ o(0xEE000190|(r2<<16)|(r<<12));
1164+ if((vtop->type.t & (VT_UNSIGNED|VT_BTYPE)) == (VT_UNSIGNED|VT_INT)) {
1165+ unsigned int off=0;
1166+ o(0xE3500000|(r<<12));
1167+ r=fpr(get_reg(RC_FLOAT));
1168+ if(last_itod_magic) {
1169+ off=ind+8-last_itod_magic;
1170+ off/=4;
1171+ if(off>255)
1172+ off=0;
1173+ }
1174+ o(0xBD1F8100|(r<<12)|off);
1175+ if(!off) {
1176+ o(0xEA000001);
1177+ last_itod_magic=ind;
1178+ o(0x41F00000);
1179+ o(0);
1180+ }
1181+ o(0xBE000180|(r2<<16)|(r2<<12)|r);
1182+ }
1183+ return;
1184+ } else if(bt == VT_LLONG) {
1185+ int r3;
1186+ unsigned long x=0;
1187+ r3=intr(vtop->r2);
1188+ o(0xe52d0004|(r<<12)); //str r0, [sp, -#4]!
1189+ o(0xe3500000|(r3<<16)); //cmp r1, #0
1190+ o(0xa3800102|(r3<<16)|(r3<<12)); //orrge r1, r1, #0x80000000
1191+ o(0xe59f0014|(r<<12)); //ldr r0, [pc, #20]
1192+ o(0xe52d0004|(r3<<12)); //str r1, [sp, -#4]!
1193+ o(0xe52d0004|(r<<12)); //str r0, [sp, -#4]!
1194+ o(0xecfd0103|(r2<<12)); //ldfe f0, [sp], #12
1195+ r=fpr(get_reg(RC_FLOAT));
1196+ if((vtop->type.t & VT_UNSIGNED) != VT_UNSIGNED)
1197+ x=0xE0000000;
1198+ o(0xaddf0101|(r<<12)|x); //ldf(ge)e f1, [pc, #4]
1199+ o(0xae280100|(r2<<16)|(r2<<12)|r|x); //suf(ge)e f0, f0, f1
1200+ o(0xea000002); //b pc+8
1201+ o(0x403e);o(0x80000000);o(0);
1202+ if(x)
1203+ o(0xbe280100|(r2<<16)|(r2<<12)|r); //suflte f0, f0, f1
1204+ vtop->r2=VT_CONST;
1205+ return;
1206+ }
1207+ error("unimplemented gen_cvt_itof %x!",vtop->type.t);
1208+}
1209+
1210+/* convert fp to int 't' type */
1211+void gen_cvt_ftoi(int t)
1212+{
1213+ int r,r2,u;
1214+ u=t&VT_UNSIGNED;
1215+ t&=VT_BTYPE;
1216+ r=fpr(gv(RC_FLOAT));
1217+ r2=intr(vtop->r=get_reg(RC_INT));
1218+ if(t==VT_INT) {
1219+ if(u) {
1220+ u=fpr(get_reg(RC_FLOAT));
1221+ o(0xed9f0100|(u<<12));
1222+ o(0xea000000);
1223+ o(0x4f000000);
1224+ o(0xee90f110|(r<<12)|u);
1225+ o(0x2e200180|(r<<16)|(r<<12)|u);
1226+ o(0x2e200180|(r<<16)|(r<<12)|u);
1227+ o(0xee100150|(r2<<12)|u);
1228+ } else
1229+ o(0xEE100170|(r<<12)|r);
1230+ return;
1231+ } else if(t==VT_LLONG) {
1232+ int Q,R;
1233+ Q=r2;
1234+ R=intr(vtop->r2=get_reg(RC_INT));
1235+ if(Q<R) {
1236+ Q=R;
1237+ R=r2;
1238+ r2=vtop->r;
1239+ vtop->r=vtop->r2;
1240+ vtop->r2=r2;
1241+ }
1242+ if(!u)
1243+ r2=intr(get_reg(RC_INT));
1244+ o(0xed6d0103|(r<<12));
1245+ o(0xe0dde0b4);
1246+ o(0xe8bd0000|(1<<Q)|(1<<R));
1247+ if(!u)
1248+ o(0xe20e0902|(r2<<12));
1249+ o(0xe3cee902);
1250+ o(0xe24eec3f);
1251+ o(0xe25ee0ff);
1252+ if(!u) {
1253+ o(0xb3a00000|(R<<12));
1254+ o(0xb3a00000|(Q<<12));
1255+ }
1256+ o(0xba000000|(u?5:9));
1257+ o(0xe25ee03f);
1258+ o(0xaa000000|(u?5:3));
1259+ o(0xe1b000a0|(R<<12)|R);
1260+ o(0xe1a00060|(Q<<12)|Q);
1261+ o(0xe29ee001);
1262+ o(0x1afffffb);
1263+ if(u) {
1264+ o(0x13a00000|(R<<12));
1265+ o(0x13a00000|(Q<<12));
1266+ } else {
1267+ o(0xe3500000|(r2<<12));
1268+ o(0x0a000001);
1269+ o(0xe2700000|(Q<<16)|(Q<<12));
1270+ o(0xe2e00000|(R<<16)|(R<<12));
1271+ }
1272+ return;
1273+ }
1274+ error("unimplemented gen_cvt_ftoi!");
1275+}
1276+
1277+/* convert from one floating point type to another */
1278+void gen_cvt_ftof(int t)
1279+{
1280+ /* all we have to do on i386 and ARM is to put the float in a register */
1281+ gv(RC_FLOAT);
1282+}
1283+
1284+/* computed goto support */
1285+void ggoto(void)
1286+{
1287+ gcall_or_jmp(1);
1288+ vtop--;
1289+}
1290+
1291+/* end of ARM code generator */
1292+/*************************************************************/
1293+
i386-gen.c+11−1
@@ -70,8 +70,18 @@ int reg_classes[NB_REGS] = { · 69 unmodified lines
7070 /* maximum alignment (for aligned attribute support) */
7171 #define MAX_ALIGN 8
7272
73+/******************************************************/
74+/* ELF defines */
75+
76+#define EM_TCC_TARGET EM_386
77+
7378 /* relocation type for 32 bit data relocation */
74−#define R_DATA_32 R_386_32
79+#define R_DATA_32 R_386_32
80+#define R_JMP_SLOT R_386_JMP_SLOT
81+#define R_COPY R_386_COPY
82+
83+#define ELF_START_ADDR 0x08048000
84+#define ELF_PAGE_SIZE 0x1000
7585
7686 /******************************************************/
7787
tcc.c+95−9
@@ -61,18 +61,21 @@ · 60 unmodified lines
6161
6262 /* target selection */
6363 //#define TCC_TARGET_I386 /* i386 code generator */
64+//#define TCC_TARGET_ARM /* ARMv4 code generator */
6465
6566 /* default target is I386 */
66−#if !defined(TCC_TARGET_I386)
67+#if !defined(TCC_TARGET_I386) && !defined(TCC_TARGET_ARM)
6768 #define TCC_TARGET_I386
6869 #endif
6970
70−#if !defined(WIN32) && !defined(TCC_UCLIBC)
71+#if !defined(WIN32) && !defined(TCC_UCLIBC) && !defined(TCC_TARGET_ARM)
7172 #define CONFIG_TCC_BCHECK /* enable bound checking code */
7273 #endif
7374
7475 /* define it to include assembler support */
76+#if !defined(TCC_TARGET_ARM)
7577 #define CONFIG_TCC_ASM
78+#endif
7679
7780 /* path to find crt1.o, crti.o and crtn.o. Only needed when generating
7881 executables or dlls */
@@ -471,6 +474,7 @@ struct TCCState { · 392 unmodified lines
471474 #define VT_BITFIELD 0x0040 /* bitfield modifier */
472475 #define VT_CONSTANT 0x0800 /* const modifier */
473476 #define VT_VOLATILE 0x1000 /* volatile modifier */
477+#define VT_SIGNED 0x2000 /* signed type */
474478
475479 /* storage */
476480 #define VT_EXTERN 0x00000080 /* extern definition */
@@ -684,6 +688,7 @@ void vpop(void); · 207 unmodified lines
684688 void vswap(void);
685689 void vdup(void);
686690 int get_reg(int rc);
691+int get_reg_ex(int rc,int rc2);
687692
688693 static void macro_subst(TokenString *tok_str, Sym **nested_list,
689694 const int *macro_str, int can_read_stream);
@@ -704,8 +709,11 @@ static int parse_btype(CType *type, AttributeDef *ad); · 14 unmodified lines
704709 static void type_decl(CType *type, AttributeDef *ad, int *v, int td);
705710 static int is_compatible_types(CType *type1, CType *type2);
706711
712+int ieee_finite(double d);
707713 void error(const char *fmt, ...);
708714 void vpushi(int v);
715+void vrott(int n);
716+static void vpush_global_sym(CType *type, int v);
709717 void vset(CType *type, int r, int v);
710718 void type_to_str(char *buf, int buf_size,
711719 CType *type, const char *varstr);
@@ -785,6 +793,10 @@ static inline int is_float(int t) · 73 unmodified lines
785793 #include "i386-gen.c"
786794 #endif
787795
796+#ifdef TCC_TARGET_ARM
797+#include "arm-gen.c"
798+#endif
799+
788800 #ifdef CONFIG_TCC_STATIC
789801
790802 #define RTLD_LAZY 0x001
@@ -2220,15 +2232,18 @@ static void tok_str_add2(TokenString *s, int t, CValue *cv) · 1429 unmodified lines
22202232 case TOK_CDOUBLE:
22212233 case TOK_CLLONG:
22222234 case TOK_CULLONG:
2235+#if LDOUBLE_SIZE == 8
2236+ case TOK_CLDOUBLE:
2237+#endif
22232238 str[len++] = cv->tab[0];
22242239 str[len++] = cv->tab[1];
22252240 break;
2226− case TOK_CLDOUBLE:
22272241 #if LDOUBLE_SIZE == 12
2242+ case TOK_CLDOUBLE:
22282243 str[len++] = cv->tab[0];
22292244 str[len++] = cv->tab[1];
22302245 str[len++] = cv->tab[2];
2231−#else
2246+#elif LDOUBLE_SIZE != 8
22322247 #error add long double size support
22332248 #endif
22342249 break;
@@ -2257,6 +2272,10 @@ static void tok_str_add_tok(TokenString *s) · 22 unmodified lines
22572272 cv.tab[0] = p[0]; \
22582273 cv.tab[1] = p[1]; \
22592274 cv.tab[2] = p[2];
2275+#elif LDOUBLE_SIZE == 8
2276+#define LDOUBLE_GET(p, cv) \
2277+ cv.tab[0] = p[0]; \
2278+ cv.tab[1] = p[1];
22602279 #else
22612280 #error add long double size support
22622281 #endif
@@ -4335,6 +4354,29 @@ void save_reg(int r) · 2072 unmodified lines
43354354 }
43364355 }
43374356
4357+/* find a register of class 'rc2' with at most one reference on stack.
4358+ * If none, call get_reg(rc) */
4359+int get_reg_ex(int rc, int rc2)
4360+{
4361+ int r;
4362+ SValue *p;
4363+
4364+ for(r=0;r<NB_REGS;r++) {
4365+ if (reg_classes[r] & rc2) {
4366+ int n;
4367+ n=0;
4368+ for(p = vstack; p <= vtop; p++) {
4369+ if ((p->r & VT_VALMASK) == r ||
4370+ (p->r2 & VT_VALMASK) == r)
4371+ n++;
4372+ }
4373+ if (n <= 1)
4374+ return r;
4375+ }
4376+ }
4377+ return get_reg(rc);
4378+}
4379+
43384380 /* find a free register of class 'rc'. If none, save one register */
43394381 int get_reg(int rc)
43404382 {
@@ -4905,10 +4947,13 @@ void gen_opl(int op) · 564 unmodified lines
49054947 if (a == 0) {
49064948 b = gtst(0, 0);
49074949 } else {
4908−#ifdef TCC_TARGET_I386
4950+#if defined(TCC_TARGET_I386)
49094951 b = psym(0x850f, 0);
4952+#elif defined(TCC_TARGET_ARM)
4953+ b = ind;
4954+ o(0x1A000000 | encbranch(ind, 0, 1));
49104955 #else
4911− error("not implemented");
4956+#error not supported
49124957 #endif
49134958 }
49144959 }
@@ -5447,7 +5492,11 @@ static void gen_cast(CType *type) · 532 unmodified lines
54475492 }
54485493 } else {
54495494 do_itof:
5495+#if !defined(TCC_TARGET_ARM)
54505496 gen_cvt_itof1(dbt);
5497+#else
5498+ gen_cvt_itof(dbt);
5499+#endif
54515500 }
54525501 } else if (sf) {
54535502 /* convert fp to int */
@@ -6302,6 +6351,9 @@ static int parse_btype(CType *type, AttributeDef *ad) · 848 unmodified lines
63026351 case TOK_SIGNED2:
63036352 case TOK_SIGNED3:
63046353 typespec_found = 1;
6354+ t |= VT_SIGNED;
6355+ next();
6356+ break;
63056357 case TOK_REGISTER:
63066358 case TOK_AUTO:
63076359 case TOK_RESTRICT1:
@@ -6361,6 +6413,14 @@ static int parse_btype(CType *type, AttributeDef *ad) · 53 unmodified lines
63616413 type_found = 1;
63626414 }
63636415 the_end:
6416+ if ((t & (VT_SIGNED|VT_UNSIGNED)) == (VT_SIGNED|VT_UNSIGNED))
6417+ error("signed and unsigned modifier");
6418+#ifdef CHAR_IS_UNSIGNED
6419+ if ((t & (VT_SIGNED|VT_UNSIGNED|VT_BTYPE)) == VT_BYTE)
6420+ t |= VT_UNSIGNED;
6421+#endif
6422+ t &= ~VT_SIGNED;
6423+
63646424 /* long is never used as type */
63656425 if ((t & VT_BTYPE) == VT_LONG)
63666426 t = (t & ~VT_BTYPE) | VT_INT;
@@ -8838,7 +8898,9 @@ void tcc_undefine_symbol(TCCState *s1, const char *sym) · 2471 unmodified lines
88388898
88398899 #ifdef CONFIG_TCC_ASM
88408900
8901+#ifdef TCC_TARGET_I386
88418902 #include "i386-asm.c"
8903+#endif
88428904 #include "tccasm.c"
88438905
88448906 #else
@@ -9013,7 +9075,14 @@ static int rt_get_caller_pc(unsigned long *paddr, · 168 unmodified lines
90139075 }
90149076 }
90159077 #else
9016−#error add arch specific rt_get_caller_pc()
9078+
9079+#warning add arch specific rt_get_caller_pc()
9080+
9081+static int rt_get_caller_pc(unsigned long *paddr,
9082+ ucontext_t *uc, int level)
9083+{
9084+ return -1;
9085+}
90179086 #endif
90189087
90199088 /* emit a run time error at position 'pc' */
@@ -9207,6 +9276,19 @@ TCCState *tcc_new(void) · 187 unmodified lines
92079276 #if defined(TCC_TARGET_I386)
92089277 tcc_define_symbol(s, "__i386__", NULL);
92099278 #endif
9279+#if defined(TCC_TARGET_ARM)
9280+ tcc_define_symbol(s, "__ARM_ARCH_4__", NULL);
9281+ tcc_define_symbol(s, "__arm_elf__", NULL);
9282+ tcc_define_symbol(s, "__arm_elf", NULL);
9283+ tcc_define_symbol(s, "arm_elf", NULL);
9284+ tcc_define_symbol(s, "__arm__", NULL);
9285+ tcc_define_symbol(s, "__arm", NULL);
9286+ tcc_define_symbol(s, "arm", NULL);
9287+ tcc_define_symbol(s, "__APCS_32__", NULL);
9288+#endif
9289+#ifdef CHAR_IS_UNSIGNED
9290+ tcc_define_symbol(s, "__CHAR_UNSIGNED__", NULL);
9291+#endif
92109292 #if defined(linux)
92119293 tcc_define_symbol(s, "__linux__", NULL);
92129294 tcc_define_symbol(s, "linux", NULL);
@@ -9359,11 +9441,14 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 146 unmodified lines
93599441 {
93609442 fd = file->fd;
93619443 /* assume executable format: auto guess file type */
9362− if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
9444+ ret = read(fd, &ehdr, sizeof(ehdr));
9445+ lseek(fd, 0, SEEK_SET);
9446+ if (ret <= 0) {
93639447 error_noabort("could not read header");
93649448 goto fail;
9449+ } else if (ret != sizeof(ehdr)) {
9450+ goto try_load_script;
93659451 }
9366− lseek(fd, 0, SEEK_SET);
93679452
93689453 if (ehdr.e_ident[0] == ELFMAG0 &&
93699454 ehdr.e_ident[1] == ELFMAG1 &&
@@ -9393,6 +9478,7 @@ static int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 23 unmodified lines
93939478 ret = tcc_load_archive(s1, fd);
93949479 } else {
93959480 /* as GNU ld, consider it is an ld script if not recognized */
9481+ try_load_script:
93969482 ret = tcc_load_ldscript(s1);
93979483 if (ret < 0) {
93989484 error_noabort("unrecognized file type");
tccelf.c+116−8
@@ -468,6 +468,7 @@ static void relocate_section(TCCState *s1, Section *s) · 467 unmodified lines
468468
469469 /* CPU specific */
470470 switch(type) {
471+#if defined(TCC_TARGET_I386)
471472 case R_386_32:
472473 if (s1->output_type == TCC_OUTPUT_DLL) {
473474 esym_index = s1->symtab_to_dynsym[sym_index];
@@ -513,6 +514,43 @@ static void relocate_section(TCCState *s1, Section *s) · 39 unmodified lines
513514 /* we load the got offset */
514515 *(int *)ptr += s1->got_offsets[sym_index];
515516 break;
517+#elif defined(TCC_TARGET_ARM)
518+ case R_ARM_PC24:
519+ case R_ARM_PLT32:
520+ {
521+ int x;
522+ x = (*(int *)ptr)&0xffffff;
523+ (*(int *)ptr) &= 0xff000000;
524+ if (x & 0x800000)
525+ x -= 0x1000000;
526+ x *= 4;
527+ x += val - addr;
528+ if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000)
529+ error("can't relocate value at %x",addr);
530+ x >>= 2;
531+ x &= 0xffffff;
532+ (*(int *)ptr) |= x;
533+ }
534+ break;
535+ case R_ARM_ABS32:
536+ *(int *)ptr += val;
537+ break;
538+ case R_ARM_GOTPC:
539+ *(int *)ptr += s1->got->sh_addr - addr;
540+ break;
541+ case R_ARM_GOT32:
542+ /* we load the got offset */
543+ *(int *)ptr += s1->got_offsets[sym_index];
544+ break;
545+ case R_ARM_COPY:
546+ break;
547+ default:
548+ fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n",
549+ type,addr,(unsigned int )ptr,val);
550+ break;
551+#else
552+#error unsupported processor
553+#endif
516554 }
517555 }
518556 /* if the relocation is allocated, we change its symbol table */
@@ -646,6 +684,7 @@ static void put_got_entry(TCCState *s1, · 127 unmodified lines
646684 sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
647685 name = symtab_section->link->data + sym->st_name;
648686 offset = sym->st_value;
687+#ifdef TCC_TARGET_I386
649688 if (reloc_type == R_386_JMP_SLOT) {
650689 Section *plt;
651690 uint8_t *p;
@@ -684,6 +723,40 @@ static void put_got_entry(TCCState *s1, · 32 unmodified lines
684723 if (s1->output_type == TCC_OUTPUT_EXE)
685724 offset = plt->data_offset - 16;
686725 }
726+#elif defined(TCC_TARGET_ARM)
727+ if (reloc_type == R_ARM_JUMP_SLOT) {
728+ Section *plt;
729+ uint8_t *p;
730+
731+ /* if we build a DLL, we add a %ebx offset */
732+ if (s1->output_type == TCC_OUTPUT_DLL)
733+ error("DLLs unimplemented!");
734+
735+ /* add a PLT entry */
736+ plt = s1->plt;
737+ if (plt->data_offset == 0) {
738+ /* first plt entry */
739+ p = section_ptr_add(plt, 16);
740+ put32(p , 0xe52de004);
741+ put32(p + 4, 0xe59fe010);
742+ put32(p + 8, 0xe08fe00e);
743+ put32(p + 12, 0xe5bef008);
744+ }
745+
746+ p = section_ptr_add(plt, 16);
747+ put32(p , 0xe59fc004);
748+ put32(p+4, 0xe08fc00c);
749+ put32(p+8, 0xe59cf000);
750+ put32(p+12, s1->got->data_offset);
751+
752+ /* the symbol is modified so that it will be relocated to
753+ the PLT */
754+ if (s1->output_type == TCC_OUTPUT_EXE)
755+ offset = plt->data_offset - 16;
756+ }
757+#else
758+#error unsupported CPU
759+#endif
687760 index = put_elf_sym(s1->dynsym, offset,
688761 size, info, 0, sym->st_shndx, name);
689762 /* put a got entry */
@@ -717,6 +790,7 @@ static void build_got_entries(TCCState *s1) · 27 unmodified lines
717790 rel++) {
718791 type = ELF32_R_TYPE(rel->r_info);
719792 switch(type) {
793+#if defined(TCC_TARGET_I386)
720794 case R_386_GOT32:
721795 case R_386_GOTOFF:
722796 case R_386_GOTPC:
@@ -735,6 +809,28 @@ static void build_got_entries(TCCState *s1) · 12 unmodified lines
735809 sym_index);
736810 }
737811 break;
812+#elif defined(TCC_TARGET_ARM)
813+ case R_ARM_GOT32:
814+ case R_ARM_GOTOFF:
815+ case R_ARM_GOTPC:
816+ case R_ARM_PLT32:
817+ if (!s1->got)
818+ build_got(s1);
819+ if (type == R_ARM_GOT32 || type == R_ARM_PLT32) {
820+ sym_index = ELF32_R_SYM(rel->r_info);
821+ sym = &((Elf32_Sym *)symtab_section->data)[sym_index];
822+ /* look at the symbol got offset. If none, then add one */
823+ if (type == R_ARM_GOT32)
824+ reloc_type = R_ARM_GLOB_DAT;
825+ else
826+ reloc_type = R_ARM_JUMP_SLOT;
827+ put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
828+ sym_index);
829+ }
830+ break;
831+#else
832+#error unsupported CPU
833+#endif
738834 default:
739835 break;
740836 }
@@ -916,9 +1012,6 @@ static char elf_interp[] = "/usr/libexec/ld-elf.so.1"; · 175 unmodified lines
9161012 static char elf_interp[] = "/lib/ld-linux.so.2";
9171013 #endif
9181014
919−#define ELF_START_ADDR 0x08048000
920−#define ELF_PAGE_SIZE 0x1000
921−
9221015 /* output an ELF file */
9231016 /* XXX: suppress unneeded sections */
9241017 int tcc_output_file(TCCState *s1, const char *filename)
@@ -1005,7 +1098,7 @@ int tcc_output_file(TCCState *s1, const char *filename) · 80 unmodified lines
10051098 esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index];
10061099 type = ELF32_ST_TYPE(esym->st_info);
10071100 if (type == STT_FUNC) {
1008− put_got_entry(s1, R_386_JMP_SLOT, esym->st_size,
1101+ put_got_entry(s1, R_JMP_SLOT, esym->st_size,
10091102 esym->st_info,
10101103 sym - (Elf32_Sym *)symtab_section->data);
10111104 } else if (type == STT_OBJECT) {
@@ -1017,7 +1110,7 @@ int tcc_output_file(TCCState *s1, const char *filename) · 5 unmodified lines
10171110 esym->st_info, 0,
10181111 bss_section->sh_num, name);
10191112 put_elf_reloc(s1->dynsym, bss_section,
1020− offset, R_386_COPY, index);
1113+ offset, R_COPY, index);
10211114 offset += esym->st_size;
10221115 bss_section->data_offset = offset;
10231116 }
@@ -1306,6 +1399,7 @@ int tcc_output_file(TCCState *s1, const char *filename) · 282 unmodified lines
13061399 p = s1->plt->data;
13071400 p_end = p + s1->plt->data_offset;
13081401 if (p < p_end) {
1402+#if defined(TCC_TARGET_I386)
13091403 put32(p + 2, get32(p + 2) + s1->got->sh_addr);
13101404 put32(p + 8, get32(p + 8) + s1->got->sh_addr);
13111405 p += 16;
@@ -1313,6 +1407,17 @@ int tcc_output_file(TCCState *s1, const char *filename) · 1 unmodified line
13131407 put32(p + 2, get32(p + 2) + s1->got->sh_addr);
13141408 p += 16;
13151409 }
1410+#elif defined(TCC_TARGET_ARM)
1411+ int x;
1412+ x=s1->got->sh_addr - s1->plt->sh_addr - 12;
1413+ p +=16;
1414+ while (p < p_end) {
1415+ put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
1416+ p += 16;
1417+ }
1418+#else
1419+#error unsupported CPU
1420+#endif
13161421 }
13171422 }
13181423
@@ -1415,6 +1520,9 @@ int tcc_output_file(TCCState *s1, const char *filename) · 96 unmodified lines
14151520 ehdr.e_ident[6] = EV_CURRENT;
14161521 #ifdef __FreeBSD__
14171522 ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
1523+#endif
1524+#ifdef TCC_TARGET_ARM
1525+ ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
14181526 #endif
14191527 switch(file_type) {
14201528 default:
@@ -1428,7 +1536,7 @@ int tcc_output_file(TCCState *s1, const char *filename) · 7 unmodified lines
14281536 ehdr.e_type = ET_REL;
14291537 break;
14301538 }
1431− ehdr.e_machine = EM_386;
1539+ ehdr.e_machine = EM_TCC_TARGET;
14321540 ehdr.e_version = EV_CURRENT;
14331541 ehdr.e_shoff = file_offset;
14341542 ehdr.e_ehsize = sizeof(Elf32_Ehdr);
@@ -1543,7 +1651,7 @@ static int tcc_load_object_file(TCCState *s1, · 108 unmodified lines
15431651 goto fail1;
15441652 /* test CPU specific stuff */
15451653 if (ehdr.e_ident[5] != ELFDATA2LSB ||
1546− ehdr.e_machine != EM_386) {
1654+ ehdr.e_machine != EM_TCC_TARGET) {
15471655 fail1:
15481656 error_noabort("invalid object file");
15491657 return -1;
@@ -1881,7 +1989,7 @@ static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 331 unmodified lines
18811989
18821990 /* test CPU specific stuff */
18831991 if (ehdr.e_ident[5] != ELFDATA2LSB ||
1884− ehdr.e_machine != EM_386) {
1992+ ehdr.e_machine != EM_TCC_TARGET) {
18851993 error_noabort("bad architecture");
18861994 return -1;
18871995 }
tcctok.h+11−0
@@ -111,9 +111,20 @@ · 110 unmodified lines
111111 DEF(TOK___moddi3, "__moddi3")
112112 DEF(TOK___udivdi3, "__udivdi3")
113113 DEF(TOK___umoddi3, "__umoddi3")
114+#ifdef TCC_TARGET_ARM
115+ DEF(TOK___divsi3, "__divsi3")
116+ DEF(TOK___modsi3, "__modsi3")
117+ DEF(TOK___udivsi3, "__udivsi3")
118+ DEF(TOK___umodsi3, "__umodsi3")
119+ DEF(TOK___sardi3, "__ashrdi3")
120+ DEF(TOK___shrdi3, "__lshrdi3")
121+ DEF(TOK___shldi3, "__ashldi3")
122+#else
123+ /* XXX: same names on i386 ? */
114124 DEF(TOK___sardi3, "__sardi3")
115125 DEF(TOK___shrdi3, "__shrdi3")
116126 DEF(TOK___shldi3, "__shldi3")
127+#endif
117128 DEF(TOK___tcc_int_fpu_control, "__tcc_int_fpu_control")
118129 DEF(TOK___tcc_fpu_control, "__tcc_fpu_control")
119130 DEF(TOK___ulltof, "__ulltof")