diff --git a/arm-asm.c b/arm-asm.c index 54c063ae..5f8f703c 100644 --- a/arm-asm.c +++ b/arm-asm.c @@ -971,6 +971,7 @@ static void asm_multiplication_opcode(TCCState *s1, int token) opcode |= 1 << 20; // Status /* fallthrough */ case TOK_ASM_mlaeq: + case_TOK_ASM_mlaeq: if (nb_ops != 4) expect("four operands"); else { @@ -978,6 +979,14 @@ static void asm_multiplication_opcode(TCCState *s1, int token) asm_emit_opcode(token, opcode); } break; + case TOK_ASM_mlseq: + opcode |= 0x00400000; + goto case_TOK_ASM_mlaeq; + case TOK_ASM_udiveq: + opcode |= 0x00200000; + case TOK_ASM_sdiveq: + asm_emit_opcode(token, (opcode & ~0x80) | 0x0710f010); + break; default: expect("known multiplication instruction"); } @@ -1084,6 +1093,7 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) next(); // skip ',' switch (ARM_INSTRUCTION_GROUP(token)) { + case TOK_ASM_strexheq: case TOK_ASM_strexbeq: case TOK_ASM_strexeq: parse_operand(s1, &strex_operand); @@ -1200,6 +1210,8 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) opcode |= asm_encode_shift(&shift); asm_emit_opcode(token, opcode); break; + case TOK_ASM_strexheq: + opcode |= 1 << 21; case TOK_ASM_strexbeq: opcode |= 1 << 22; // B /* fallthrough */ @@ -1217,6 +1229,8 @@ static void asm_single_data_transfer_opcode(TCCState *s1, int token) opcode |= strex_operand.reg; asm_emit_opcode(token, opcode); break; + case TOK_ASM_ldrexheq: + opcode |= 1 << 21; case TOK_ASM_ldrexbeq: opcode |= 1 << 22; // B /* fallthrough */ @@ -2305,11 +2319,16 @@ static void asm_branch_opcode(TCCState *s1, int token) case TOK_ASM_beq: case TOK_ASM_bleq: asm_expr(s1, &e); - esym = elfsym(e.sym); - if (!esym || esym->st_shndx != cur_text_section->sh_num) { - tcc_error("invalid branch target"); + if (e.sym) { + esym = elfsym(e.sym); + if (esym && esym->st_shndx == cur_text_section->sh_num) { + jmp_disp = esym->st_value; + } else { + greloca(cur_text_section, e.sym, ind, R_ARM_PC24, 0); + jmp_disp = ind; + } } - jmp_disp = encbranchoffset(ind, e.v + esym->st_value, 1); + jmp_disp = encbranchoffset(ind, e.v + jmp_disp, 1); break; default: parse_operand(s1, &op); @@ -2409,8 +2428,10 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_strbeq: case TOK_ASM_ldrexeq: case TOK_ASM_ldrexbeq: + case TOK_ASM_ldrexheq: case TOK_ASM_strexeq: case TOK_ASM_strexbeq: + case TOK_ASM_strexheq: asm_single_data_transfer_opcode(s1, token); return; @@ -2473,6 +2494,9 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_mulseq: case TOK_ASM_mlaeq: case TOK_ASM_mlaseq: + case TOK_ASM_mlseq: + case TOK_ASM_udiveq: + case TOK_ASM_sdiveq: asm_multiplication_opcode(s1, token); return; diff --git a/arm-gen.c b/arm-gen.c index c0dd5099..ec4a2e25 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -541,6 +541,15 @@ static int negcc(int cc) Use relative/got addressing to avoid setting DT_TEXTREL */ static void load_value(SValue *sv, int r) { +#if CONFIG_TCC_CPUVER >= 7 + if (!(sv->r & VT_SYM)) { + unsigned x=sv->c.i; + o(0xE3000000|intr(r)<<12|(x&0xFFF)|(x<<4&0xF0000)); /* movw rx,#x(lo) */ + if (x&0xFFFF0000) + o(0xE3400000|intr(r)<<12|(x>>16&0xFFF)|(x>>12&0xF0000)); /* movt rx,#x(hi) */ + return; + } +#endif o(0xE59F0000|(intr(r)<<12)); /* ldr r, [pc] */ o(0xEA000000); /* b $+4 */ #ifndef CONFIG_TCC_PIC diff --git a/arm-tok.h b/arm-tok.h index 297b1055..c15870e2 100644 --- a/arm-tok.h +++ b/arm-tok.h @@ -238,6 +238,9 @@ DEF_ASM_CONDED(smlals) DEF_ASM_CONDED(umlal) DEF_ASM_CONDED(umlals) + DEF_ASM_CONDED(mls) + DEF_ASM_CONDED(udiv) + DEF_ASM_CONDED(sdiv) /* load/store */ @@ -247,8 +250,10 @@ DEF_ASM_CONDED(strb) DEF_ASM_CONDED(ldrex) DEF_ASM_CONDED(ldrexb) + DEF_ASM_CONDED(ldrexh) DEF_ASM_CONDED(strex) DEF_ASM_CONDED(strexb) + DEF_ASM_CONDED(strexh) DEF_ASM_CONDED(ldrh) DEF_ASM_CONDED(ldrsh) DEF_ASM_CONDED(ldrsb) diff --git a/configure b/configure index 8be3d9fd..cc55ab23 100755 --- a/configure +++ b/configure @@ -381,7 +381,7 @@ case $targetos in default sysroot "/usr" fi default prefix "${sysroot}" - confvars_set Android new_dtags rpath=no + confvars_set Android new_dtags rpath=no dwarf=4 test "${cpu}" != "i386" && confvars_set pie default_conf "static=no" case "$cpu" in @@ -510,6 +510,11 @@ if test "$cpu" = "arm"; then confvars_set arm_vfp fi fi + if test -z "$build_cross"; then + if grep -s -q "^Features.* \(idiv\)" /proc/cpuinfo ; then + confvars_set arm_idiv + fi + fi fi # a final configuration tuning @@ -648,6 +653,7 @@ for v in $cpu $confvars ; do print_num TCC_ARM_HARDFLOAT 1 ;; CONFIG_arm_eabi=yes) print_num TCC_ARM_EABI 1 ;; CONFIG_arm_vfp=yes) print_num TCC_ARM_VFP 1 ;; + CONFIG_arm_idiv=yes) print_num __ARM_FEATURE_IDIV 1 ;; # OS CONFIG_WIN32=yes) print_num TCC_TARGET_PE 1 ;; CONFIG_OSX=yes) print_num TCC_TARGET_MACHO 1 ;; diff --git a/lib/Makefile b/lib/Makefile index 6524d829..29b339a2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -33,6 +33,8 @@ ifeq "$($(T)-libtcc1-usegcc)" "yes" BFLAGS = $(if $(CONFIG_dwarf),-gdwarf,-gstabs) endif +XFLAGS += -I$(TOP) + I386_O = libtcc1.o alloca.o alloca-bt.o $(COMMON_O) X86_64_O = libtcc1.o alloca.o alloca-bt.o $(COMMON_O) ARM_O = libtcc1.o armeabi.o alloca.o armflush.o $(COMMON_O) @@ -91,9 +93,7 @@ $(X)%.o : %.S $(TCC) $(TOP)/%.o : %.c $(TCC) $S$(XCC) -c $< -o $@ $(XFLAGS) -$(TOP)/bcheck.o : XFLAGS += $(BFLAGS) -I$(TOP) -# includes tccrun.c, $(TOP) for config.h (tccrun.c prerequisite via $(TCC)) -$(TOP)/bt-exe.o : XFLAGS += -I$(TOP) +$(TOP)/bcheck.o : XFLAGS += $(BFLAGS) $(X)crt1w.o : crt1.c $(X)wincrt1w.o : wincrt1.c diff --git a/lib/armeabi.c b/lib/armeabi.c index 6ade65ef..047a259c 100644 --- a/lib/armeabi.c +++ b/lib/armeabi.c @@ -47,7 +47,7 @@ typedef struct unsigned_int_struct { } unsigned_int_struct; #define REGS_RETURN(name, type) \ - void name ## _return(type ret) {} + static void name ## _return(type ret) {} /* Float helper functions */ @@ -339,7 +339,7 @@ __AEABI_XL2D(ul2d, 0) /* long long to double conversion */ __AEABI_XL2D(l2d, 1) - +#if 1 /* Long long helper functions */ /* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */ @@ -474,6 +474,7 @@ void __aeabi_lasr(unsigned_int_struct val, int shift) /* Integer division functions */ +#if 0 /* very slow */ AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT) int __aeabi_idiv(int numerator, int denominator) @@ -506,6 +507,9 @@ void __aeabi_uidivmod(unsigned num, unsigned den) { uidiv_t_return(aeabi_uidivmod(num, den)); } +#else +# define UIDIVMOD_ASM 1 +#endif /* Some targets do not have all eabi calls (OpenBSD) */ typedef __SIZE_TYPE__ size_t; @@ -542,3 +546,97 @@ __aeabi_memset (void *s, size_t n, int c) { return memset (s, c, n); } + +/* ***************************************************************** */ +#if UIDIVMOD_ASM +#include +__asm__( + "\n .global __aeabi_idiv, __aeabi_idivmod" + "\n .global __aeabi_uidiv, __aeabi_uidivmod" +#if __ARM_FEATURE_IDIV + "\n__aeabi_idiv:" + "\n__aeabi_idivmod:" + "\n mov r2, r0" + "\n sdiv r0, r0, r1" + "\n mls r1, r1, r0, r2" + "\n bx lr" + + "\n__aeabi_uidiv:" + "\n__aeabi_uidivmod:" + "\n mov r2, r0" + "\n udiv r0, r0, r1" + "\n mls r1, r1, r0, r2" + "\n bx lr" +#else +/* Runtime ABI for the ARM Cortex-M0 + * idivmod.S: signed 32 bit division (quotient and remainder) + * + * Copyright (c) 2012 Jörg Mische + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + "\n__aeabi_idiv:" + "\n__aeabi_idivmod:" + "\n cmp r0, #0" + "\n bge .Lnumerator_pos" + "\n rsb r0, r0, #0" // num = -num + "\n cmp r1, #0" + "\n bge .Lboth_neg" + "\n rsb r1, r1, #0" // den = -den + "\n push {lr}" + "\n bl __aeabi_uidivmod" + "\n rsb r1, r1, #0" // rem = -rem + "\n pop {pc}" + "\n.Lboth_neg:" + "\n push {lr}" + "\n bl __aeabi_uidivmod" + "\n rsb r0, r0, #0" // quot = -quot + "\n rsb r1, r1, #0" // rem = -rem + "\n pop {pc}" + "\n.Ldenom_neg:" + "\n rsb r1, r1, #0" // den = -den + "\n push {lr}" + "\n bl __aeabi_uidivmod" + "\n rsb r0, r0, #0" // quot = -quot + "\n pop {pc}" + "\n.Lnumerator_pos:" + "\n cmp r1, #0" + "\n blt .Ldenom_neg" + + // Divide r0 by r1 and return the quotient in r0 and the remainder in r1 + "\n__aeabi_uidiv:" + "\n__aeabi_uidivmod:" + // Shift left the denominator until it is greater than the numerator + "\n mov r2, #1" // counter + "\n mov r3, #0" // result + "\n cmp r0, r1" + "\n bls .Lsub_loop" + "\n adds r1, #0" // dont shift if denominator would overflow + "\n bmi .Lsub_loop" + "\n beq .Luidiv0" + "\n.Ldenom_shift_loop:" + "\n lsl r2, #1" + "\n lsls r1, #1" + "\n bmi .Lsub_loop" + "\n cmp r0, r1" + "\n bhi .Ldenom_shift_loop" + "\n.Lsub_loop:" + "\n cmp r0, r1" // if (num >= den)... + "\n subcs r0, r1" // numerator -= denom + "\n orrcs r3, r2" // result(r3) |= bitmask(r2) + "\n lsr r1, #1" // denom(r1) >>= 1 + "\n lsrs r2, #1" // bitmask(r2) >>= 1 + "\n bne .Lsub_loop" + "\n mov r1, r0" // remainder(r1) = numerator(r0) + "\n mov r0, r3" // quotient(r0) = result(r3) + "\n bx lr" + "\n.Luidiv0:" // XXX: division by zero + "\n mov r0, #0" + "\n bx lr" +#endif +); +#endif /* UIDIVMOD_ASM */ +/* ***************************************************************** */ +#endif diff --git a/tccdbg.c b/tccdbg.c index 345f7aa9..fadd2765 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -1023,6 +1023,11 @@ ST_FUNC void tcc_debug_start(TCCState *s1) SHN_ABS, filename); if (s1->do_debug) { + /* put a "mapping symbol" '$a' for llvm-objdump etc. tools needed + to make them disassemble again when crt1.o had a '$d' before */ + put_elf_sym(symtab_section, text_section->data_offset, 0, + ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE), 0, + text_section->sh_num, "$a"); new_file = last_line_num = 0; debug_next_type = N_DEFAULT_DEBUG; diff --git a/tccelf.c b/tccelf.c index 697d448d..ee3e6360 100644 --- a/tccelf.c +++ b/tccelf.c @@ -2115,15 +2115,6 @@ static int set_sec_sizes(TCCState *s1) || s1->do_debug) { s->sh_size = s->data_offset; } - -#ifdef TCC_TARGET_ARM - /* XXX: Suppress stack unwinding section. */ - if (s->sh_type == SHT_ARM_EXIDX) { - s->sh_flags = 0; - s->sh_size = 0; - } -#endif - } return textrel; } @@ -2762,7 +2753,11 @@ static void create_arm_attribute_section(TCCState *s1) 'a', 'e', 'a', 'b', 'i', 0x00, // "aeabi" 0x01, 0x22, 0x00, 0x00, 0x00, // 'File Attributes', size 0x22 0x05, 0x36, 0x00, // 'CPU_name', "6" +#if CONFIG_TCC_CPUVER >= 7 + 0x06, 0x0a, // 'CPU_arch', 'v7' +#else 0x06, 0x06, // 'CPU_arch', 'v6' +#endif 0x08, 0x01, // 'ARM_ISA_use', 'Yes' 0x09, 0x01, // 'THUMB_ISA_use', 'Thumb-1' 0x0a, 0x02, // 'FP_arch', 'VFPv2' @@ -3184,8 +3179,13 @@ invalid: sh->sh_type != SHT_INIT_ARRAY && sh->sh_type != SHT_FINI_ARRAY #ifdef TCC_ARM_EABI - && sh->sh_type != SHT_ARM_EXIDX + /* Added in commit f99d3de221db23e322c6c18c8249282e27726c25 + but suppressed in 3cfaaaf1eb97d858e583412616f68f75fdad5da5 + So don't load it in order to avoid dangling references from + (STT_SECTION) symbols. */ + // && sh->sh_type != SHT_ARM_EXIDX #endif + #if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD && sh->sh_type != SHT_X86_64_UNWIND #endif diff --git a/tccpp.c b/tccpp.c index 3247dd0a..8d75e972 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2933,6 +2933,13 @@ maybe_newline: break; /* simple tokens */ + case '@': /* only used in assembler */ +#ifdef TCC_TARGET_ARM /* comment on arm asm */ + if (parse_flags & PARSE_FLAG_ASM_FILE) { + p = parse_line_comment(p); + goto redo_no_start; + } +#endif case '(': case ')': case '[': @@ -2944,7 +2951,6 @@ maybe_newline: case ':': case '?': case '~': - case '@': /* only used in assembler */ parse_simple: tok = c; p++;