History

added 16-bit x86 assembly support

Frederic Feret committed 17 years ago

Commit 0d768b91 parent 2349efa8 files · +245 −37Browse files

Unified · Split

8 files
  1. elf.h +4 −0
  2. i386-asm.c +188 −31
  3. i386-asm.h +15 −6
  4. libtcc.c +3 −0
  5. tcc.h +4 −0
  6. tccasm.c +14 −0
  7. tccelf.c +12 −0
  8. tcctok.h +5 −0
elf.h+4−0
@@ -949,6 +949,10 @@ typedef struct · 948 unmodified lines
949949 /* Keep this the last entry. */
950950 #define R_386_NUM 11
951951
952+/* TCC-specific 16-bit relocs. */
953+#define R_386_16 12 /* Direct 16 bit */
954+#define R_386_PC16 13 /* PC relative 16 bit */
955+
952956 /* SUN SPARC specific definitions. */
953957
954958 /* Values for Elf64_Ehdr.e_flags. */
i386-asm.c+188−31
@@ -116,8 +116,6 @@ static const uint8_t reg_to_size[5] = { · 115 unmodified lines
116116 */
117117 0, 0, 1, 0, 2
118118 };
119−
120−#define WORD_PREFIX_OPCODE 0x66
121119
122120 #define NB_TEST_OPCODES 30
123121
@@ -190,6 +188,10 @@ static inline int get_reg_shift(TCCState *s1) · 66 unmodified lines
190188 {
191189 int shift, v;
192190
191+ if (s1->seg_size == 16) {
192+ error("invalid effective address");
193+ }
194+
193195 v = asm_int_expr(s1);
194196 switch(v) {
195197 case 1:
@@ -222,9 +224,13 @@ static int asm_parse_reg(void) · 26 unmodified lines
222224 reg = tok - TOK_ASM_eax;
223225 next();
224226 return reg;
227+ } else if (tok >= TOK_ASM_ax && tok <= TOK_ASM_di) {
228+ reg = tok - TOK_ASM_ax;
229+ next();
230+ return reg;
225231 } else {
226232 error_32:
227− expect("32 bit register");
233+ expect("register");
228234 return 0;
229235 }
230236 }
@@ -336,6 +342,12 @@ static void parse_operand(TCCState *s1, Operand *op) · 105 unmodified lines
336342 op->type |= indir;
337343 }
338344
345+static void gen_le16(int v)
346+{
347+ g(v);
348+ g(v >> 8);
349+}
350+
339351 /* XXX: unify with C code output ? */
340352 static void gen_expr32(ExprValue *pe)
341353 {
@@ -344,6 +356,13 @@ static void gen_expr32(ExprValue *pe) · 2 unmodified lines
344356 gen_le32(pe->v);
345357 }
346358
359+static void gen_expr16(ExprValue *pe)
360+{
361+ if (pe->sym)
362+ greloc(cur_text_section, pe->sym, ind, R_386_16);
363+ gen_le16(pe->v);
364+}
365+
347366 /* XXX: unify with C code output ? */
348367 static void gen_disp32(ExprValue *pe)
349368 {
@@ -368,11 +387,27 @@ static void gen_disp32(ExprValue *pe) · 18 unmodified lines
368387 }
369388 }
370389
371−
372−static void gen_le16(int v)
390+static void gen_disp16(ExprValue *pe)
373391 {
374− g(v);
375− g(v >> 8);
392+ Sym *sym;
393+ sym = pe->sym;
394+ if (sym) {
395+ if (sym->r == cur_text_section->sh_num) {
396+ /* same section: we can output an absolute value. Note
397+ that the TCC compiler behaves differently here because
398+ it always outputs a relocation to ease (future) code
399+ elimination in the linker */
400+ gen_le16(pe->v + (long)sym->next - ind - 2);
401+ } else {
402+ greloc(cur_text_section, sym, ind, R_386_PC16);
403+ gen_le16(pe->v - 2);
404+ }
405+ } else {
406+ /* put an empty PC32 relocation */
407+ put_elf_reloc(symtab_section, cur_text_section,
408+ ind, R_386_PC16, 0);
409+ gen_le16(pe->v - 2);
410+ }
376411 }
377412
378413 /* generate the modrm operand */
@@ -384,8 +419,13 @@ static inline void asm_modrm(int reg, Operand *op) · 5 unmodified lines
384419 g(0xc0 + (reg << 3) + op->reg);
385420 } else if (op->reg == -1 && op->reg2 == -1) {
386421 /* displacement only */
387− g(0x05 + (reg << 3));
388− gen_expr32(&op->e);
422+ if (tcc_state->seg_size == 16) {
423+ g(0x06 + (reg << 3));
424+ gen_expr16(&op->e);
425+ } else if (tcc_state->seg_size == 32) {
426+ g(0x05 + (reg << 3));
427+ gen_expr32(&op->e);
428+ }
389429 } else {
390430 sib_reg1 = op->reg;
391431 /* fist compute displacement encoding */
@@ -403,20 +443,59 @@ static inline void asm_modrm(int reg, Operand *op) · 11 unmodified lines
403443 reg1 = op->reg;
404444 if (op->reg2 != -1)
405445 reg1 = 4;
406− g(mod + (reg << 3) + reg1);
407− if (reg1 == 4) {
408− /* add sib byte */
409− reg2 = op->reg2;
410− if (reg2 == -1)
411− reg2 = 4; /* indicate no index */
412− g((op->shift << 6) + (reg2 << 3) + sib_reg1);
446+ if (tcc_state->seg_size == 32) {
447+ g(mod + (reg << 3) + reg1);
448+ if (reg1 == 4) {
449+ /* add sib byte */
450+ reg2 = op->reg2;
451+ if (reg2 == -1)
452+ reg2 = 4; /* indicate no index */
453+ g((op->shift << 6) + (reg2 << 3) + sib_reg1);
454+ }
455+ } else if (tcc_state->seg_size == 16) {
456+ /* edi = 7, esi = 6 --> di = 5, si = 4 */
457+ if ((reg1 == 6) || (reg1 == 7)) {
458+ reg1 -= 2;
459+ /* ebx = 3 --> bx = 7 */
460+ } else if (reg1 == 3) {
461+ reg1 = 7;
462+ /* o32 = 5 --> o16 = 6 */
463+ } else if (reg1 == 5) {
464+ reg1 = 6;
465+ /* sib not valid in 16-bit mode */
466+ } else if (reg1 == 4) {
467+ reg2 = op->reg2;
468+ /* bp + si + offset */
469+ if ((sib_reg1 == 5) && (reg2 == 6)) {
470+ reg1 = 2;
471+ /* bp + di + offset */
472+ } else if ((sib_reg1 == 5) && (reg2 == 7)) {
473+ reg1 = 3;
474+ /* bx + si + offset */
475+ } else if ((sib_reg1 == 3) && (reg2 == 6)) {
476+ reg1 = 0;
477+ /* bx + di + offset */
478+ } else if ((sib_reg1 == 3) && (reg2 == 7)) {
479+ reg1 = 1;
480+ } else {
481+ error("invalid effective address");
482+ }
483+ if (op->e.v == 0)
484+ mod = 0;
485+ } else {
486+ error("invalid register");
487+ }
488+ g(mod + (reg << 3) + reg1);
413489 }
414490
415491 /* add offset */
416492 if (mod == 0x40) {
417493 g(op->e.v);
418494 } else if (mod == 0x80 || op->reg == -1) {
419− gen_expr32(&op->e);
495+ if (tcc_state->seg_size == 16)
496+ gen_expr16(&op->e);
497+ else if (tcc_state->seg_size == 32)
498+ gen_expr32(&op->e);
420499 }
421500 }
422501 }
@@ -428,6 +507,7 @@ static void asm_opcode(TCCState *s1, int opcode) · 5 unmodified lines
428507 int nb_ops, s, ss;
429508 Operand ops[MAX_OPERANDS], *pop;
430509 int op_type[3]; /* decoded op type */
510+ static int a32 = 0, o32 = 0, addr32 = 0, data32 = 0;
431511
432512 /* get operands */
433513 pop = ops;
@@ -442,14 +522,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 8 unmodified lines
442522 parse_operand(s1, pop);
443523 if (tok == ':') {
444524 if (pop->type != OP_SEG || seg_prefix) {
525+ bad_prefix:
445526 error("incorrect prefix");
446527 }
447528 seg_prefix = segment_prefixes[pop->reg];
448529 next();
449530 parse_operand(s1, pop);
531+#if 0
450532 if (!(pop->type & OP_EA)) {
451533 error("segment prefix must be followed by memory reference");
452534 }
535+#endif
453536 }
454537 pop++;
455538 nb_ops++;
@@ -531,6 +614,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 75 unmodified lines
531614 if (opcode >= TOK_ASM_pusha && opcode <= TOK_ASM_emms) {
532615 int b;
533616 b = op0_codes[opcode - TOK_ASM_pusha];
617+ if (opcode == TOK_ASM_o32) {
618+ if (s1->seg_size == 32)
619+ goto bad_prefix;
620+ else
621+ o32 = data32 = 1;
622+ } else if (opcode == TOK_ASM_a32) {
623+ if (s1->seg_size == 32)
624+ goto bad_prefix;
625+ else
626+ a32 = addr32 = 1;
627+ }
534628 if (b & 0xff00)
535629 g(b >> 8);
536630 g(b);
@@ -555,12 +649,37 @@ static void asm_opcode(TCCState *s1, int opcode) · 18 unmodified lines
555649 }
556650 }
557651
558− /* generate data16 prefix if needed */
652+ for(i = 0; i < nb_ops; i++) {
653+ if (ops[i].type & OP_REG32) {
654+ if (s1->seg_size == 16)
655+ o32 = 1;
656+ } else if (!ops[i].type & OP_REG32) {
657+ if (s1->seg_size == 32)
658+ o32 = 1;
659+ }
660+ }
661+
559662 ss = s;
560− if (s == 1 || (pa->instr_type & OPC_D16))
561− g(WORD_PREFIX_OPCODE);
562− else if (s == 2)
663+ if (s == 1 || (pa->instr_type & OPC_D16)) {
664+ if (s1->seg_size == 32)
665+ o32 = 1;
666+ } else if (s == 2) {
667+ if (s1->seg_size == 16) {
668+ if (!(pa->instr_type & OPC_D16))
669+ o32 = 1;
670+ }
563671 s = 1;
672+ }
673+
674+ /* generate a16/a32 prefix if needed */
675+ if ((a32 == 1) && (addr32 == 0))
676+ g(0x67);
677+ /* generate o16/o32 prefix if needed */
678+ if ((o32 == 1) && (data32 == 0))
679+ g(0x66);
680+
681+ addr32 = data32 = 0;
682+
564683 /* now generates the operation */
565684 if (pa->instr_type & OPC_FWAIT)
566685 g(0x9b);
@@ -685,9 +804,17 @@ static void asm_opcode(TCCState *s1, int opcode) · 118 unmodified lines
685804 /* emit constants */
686805 if (pa->opcode == 0x9a || pa->opcode == 0xea) {
687806 /* ljmp or lcall kludge */
688− gen_expr32(&ops[1].e);
689− if (ops[0].e.sym)
807+ if (s1->seg_size == 16) {
808+ if (o32 == 0)
809+ gen_expr16(&ops[1].e);
810+ else if (o32 == 1)
811+ gen_expr32(&ops[1].e);
812+ } else
813+ gen_expr32(&ops[1].e);
814+ if (ops[0].e.sym) {
815+ error_relocate:
690816 error("cannot relocate");
817+ }
691818 gen_le16(ops[0].e.v);
692819 } else {
693820 for(i = 0;i < nb_ops; i++) {
@@ -709,24 +836,48 @@ static void asm_opcode(TCCState *s1, int opcode) · 15 unmodified lines
709836 goto error_relocate;
710837 g(ops[i].e.v);
711838 } else if (v & OP_IM16) {
712− if (ops[i].e.sym) {
713− error_relocate:
714− error("cannot relocate");
839+ if (s1->seg_size == 16)
840+ gen_expr16(&ops[i].e);
841+ else {
842+ if (ops[i].e.sym)
843+ goto error_relocate;
715844 }
716845 gen_le16(ops[i].e.v);
846+ }
717847 } else {
718848 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
719849 if (is_short_jmp)
720850 g(ops[i].e.v);
721− else
722− gen_disp32(&ops[i].e);
851+ else {
852+ if (s1->seg_size == 16)
853+ gen_disp16(&ops[i].e);
854+ else
855+ gen_disp32(&ops[i].e);
856+ }
723857 } else {
724− gen_expr32(&ops[i].e);
858+ if (s1->seg_size == 16) {
859+ if ((o32 == 1) && (v & OP_IM32))
860+ gen_expr32(&ops[i].e);
861+ else
862+ gen_expr16(&ops[i].e);
863+ } else if (s1->seg_size == 32) {
864+ if (o32 == 1)
865+ gen_expr16(&ops[i].e);
866+ else
867+ gen_expr32(&ops[i].e);
868+ }
725869 }
726870 }
871+ } else if (v & (OP_REG16 | OP_REG32)) {
872+ if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
873+ /* jmp $r */
874+ g(0xE0 + ops[i].reg);
875+ }
727876 }
728877 }
729878 }
879+
880+ a32 = o32 = 0;
730881 }
731882
732883 #define NB_SAVED_REGS 3
@@ -1127,8 +1278,11 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands, · 394 unmodified lines
11271278 /* generate reg save code */
11281279 for(i = 0; i < NB_SAVED_REGS; i++) {
11291280 reg = reg_saved[i];
1130− if (regs_allocated[reg])
1281+ if (regs_allocated[reg]) {
1282+ if (tcc_state->seg_size == 16)
1283+ g(0x66);
11311284 g(0x50 + reg);
1285+ }
11321286 }
11331287
11341288 /* generate load code */
@@ -1184,8 +1338,11 @@ static void asm_gen_code(ASMOperand *operands, int nb_operands, · 49 unmodified lines
11841338 /* generate reg restore code */
11851339 for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
11861340 reg = reg_saved[i];
1187− if (regs_allocated[reg])
1341+ if (regs_allocated[reg]) {
1342+ if (tcc_state->seg_size == 16)
1343+ g(0x66);
11881344 g(0x58 + reg);
1345+ }
11891346 }
11901347 }
11911348 }
i386-asm.h+15−6
@@ -74,10 +74,8 @@ ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WL, OPT_REGW, OPT_REGW | OPT_EA · 73 unmodified lines
7474 ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WL, OPT_IM8, OPT_REGW | OPT_EA))
7575
7676 /* prefixes */
77− DEF_ASM_OP0(aword, 0x67)
78− DEF_ASM_OP0(addr16, 0x67)
79− DEF_ASM_OP0(word, 0x66)
80− DEF_ASM_OP0(data16, 0x66)
77+ DEF_ASM_OP0(addr32, 0x67)
78+ DEF_ASM_OP0(data32, 0x66)
8179 DEF_ASM_OP0(lock, 0xf0)
8280 DEF_ASM_OP0(rep, 0xf3)
8381 DEF_ASM_OP0(repe, 0xf3)
@@ -120,9 +118,9 @@ ALT(DEF_ASM_OP2(movzwl, 0x0fb7, 0, OPC_MODRM, OPT_REG16 | OPT_EA, OPT_REG32)) · 36 unmodified lines
120118
121119 ALT(DEF_ASM_OP1(pushw, 0x50, 0, OPC_REG | OPC_WL, OPT_REGW))
122120 ALT(DEF_ASM_OP1(pushw, 0xff, 6, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
123−ALT(DEF_ASM_OP1(pushw, 0x6a, 0, OPC_WL, OPT_IM8S))
124121 ALT(DEF_ASM_OP1(pushw, 0x68, 0, OPC_WL, OPT_IM32))
125122 ALT(DEF_ASM_OP1(pushw, 0x06, 0, OPC_WL, OPT_SEG))
123+ DEF_ASM_OP1(pushb, 0x6a, 0, OPC_B, OPT_IM8S)
126124
127125 ALT(DEF_ASM_OP1(popw, 0x58, 0, OPC_REG | OPC_WL, OPT_REGW))
128126 ALT(DEF_ASM_OP1(popw, 0x8f, 0, OPC_MODRM | OPC_WL, OPT_REGW | OPT_EA))
@@ -201,6 +199,7 @@ ALT(DEF_ASM_OP1(call, 0xff, 2, OPC_MODRM, OPT_INDIR)) · 72 unmodified lines
201199 ALT(DEF_ASM_OP1(call, 0xe8, 0, OPC_JMP, OPT_ADDR))
202200 ALT(DEF_ASM_OP1(jmp, 0xff, 4, OPC_MODRM, OPT_INDIR))
203201 ALT(DEF_ASM_OP1(jmp, 0xeb, 0, OPC_SHORTJMP | OPC_JMP, OPT_ADDR))
202+ALT(DEF_ASM_OP1(jmp, 0xff, 0, OPC_JMP | OPC_WL, OPT_REGW))
204203
205204 ALT(DEF_ASM_OP2(lcall, 0x9a, 0, 0, OPT_IM16, OPT_IM32))
206205 ALT(DEF_ASM_OP1(lcall, 0xff, 3, 0, OPT_EA))
@@ -350,6 +349,9 @@ ALT(DEF_ASM_OP2(lslw, 0x0f03, 0, OPC_MODRM | OPC_WL, OPT_EA | OPT_REG, OPT_REG)) · 143 unmodified lines
350349 DEF_ASM_OP1(verr, 0x0f00, 4, OPC_MODRM, OPT_REG | OPT_EA)
351350 DEF_ASM_OP1(verw, 0x0f00, 5, OPC_MODRM, OPT_REG | OPT_EA)
352351
352+ /* 386 */
353+ DEF_ASM_OP0(loadall386, 0x0f07)
354+
353355 /* 486 */
354356 DEF_ASM_OP1(bswap, 0x0fc8, 0, OPC_REG, OPT_REG32 )
355357 ALT(DEF_ASM_OP2(xaddb, 0x0fc0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT_EA ))
@@ -363,7 +365,14 @@ ALT(DEF_ASM_OP2(cmpxchgb, 0x0fb0, 0, OPC_MODRM | OPC_BWL, OPT_REG, OPT_REG | OPT · 7 unmodified lines
363365 DEF_ASM_OP1(cmpxchg8b, 0x0fc7, 1, OPC_MODRM, OPT_EA )
364366
365367 /* pentium pro */
366− ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
368+ALT(DEF_ASM_OP2(cmovo, 0x0f40, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
369+ALT(DEF_ASM_OP2(cmovno, 0x0f41, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
370+ALT(DEF_ASM_OP2(cmovc, 0x0f42, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
371+ALT(DEF_ASM_OP2(cmovnc, 0x0f43, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
372+ALT(DEF_ASM_OP2(cmovz, 0x0f44, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
373+ALT(DEF_ASM_OP2(cmovnz, 0x0f45, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
374+ALT(DEF_ASM_OP2(cmovna, 0x0f46, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
375+ALT(DEF_ASM_OP2(cmova, 0x0f47, 0, OPC_MODRM | OPC_TEST, OPT_REG32 | OPT_EA, OPT_REG32))
367376
368377 DEF_ASM_OP2(fcmovb, 0xdac0, 0, OPC_REG, OPT_ST, OPT_ST0 )
369378 DEF_ASM_OP2(fcmove, 0xdac8, 0, OPC_REG, OPT_ST, OPT_ST0 )
libtcc.c+3−0
@@ -1937,6 +1937,9 @@ TCCState *tcc_new(void) · 1936 unmodified lines
19371937 #if defined(TCC_TARGET_PE) && 0
19381938 /* XXX: currently the PE linker is not ready to support that */
19391939 s->leading_underscore = 1;
1940+#endif
1941+#ifdef TCC_TARGET_I386
1942+ s->seg_size = 32;
19401943 #endif
19411944 return s;
19421945 }
tcc.h+4−0
@@ -512,6 +512,10 @@ struct TCCState { · 511 unmodified lines
512512 struct InlineFunc **inline_fns;
513513 int nb_inline_fns;
514514
515+#ifdef TCC_TARGET_I386
516+ int seg_size;
517+#endif
518+
515519 #ifndef TCC_TARGET_PE
516520 #ifdef TCC_TARGET_X86_64
517521 /* write PLT and GOT here */
tccasm.c+14−0
@@ -571,6 +571,20 @@ static void asm_parse_directive(TCCState *s1) · 570 unmodified lines
571571 last_text_section = sec;
572572 }
573573 break;
574+#ifdef TCC_TARGET_I386
575+ case TOK_ASM_code16:
576+ {
577+ next();
578+ s1->seg_size = 16;
579+ }
580+ break;
581+ case TOK_ASM_code32:
582+ {
583+ next();
584+ s1->seg_size = 32;
585+ }
586+ break;
587+#endif
574588 default:
575589 error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
576590 break;
tccelf.c+12−0
@@ -591,6 +591,18 @@ static void relocate_section(TCCState *s1, Section *s) · 590 unmodified lines
591591 /* we load the got offset */
592592 *(int *)ptr += s1->got_offsets[sym_index];
593593 break;
594+ case R_386_16:
595+ if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
596+ output_file:
597+ error("can only produce 16-bit binary files");
598+ }
599+ *(short *)ptr += val;
600+ break;
601+ case R_386_PC16:
602+ if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY)
603+ goto output_file;
604+ *(short *)ptr += val - addr;
605+ break;
594606 #elif defined(TCC_TARGET_ARM)
595607 case R_ARM_PC24:
596608 case R_ARM_CALL:
tcctok.h+5−0
@@ -235,6 +235,7 @@ · 234 unmodified lines
235235 /* Tiny Assembler */
236236
237237 DEF_ASM(byte)
238+ DEF_ASM(word)
238239 DEF_ASM(align)
239240 DEF_ASM(skip)
240241 DEF_ASM(space)
@@ -250,6 +251,10 @@ · 9 unmodified lines
250251 DEF_ASM(fill)
251252 DEF_ASM(org)
252253 DEF_ASM(quad)
254+#if defined(TCC_TARGET_I386)
255+ DEF_ASM(code16)
256+ DEF_ASM(code32)
257+#endif
253258
254259 #ifdef TCC_TARGET_I386
255260

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t