From f520aaee13ca3e88b0d459748a81323f4533fd36 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Fri, 12 Dec 1997 18:42:40 +0000 Subject: [PATCH] Add support for more ARM processor names. --- gas/ChangeLog | 8 + gas/config/tc-arm.c | 473 +++++++++++++++++++++++++++++++------------- 2 files changed, 344 insertions(+), 137 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index bdaa4cddec3..2508ee18e0e 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,11 @@ +Fri Dec 12 10:35:01 1997 Nick Clifton + + * doc/c-arm.texi (ARM Options): Document support for new ARM + processor names. + + * config/tc-arm.c (md_parse_option): Add support for new ARM + processor names. + Thu Dec 11 17:46:50 1997 Richard Henderson * config/tc-m68k.c (m68k_ip): Don't overwrite opcode table data. diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c index 1a4a3f4601c..9a5a5bfcb5a 100644 --- a/gas/config/tc-arm.c +++ b/gas/config/tc-arm.c @@ -51,8 +51,10 @@ /* The following bitmasks control CPU extensions (ARM7 onwards): */ #define ARM_LONGMUL 0x00000010 /* allow long multiplies */ -#define ARM_ARCH4 0x00000020 -#define ARM_THUMB ARM_ARCH4 +#define ARM_HALFWORD 0x00000020 /* allow half word loads */ +#define ARM_THUMB 0x00000040 /* allow BX instruction */ + +#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD) /* Some useful combinations: */ #define ARM_ANY 0x00ffffff @@ -73,7 +75,7 @@ #ifndef CPU_DEFAULT #if defined __thumb__ -#define CPU_DEFAULT (ARM_7 | ARM_THUMB) +#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB) #else #define CPU_DEFAULT ARM_ALL #endif @@ -88,6 +90,9 @@ static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT; #ifdef OBJ_COFF /* Flags stored in private area of BFD COFF structure */ static boolean uses_apcs_26 = false; +static boolean support_interwork = false; +static boolean uses_apcs_float = false; +static boolean pic_code = false; #endif /* This array holds the chars that always start a comment. If the @@ -419,7 +424,7 @@ static int arm_psr_parse PARAMS ((char **ccp)); static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *)); static int add_to_lit_pool PARAMS ((void)); -static int validate_immediate PARAMS ((int)); +static unsigned validate_immediate PARAMS ((unsigned)); static int validate_offset_imm PARAMS ((int, int)); static void opcode_select PARAMS ((int)); static void end_of_line PARAMS ((char *)); @@ -856,6 +861,8 @@ static void s_ltorg PARAMS ((int)); static void s_arm PARAMS ((int)); static void s_thumb PARAMS ((int)); static void s_code PARAMS ((int)); +static void s_force_thumb PARAMS ((int)); +static void s_thumb_func PARAMS ((int)); static int my_get_expression PARAMS ((expressionS *, char **)); @@ -867,6 +874,8 @@ CONST pseudo_typeS md_pseudo_table[] = {"arm", s_arm, 0}, {"thumb", s_thumb, 0}, {"code", s_code, 0}, + {"force_thumb", s_force_thumb, 0}, + {"thumb_func", s_thumb_func, 0}, {"even", s_even, 0}, {"ltorg", s_ltorg, 0}, {"pool", s_ltorg, 0}, @@ -887,7 +896,8 @@ CONST pseudo_typeS md_pseudo_table[] = */ -symbolS *last_label_seen; +symbolS * last_label_seen; +static int label_is_thumb_function_name = false; /* Literal stuff */ @@ -928,7 +938,7 @@ add_to_lit_pool () { if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE) { - inst.error = "Literal Pool Overflow\n"; + inst.error = "Literal Pool Overflow"; return FAIL; } @@ -1016,35 +1026,21 @@ symbol_make_empty () return symbolP; } -/* Check that an immediate is valid, and if so, convert it to the right format - */ - -/* OH, for a rotate instruction in C! */ +/* Check that an immediate is valid, and if so, convert it to the right format. */ -static int +static unsigned int validate_immediate (val) - int val; + unsigned int val; { - unsigned int a = (unsigned int) val; - int i; - - /* Do the easy (and most common ones) quickly */ - for (i = 0; i <= 24; i += 2) - { - if ((a & (0xff << i)) == a) - return (int) (((32 - i) & 0x1e) << 7) | ((a >> i) & 0xff); - } + unsigned int a; + unsigned int i; - /* Now do the harder ones */ - for (; i < 32; i += 2) - { - if ((a & ((0xff << i) | (0xff >> (32 - i)))) == a) - { - a = ((a >> i) & 0xff) | ((a << (32 - i)) & 0xff); - return (int) a | (((32 - i) >> 1) << 8); - } - } - return FAIL; +#define rotate_left(v, n) (v << n | v >> (32 - n)) + + for (i = 0; i < 32; i += 2) + if ((a = rotate_left (val, i)) <= 0xff) + return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */ + return FAIL; } static int @@ -1117,6 +1113,9 @@ s_ltorg (internal) (valueT) frag_now_fix (), frag_now); symbol_table_insert (current_poolP); + ARM_SET_THUMB (current_poolP, thumb_mode); + ARM_SET_INTERWORK (current_poolP, support_interwork); + while (lit_count < next_literal_pool_place) /* First output the expression in the instruction to the pool */ emit_expr (&(literals[lit_count++].exp), 4); /* .word */ @@ -1175,6 +1174,38 @@ s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */ record_alignment (now_seg, temp); } +static void +s_force_thumb (ignore) + int ignore; +{ + /* If we are not already in thumb mode go into it, EVEN if + the target processor does not support thumb instructions. + This is used by gcc/config/arm/lib1funcs.asm for example + to compile interworking support functions even if the + target processor should not support interworking. */ + + if (! thumb_mode) + { + thumb_mode = 1; + + record_alignment (now_seg, 1); + } + + demand_empty_rest_of_line (); +} + +static void +s_thumb_func (ignore) + int ignore; +{ + /* The following label is the name/address of the start of a Thumb function. + We need to know this for the interworking support. */ + + label_is_thumb_function_name = true; + + demand_empty_rest_of_line(); +} + static void opcode_select (width) int width; @@ -1702,7 +1733,7 @@ do_msr (str, flags) } else { - int value = validate_immediate (inst.reloc.exp.X_add_number); + unsigned value = validate_immediate (inst.reloc.exp.X_add_number); if (value == FAIL) { inst.error = "Invalid constant"; @@ -2579,10 +2610,10 @@ do_ldst (str, flags) { /* This is actually a load/store of a halfword, or a signed-extension load */ - if ((cpu_variant & ARM_ARCH4) == 0) + if ((cpu_variant & ARM_HALFWORD) == 0) { inst.error - = "Processor does not support halfwords or signed bytes\n"; + = "Processor does not support halfwords or signed bytes"; return; } @@ -2730,7 +2761,7 @@ do_ldst (str, flags) if (add_to_lit_pool () == FAIL) { if (!inst.error) - inst.error = "literal pool insertion failed\n"; + inst.error = "literal pool insertion failed"; return; } @@ -3998,8 +4029,8 @@ thumb_mov_compare (str, move) if (Rs < 8 && Rd < 8) { if (move == THUMB_MOVE) - /* A move of two lowregs is, by convention, encoded as - ADD Rd, Rs, #0 */ + /* A move of two lowregs is encoded as ADD Rd, Rs, #0 + since a MOV instruction produces unpredictable results */ inst.instruction = T_OPCODE_ADD_I3; else inst.instruction = T_OPCODE_CMP_LR; @@ -4106,8 +4137,48 @@ thumb_load_store (str, load_store, size) } else if (*str == '=') { - /* TODO: We should allow the "ldr Rd,=expr" pseudo op in thumb mode */ - abort (); + /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */ + str++; + + while (*str == ' ') + str++; + + if (my_get_expression (& inst.reloc.exp, & str)) + return; + + end_of_line (str); + + if ( inst.reloc.exp.X_op != O_constant + && inst.reloc.exp.X_op != O_symbol) + { + inst.error = "Constant expression expected"; + return; + } + + if (inst.reloc.exp.X_op == O_constant + && ((inst.reloc.exp.X_add_number & ~0xFF) == 0)) + { + /* This can be done with a mov instruction */ + + inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8); + inst.instruction |= inst.reloc.exp.X_add_number; + return; + } + + /* Insert into literal pool */ + if (add_to_lit_pool () == FAIL) + { + if (!inst.error) + inst.error = "literal pool insertion failed"; + return; + } + + inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET; + inst.reloc.pc_rel = 1; + inst.instruction = T_OPCODE_LDR_PC | (Rd << 8); + inst.reloc.exp.X_add_number += 4; /* Adjust ARM pipeline offset to Thumb */ + + return; } else { @@ -4566,7 +4637,7 @@ do_t_adr (str) while (*str == ' ') str++; - if (reg_required_here (&str, 4) == FAIL + if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */ || skip_past_comma (&str) == FAIL || my_get_expression (&inst.reloc.exp, &str)) { @@ -4636,7 +4707,7 @@ void md_begin () { int i; - + if ((arm_ops_hsh = hash_new ()) == NULL || (arm_tops_hsh = hash_new ()) == NULL || (arm_cond_hsh = hash_new ()) == NULL @@ -4662,8 +4733,17 @@ md_begin () set_constant_flonums (); #ifdef OBJ_COFF - /* Set the flags in the private structure */ - bfd_set_private_flags (stdoutput, uses_apcs_26 ? F_APCS26 : 0); + { + unsigned int flags = 0; + + /* Set the flags in the private structure */ + if (uses_apcs_26) flags |= F_APCS26; + if (support_interwork) flags |= F_INTERWORK; + if (uses_apcs_float) flags |= F_APCS_FLOAT; + if (pic_code) flags |= F_PIC; + + bfd_set_private_flags (stdoutput, flags); + } #endif { @@ -4695,7 +4775,7 @@ md_begin () { if (cpu_variant & ARM_THUMB) mach = bfd_mach_arm_4T; - else if (cpu_variant & ARM_ARCH4) + else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4) mach = bfd_mach_arm_4; else if (cpu_variant & ARM_LONGMUL) mach = bfd_mach_arm_3M; @@ -4846,6 +4926,14 @@ md_pcrel_from (fixP) && fixP->fx_subsy == NULL) return 0; /* HACK */ + if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD)) + { + /* PC relative addressing on the Thumb is slightly odd + as the bottom two bits of the PC are forced to zero + for the calculation */ + return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3; + } + return fixP->fx_where + fixP->fx_frag->fr_address; } @@ -4969,7 +5057,12 @@ md_apply_fix3 (fixP, val, seg) { if (S_IS_DEFINED (fixP->fx_addsy) && S_GET_SEGMENT (fixP->fx_addsy) != seg) - value += md_pcrel_from (fixP); + { + if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH) + value = 0; + else + value += md_pcrel_from (fixP); + } } fixP->fx_addnumber = value; /* Remember value for emit_reloc */ @@ -5244,7 +5337,9 @@ md_apply_fix3 (fixP, val, seg) break; default: - abort (); + as_bad_where (fixP->fx_file, fixP->fx_line, + "Unable to process relocation for thumb opcode: %x", newval); + break; } md_number_to_chars (buf, newval, THUMB_SIZE); break; @@ -5404,61 +5499,41 @@ tc_gen_reloc (section, fixp) "Literal referenced across section boundry (Implicit dump?)"); return NULL; - case BFD_RELOC_ARM_IMMEDIATE: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (IMMEDIATE)", - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_OFFSET_IMM: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (OFFSET_IMM)", - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_OFFSET_IMM8: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (OFFSET_IMM8)", - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_SHIFT_IMM: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (SHIFT_IMM)", - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_SWI: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (SWI)", - fixp->fx_r_type); - return NULL; - - case BFD_RELOC_ARM_MULTI: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (MULTI)", - fixp->fx_r_type); - return NULL; + default: + { + char * type; + switch (fixp->fx_r_type) + { + case BFD_RELOC_ARM_IMMEDIATE: type = "IMMEDIATE"; break; + case BFD_RELOC_ARM_OFFSET_IMM: type = "OFFSET_IMM"; break; + case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break; + case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break; + case BFD_RELOC_ARM_SWI: type = "SWI"; break; + case BFD_RELOC_ARM_MULTI: type = "MULTI"; break; + case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break; + case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break; + case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break; + case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break; + case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break; + default: type = ""; break; + } + as_bad_where (fixp->fx_file, fixp->fx_line, + "Can not represent %s relocation in this object file format (%d)", + type, fixp->fx_pcrel); + return NULL; + } + } - case BFD_RELOC_ARM_CP_OFF_IMM: - as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (CP_OFF_IMM)", - fixp->fx_r_type); - return NULL; + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - case BFD_RELOC_ARM_THUMB_OFFSET: + if (reloc->howto == NULL) + { as_bad_where (fixp->fx_file, fixp->fx_line, - "Internal_relocation (type %d) not fixed up (THUMB_OFFSET)", - fixp->fx_r_type); + "Can not represent %s relocation in this object file format", + bfd_get_reloc_code_name (code)); return NULL; - - default: - abort (); } - reloc->howto = bfd_reloc_type_lookup (stdoutput, code); - assert (reloc->howto != 0); - return reloc; } @@ -5503,7 +5578,7 @@ output_inst (str) if (inst.error) { - as_bad ("%s -- statement `%s'\n", inst.error, str); + as_bad (inst.error); return; } @@ -5722,40 +5797,56 @@ md_assemble (str) if (*q && !strncmp (q, ".req ", 4)) { - int reg; - if ((reg = arm_reg_parse (&str)) == FAIL) - { - char *r; + int reg; + char * copy_of_str = str; + char * r; - q += 4; - while (*q == ' ') - q++; + q += 4; + while (*q == ' ') + q++; - for (r = q; *r != '\0'; r++) - if (*r == ' ') - break; + for (r = q; *r != '\0'; r++) + if (*r == ' ') + break; + + if (r != q) + { + int regnum; + char d = *r; - if (r != q) - { - int regnum; - char d = *r; + *r = '\0'; + regnum = arm_reg_parse (& q); + *r = d; - *r = '\0'; - regnum = arm_reg_parse (&q); - *r = d; + reg = arm_reg_parse (& str); + + if (reg == FAIL) + { if (regnum != FAIL) { insert_reg_alias (str, regnum); - *p = c; - return; + } + else + { + as_warn ("register '%s' does not exist\n", q); } } + else if (regnum != FAIL) + { + if (reg != regnum) + as_warn ("ignoring redefinition of register alias '%s'", copy_of_str ); + + /* Do not warn abpout redefinitions to the same alias. */ + } + else + as_warn ("ignoring redefinition of register alias '%s' to non-existant register '%s'", + copy_of_str, q); } else - { - *p = c; - return; - } + as_warn ("ignoring incomplete .req pseuso op"); + + *p = c; + return; } *p = c; @@ -5783,6 +5874,9 @@ md_assemble (str) * ARM Procedure Calling Standard: * -mapcs-32 32 bit APCS * -mapcs-26 26 bit APCS + * -mapcs-float Pass floats in float regs + * -mapcs-reentrant Position independent code + * -mthumb-interwork Code supports Arm/Thumb interworking */ CONST char *md_shortopts = "m:"; @@ -5843,6 +5937,13 @@ md_parse_option (c, arg) cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE; thumb_mode = 1; } + else if (! strcmp (str, "thumb-interwork")) + { + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4; +#ifdef OBJ_COFF + support_interwork = true; +#endif + } else goto bad; break; @@ -5854,16 +5955,60 @@ md_parse_option (c, arg) return 1; } #ifdef OBJ_COFF - if (! strcmp (str, "apcs-32")) - { - uses_apcs_26 = false; - return 1; - } - else if (! strcmp (str, "apcs-26")) + if (! strncmp (str, "apcs-", 5)) { - uses_apcs_26 = true; - return 1; - } + /* GCC passes on all command line options starting "-mapcs-..." + to us, so we must parse them here. */ + + str += 5; + + if (! strcmp (str, "32")) + { + uses_apcs_26 = false; + return 1; + } + else if (! strcmp (str, "26")) + { + uses_apcs_26 = true; + return 1; + } + else if (! strcmp (str, "frame")) + { + /* Stack frames are being generated - does not affect + linkage of code. */ + return 1; + } + else if (! strcmp (str, "stack-check")) + { + /* Stack checking is being performed - does not affect + linkage, but does require that the functions + __rt_stkovf_split_small and __rt_stkovf_split_big be + present in the final link. */ + + return 1; + } + else if (! strcmp (str, "float")) + { + /* Floating point arguments are being passed in the floating + point registers. This does affect linking, since this + version of the APCS is incompatible with the version that + passes floating points in the integer registers. */ + + uses_apcs_float = true; + return 1; + } + else if (! strcmp (str, "reentrant")) + { + /* Reentrant code has been generated. This does affect + linking, since there is no point in linking reentrant/ + position independent code with absolute position code. */ + pic_code = true; + return 1; + } + + as_bad ("Unrecognised APCS switch -m%s", arg); + return 0; + } #endif /* Strip off optional "arm" */ if (! strncmp (str, "arm", 3)) @@ -5894,6 +6039,20 @@ md_parse_option (c, arg) goto bad; break; + case 's': + if (streq (str, "strongarm") || streq (str, "strongarm110")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL; + else + goto bad; + break; + + case '8': + if (streq (str, "8")) + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL; + else + goto bad; + break; + case '6': if (! strcmp (str, "6")) cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6; @@ -5906,20 +6065,26 @@ md_parse_option (c, arg) cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; for (; *str; str++) { - switch (*str) + switch (* str) { case 't': - cpu_variant |= ARM_THUMB; + cpu_variant |= (ARM_THUMB | ARM_ARCHv4); break; case 'm': cpu_variant |= ARM_LONGMUL; break; + case 'f': /* fe => fp enabled cpu. */ + if (str[1] == 'e') + ++ str; + else + goto bad; + + case 'c': /* Unknown */ case 'd': /* debug */ case 'i': /* embedded ice */ - /* Included for completeness in ARM processor - naming. */ + /* Included for completeness in ARM processor naming. */ break; default: @@ -5953,7 +6118,7 @@ md_parse_option (c, arg) break; case '4': - cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7; + cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4; switch (*++str) { @@ -5989,9 +6154,10 @@ md_show_usage (fp) FILE *fp; { fprintf (fp, -"-m[arm][1|2|250|3|6|7[t][d][m][i]] select processor variant\n\ +"-m[arm][] select processor variant\n\ -m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\ -mthumb\t\t\tonly allow Thumb instructions\n\ +-mthumb-interwork\tmark the assembled code as supporting interworking\n\ -mall\t\t\tallow any instruction\n\ -mfpa10, -mfpa11\tselect floating point architecture\n\ -mfpe-old\t\tdon't allow floating-point multiple instructions\n\ @@ -5999,6 +6165,10 @@ md_show_usage (fp) #ifdef OBJ_COFF fprintf (fp, "-mapcs-32, -mapcs-26\tspecify which ARM Procedure Calling Standard is in use\n"); + fprintf (fp, +"-mapcs-float\t\tfloating point args are passed in floating point regs\n"); + fprintf (fp, +"-mapcs-reentrant\tposition independent/reentrant code has been generated\n"); #endif #ifdef ARM_BI_ENDIAN fprintf (fp, @@ -6074,7 +6244,20 @@ arm_frob_label (sym) symbolS *sym; { last_label_seen = sym; - ARM_SET_TYPE(sym,thumb_mode); + ARM_SET_THUMB (sym, thumb_mode); + ARM_SET_INTERWORK (sym, support_interwork); + + if (label_is_thumb_function_name) + { + /* When the address of a Thumb function is taken the bottom + bit of that address should be set. This will allow + interworking between Arm and Thumb functions to work + correctly. */ + + THUMB_SET_FUNC (sym, 1); + + label_is_thumb_function_name = false; + } } /* Adjust the symbol table. This marks Thumb symbols as distinct from @@ -6088,9 +6271,20 @@ arm_adjust_symtab () for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym)) { - if (ARM_GET_TYPE(sym)) /* Thumb */ + if (ARM_IS_THUMB (sym)) { - switch (S_GET_STORAGE_CLASS (sym)) + if (THUMB_IS_FUNC (sym)) + { + /* Mark the symbol as a Thumb function. */ + if ( S_GET_STORAGE_CLASS (sym) == C_STAT + || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */ + S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC); + else if (S_GET_STORAGE_CLASS (sym) == C_EXT) + S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC); + else + as_bad ("%s: unexpected function type: %d", S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym)); + } + else switch (S_GET_STORAGE_CLASS (sym)) { case C_EXT: S_SET_STORAGE_CLASS (sym, C_THUMBEXT); @@ -6105,6 +6299,11 @@ arm_adjust_symtab () break; } } + + if (ARM_IS_INTERWORK (sym)) + { + coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF; + } } #endif } -- 2.30.2