📄 tc-ppc.c
字号:
#define REG_NAME_CNT (sizeof (pre_defined_registers) / sizeof (struct pd_reg))/* Given NAME, find the register number associated with that name, return the integer value associated with the given name or -1 on failure. */static int reg_name_search PARAMS ((const struct pd_reg *, int, const char * name));static intreg_name_search (regs, regcount, name) const struct pd_reg *regs; int regcount; const char *name;{ int middle, low, high; int cmp; low = 0; high = regcount - 1; do { middle = (low + high) / 2; cmp = strcasecmp (name, regs[middle].name); if (cmp < 0) high = middle - 1; else if (cmp > 0) low = middle + 1; else return regs[middle].value; } while (low <= high); return -1;}/* * Summary of register_name(). * * in: Input_line_pointer points to 1st char of operand. * * out: A expressionS. * The operand may have been a register: in this case, X_op == O_register, * X_add_number is set to the register number, and truth is returned. * Input_line_pointer->(next non-blank) char after operand, or is in its * original state. */static booleanregister_name (expressionP) expressionS *expressionP;{ int reg_number; char *name; char *start; char c; /* Find the spelling of the operand */ start = name = input_line_pointer; if (name[0] == '%' && isalpha (name[1])) name = ++input_line_pointer; else if (!reg_names_p || !isalpha (name[0])) return false; c = get_symbol_end (); reg_number = reg_name_search (pre_defined_registers, REG_NAME_CNT, name); /* look to see if it's in the register table */ if (reg_number >= 0) { expressionP->X_op = O_register; expressionP->X_add_number = reg_number; /* make the rest nice */ expressionP->X_add_symbol = NULL; expressionP->X_op_symbol = NULL; *input_line_pointer = c; /* put back the delimiting char */ return true; } else { /* reset the line as if we had not done anything */ *input_line_pointer = c; /* put back the delimiting char */ input_line_pointer = start; /* reset input_line pointer */ return false; }}/* This function is called for each symbol seen in an expression. It handles the special parsing which PowerPC assemblers are supposed to use for condition codes. *//* Whether to do the special parsing. */static boolean cr_operand;/* Names to recognize in a condition code. This table is sorted. */static const struct pd_reg cr_names[] ={ { "cr0", 0 }, { "cr1", 1 }, { "cr2", 2 }, { "cr3", 3 }, { "cr4", 4 }, { "cr5", 5 }, { "cr6", 6 }, { "cr7", 7 }, { "eq", 2 }, { "gt", 1 }, { "lt", 0 }, { "so", 3 }, { "un", 3 }};/* Parsing function. This returns non-zero if it recognized an expression. */intppc_parse_name (name, expr) const char *name; expressionS *expr;{ int val; if (! cr_operand) return 0; val = reg_name_search (cr_names, sizeof cr_names / sizeof cr_names[0], name); if (val < 0) return 0; expr->X_op = O_constant; expr->X_add_number = val; return 1;}/* Local variables. *//* The type of processor we are assembling for. This is one or more of the PPC_OPCODE flags defined in opcode/ppc.h. */static int ppc_cpu = 0;/* The size of the processor we are assembling for. This is either PPC_OPCODE_32 or PPC_OPCODE_64. */static unsigned long ppc_size = PPC_OPCODE_32;/* Whether to target xcoff64 */static int ppc_xcoff64 = 0;/* Opcode hash table. */static struct hash_control *ppc_hash;/* Macro hash table. */static struct hash_control *ppc_macro_hash;#ifdef OBJ_ELF/* What type of shared library support to use */static enum { SHLIB_NONE, SHLIB_PIC, SHLIB_MRELOCATABLE } shlib = SHLIB_NONE;/* Flags to set in the elf header */static flagword ppc_flags = 0;/* Whether this is Solaris or not. */#ifdef TARGET_SOLARIS_COMMENT#define SOLARIS_P true#else#define SOLARIS_P false#endifstatic boolean msolaris = SOLARIS_P;#endif#ifdef OBJ_XCOFF/* The RS/6000 assembler uses the .csect pseudo-op to generate code using a bunch of different sections. These assembler sections, however, are all encompassed within the .text or .data sections of the final output file. We handle this by using different subsegments within these main segments. *//* Next subsegment to allocate within the .text segment. */static subsegT ppc_text_subsegment = 2;/* Linked list of csects in the text section. */static symbolS *ppc_text_csects;/* Next subsegment to allocate within the .data segment. */static subsegT ppc_data_subsegment = 2;/* Linked list of csects in the data section. */static symbolS *ppc_data_csects;/* The current csect. */static symbolS *ppc_current_csect;/* The RS/6000 assembler uses a TOC which holds addresses of functions and variables. Symbols are put in the TOC with the .tc pseudo-op. A special relocation is used when accessing TOC entries. We handle the TOC as a subsegment within the .data segment. We set it up if we see a .toc pseudo-op, and save the csect symbol here. */static symbolS *ppc_toc_csect;/* The first frag in the TOC subsegment. */static fragS *ppc_toc_frag;/* The first frag in the first subsegment after the TOC in the .data segment. NULL if there are no subsegments after the TOC. */static fragS *ppc_after_toc_frag;/* The current static block. */static symbolS *ppc_current_block;/* The COFF debugging section; set by md_begin. This is not the .debug section, but is instead the secret BFD section which will cause BFD to set the section number of a symbol to N_DEBUG. */static asection *ppc_coff_debug_section;#endif /* OBJ_XCOFF */#ifdef TE_PE/* Various sections that we need for PE coff support. */static segT ydata_section;static segT pdata_section;static segT reldata_section;static segT rdata_section;static segT tocdata_section;/* The current section and the previous section. See ppc_previous. */static segT ppc_previous_section;static segT ppc_current_section;#endif /* TE_PE */#ifdef OBJ_ELFsymbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE" */#endif /* OBJ_ELF */#ifdef OBJ_ELFCONST char *md_shortopts = "b:l:usm:K:VQ:";#elseCONST char *md_shortopts = "um:";#endifstruct option md_longopts[] = { {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg) int c; char *arg;{ switch (c) { case 'u': /* -u means that any undefined symbols should be treated as external, which is the default for gas anyhow. */ break;#ifdef OBJ_ELF case 'l': /* Solaris as takes -le (presumably for little endian). For completeness sake, recognize -be also. */ if (strcmp (arg, "e") == 0) { target_big_endian = 0; set_target_endian = 1; } else return 0; break; case 'b': if (strcmp (arg, "e") == 0) { target_big_endian = 1; set_target_endian = 1; } else return 0; break; case 'K': /* Recognize -K PIC */ if (strcmp (arg, "PIC") == 0 || strcmp (arg, "pic") == 0) { shlib = SHLIB_PIC; ppc_flags |= EF_PPC_RELOCATABLE_LIB; } else return 0; break;#endif /* a64 and a32 determine whether to use XCOFF64 or XCOFF32. */ case 'a': if (strcmp (arg, "64") == 0) ppc_xcoff64 = 1; else if (strcmp (arg, "32") == 0) ppc_xcoff64 = 0; else return 0; break; case 'm': /* -mpwrx and -mpwr2 mean to assemble for the IBM POWER/2 (RIOS2). */ if (strcmp (arg, "pwrx") == 0 || strcmp (arg, "pwr2") == 0) ppc_cpu = PPC_OPCODE_POWER | PPC_OPCODE_POWER2; /* -mpwr means to assemble for the IBM POWER (RIOS1). */ else if (strcmp (arg, "pwr") == 0) ppc_cpu = PPC_OPCODE_POWER; /* -m601 means to assemble for the Motorola PowerPC 601, which includes instructions that are holdovers from the Power. */ else if (strcmp (arg, "601") == 0) ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_601; /* -mppc, -mppc32, -m603, and -m604 mean to assemble for the Motorola PowerPC 603/604. */ else if (strcmp (arg, "ppc") == 0 || strcmp (arg, "ppc32") == 0 || strcmp (arg, "403") == 0 || strcmp (arg, "405") == 0 || strcmp (arg, "603") == 0 || strcmp (arg, "604") == 0) ppc_cpu = PPC_OPCODE_PPC; else if (strcmp (arg, "7400") == 0) ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC; /* -mppc64 and -m620 mean to assemble for the 64-bit PowerPC 620. */ else if (strcmp (arg, "ppc64") == 0 || strcmp (arg, "620") == 0) { ppc_cpu = PPC_OPCODE_PPC; ppc_size = PPC_OPCODE_64; } else if (strcmp (arg, "ppc64bridge") == 0) { ppc_cpu = PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE; ppc_size = PPC_OPCODE_64; } /* -mcom means assemble for the common intersection between Power and PowerPC. At present, we just allow the union, rather than the intersection. */ else if (strcmp (arg, "com") == 0) ppc_cpu = PPC_OPCODE_COMMON; /* -many means to assemble for any architecture (PWR/PWRX/PPC). */ else if (strcmp (arg, "any") == 0) ppc_cpu = PPC_OPCODE_ANY; else if (strcmp (arg, "regnames") == 0) reg_names_p = true; else if (strcmp (arg, "no-regnames") == 0) reg_names_p = false;#ifdef OBJ_ELF /* -mrelocatable/-mrelocatable-lib -- warn about initializations that require relocation */ else if (strcmp (arg, "relocatable") == 0) { shlib = SHLIB_MRELOCATABLE; ppc_flags |= EF_PPC_RELOCATABLE; } else if (strcmp (arg, "relocatable-lib") == 0) { shlib = SHLIB_MRELOCATABLE; ppc_flags |= EF_PPC_RELOCATABLE_LIB; } /* -memb, set embedded bit */ else if (strcmp (arg, "emb") == 0) ppc_flags |= EF_PPC_EMB; /* -mlittle/-mbig set the endianess */ else if (strcmp (arg, "little") == 0 || strcmp (arg, "little-endian") == 0) { target_big_endian = 0; set_target_endian = 1; } else if (strcmp (arg, "big") == 0 || strcmp (arg, "big-endian") == 0) { target_big_endian = 1; set_target_endian = 1; } else if (strcmp (arg, "solaris") == 0) { msolaris = true; ppc_comment_chars = ppc_solaris_comment_chars; } else if (strcmp (arg, "no-solaris") == 0) { msolaris = false; ppc_comment_chars = ppc_eabi_comment_chars; }#endif else { as_bad (_("invalid switch -m%s"), arg); return 0; } break;#ifdef OBJ_ELF /* -V: SVR4 argument to print version ID. */ case 'V': print_version_id (); break; /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section should be emitted or not. FIXME: Not implemented. */ case 'Q': break; /* Solaris takes -s to specify that .stabs go in a .stabs section, rather than .stabs.excl, which is ignored by the linker. FIXME: Not implemented. */ case 's': if (arg) return 0; break;#endif default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("\PowerPC options:\n\-u ignored\n\-mpwrx, -mpwr2 generate code for IBM POWER/2 (RIOS2)\n\-mpwr generate code for IBM POWER (RIOS1)\n\-m601 generate code for Motorola PowerPC 601\n\-mppc, -mppc32, -m403, -m405, -m603, -m604\n\ generate code for Motorola PowerPC 603/604\n\-mppc64, -m620 generate code for Motorola PowerPC 620\n\-mppc64bridge generate code for PowerPC 64, including bridge insns\n\-mcom generate code Power/PowerPC common instructions\n\-many generate code for any architecture (PWR/PWRX/PPC)\n\-mregnames Allow symbolic names for registers\n\-mno-regnames Do not allow symbolic names for registers\n"));#ifdef OBJ_ELF fprintf (stream, _("\-mrelocatable support for GCC's -mrelocatble option\n\-mrelocatable-lib support for GCC's -mrelocatble-lib option\n\-memb set PPC_EMB bit in ELF flags\n\-mlittle, -mlittle-endian\n\ generate code for a little endian machine\n\-mbig, -mbig-endian generate code for a big endian machine\n\-msolaris generate code for Solaris\n\-mno-solaris do not generate code for Solaris\n\-V print assembler version number\n\-Qy, -Qn ignored\n"));#endif}/* Set ppc_cpu if it is not already set. */static voidppc_set_cpu (){ const char *default_os = TARGET_OS; const char *default_cpu = TARGET_CPU; if (ppc_cpu == 0) { if (strncmp (default_os, "aix", 3) == 0 && default_os[3] >= '4' && default_os[3] <= '9') ppc_cpu = PPC_OPCODE_COMMON; else if (strncmp (default_os, "aix3", 4) == 0) ppc_cpu = PPC_OPCODE_POWER; else if (strcmp (default_cpu, "rs6000") == 0) ppc_cpu = PPC_OPCODE_POWER; else if (strcmp (default_cpu, "powerpc") == 0 || strcmp (default_cpu, "powerpcle") == 0) ppc_cpu = PPC_OPCODE_PPC; else as_fatal (_("Unknown default cpu = %s, os = %s"), default_cpu, default_os); }}/* Figure out the BFD architecture to use. */enum bfd_architectureppc_arch (){ const char *default_cpu = TARGET_CPU; ppc_set_cpu (); if ((ppc_cpu & PPC_OPCODE_PPC) != 0) return bfd_arch_powerpc; else if ((ppc_cpu & PPC_OPCODE_POWER) != 0) return bfd_arch_rs6000; else if ((ppc_cpu & (PPC_OPCODE_COMMON | PPC_OPCODE_ANY)) != 0) { if (strcmp (default_cpu, "rs6000") == 0) return bfd_arch_rs6000; else if (strcmp (default_cpu, "powerpc") == 0 || strcmp (default_cpu, "powerpcle") == 0) return bfd_arch_powerpc; } as_fatal (_("Neither Power nor PowerPC opcodes were selected.")); return bfd_arch_unknown;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -