| 1 | /* b.out object file format | 
|---|
| 2 | Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002 | 
|---|
| 3 | Free Software Foundation, Inc. | 
|---|
| 4 |  | 
|---|
| 5 | This file is part of GAS, the GNU Assembler. | 
|---|
| 6 |  | 
|---|
| 7 | GAS is free software; you can redistribute it and/or modify | 
|---|
| 8 | it under the terms of the GNU General Public License as | 
|---|
| 9 | published by the Free Software Foundation; either version 2, | 
|---|
| 10 | or (at your option) any later version. | 
|---|
| 11 |  | 
|---|
| 12 | GAS is distributed in the hope that it will be useful, but | 
|---|
| 13 | WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See | 
|---|
| 15 | the GNU General Public License for more details. | 
|---|
| 16 |  | 
|---|
| 17 | You should have received a copy of the GNU General Public License | 
|---|
| 18 | along with GAS; see the file COPYING.  If not, write to the Free | 
|---|
| 19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | 
|---|
| 20 | 02111-1307, USA.  */ | 
|---|
| 21 |  | 
|---|
| 22 | #include "as.h" | 
|---|
| 23 | #include "obstack.h" | 
|---|
| 24 |  | 
|---|
| 25 | /* In: segT   Out: N_TYPE bits  */ | 
|---|
| 26 | const short seg_N_TYPE[] = | 
|---|
| 27 | { | 
|---|
| 28 | N_ABS, | 
|---|
| 29 | N_TEXT, | 
|---|
| 30 | N_DATA, | 
|---|
| 31 | N_BSS, | 
|---|
| 32 | N_UNDF,                       /* unknown  */ | 
|---|
| 33 | N_UNDF,                       /* error  */ | 
|---|
| 34 | N_UNDF,                       /* expression  */ | 
|---|
| 35 | N_UNDF,                       /* debug  */ | 
|---|
| 36 | N_UNDF,                       /* ntv  */ | 
|---|
| 37 | N_UNDF,                       /* ptv  */ | 
|---|
| 38 | N_REGISTER,                   /* register  */ | 
|---|
| 39 | }; | 
|---|
| 40 |  | 
|---|
| 41 | const segT N_TYPE_seg[N_TYPE + 2] = | 
|---|
| 42 | {                               /* N_TYPE == 0x1E = 32-2  */ | 
|---|
| 43 | SEG_UNKNOWN,                  /* N_UNDF == 0  */ | 
|---|
| 44 | SEG_GOOF, | 
|---|
| 45 | SEG_ABSOLUTE,                 /* N_ABS == 2  */ | 
|---|
| 46 | SEG_GOOF, | 
|---|
| 47 | SEG_TEXT,                     /* N_TEXT == 4  */ | 
|---|
| 48 | SEG_GOOF, | 
|---|
| 49 | SEG_DATA,                     /* N_DATA == 6  */ | 
|---|
| 50 | SEG_GOOF, | 
|---|
| 51 | SEG_BSS,                      /* N_BSS == 8  */ | 
|---|
| 52 | SEG_GOOF, | 
|---|
| 53 | SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, | 
|---|
| 54 | SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, | 
|---|
| 55 | SEG_GOOF, SEG_GOOF, SEG_GOOF, SEG_GOOF, | 
|---|
| 56 | SEG_REGISTER,                 /* dummy N_REGISTER for regs = 30  */ | 
|---|
| 57 | SEG_GOOF, | 
|---|
| 58 | }; | 
|---|
| 59 |  | 
|---|
| 60 | static void obj_bout_line PARAMS ((int)); | 
|---|
| 61 |  | 
|---|
| 62 | const pseudo_typeS obj_pseudo_table[] = | 
|---|
| 63 | { | 
|---|
| 64 | {"line", obj_bout_line, 0},   /* Source code line number.  */ | 
|---|
| 65 |  | 
|---|
| 66 | /* coff debugging directives.  Currently ignored silently.  */ | 
|---|
| 67 | {"def", s_ignore, 0}, | 
|---|
| 68 | {"dim", s_ignore, 0}, | 
|---|
| 69 | {"endef", s_ignore, 0}, | 
|---|
| 70 | {"ln", s_ignore, 0}, | 
|---|
| 71 | {"scl", s_ignore, 0}, | 
|---|
| 72 | {"size", s_ignore, 0}, | 
|---|
| 73 | {"tag", s_ignore, 0}, | 
|---|
| 74 | {"type", s_ignore, 0}, | 
|---|
| 75 | {"val", s_ignore, 0}, | 
|---|
| 76 |  | 
|---|
| 77 | /* other stuff we don't handle */ | 
|---|
| 78 | {"ABORT", s_ignore, 0}, | 
|---|
| 79 | {"ident", s_ignore, 0}, | 
|---|
| 80 |  | 
|---|
| 81 | {NULL, NULL, 0}               /* End sentinel.  */ | 
|---|
| 82 | }; | 
|---|
| 83 |  | 
|---|
| 84 | /* Relocation.  */ | 
|---|
| 85 |  | 
|---|
| 86 | /* Crawl along a fixS chain. Emit the segment's relocations.  */ | 
|---|
| 87 |  | 
|---|
| 88 | void | 
|---|
| 89 | obj_emit_relocations (where, fixP, segment_address_in_file) | 
|---|
| 90 | char **where; | 
|---|
| 91 | fixS *fixP;                /* Fixup chain for this segment.  */ | 
|---|
| 92 | relax_addressT segment_address_in_file; | 
|---|
| 93 | { | 
|---|
| 94 | for (; fixP; fixP = fixP->fx_next) | 
|---|
| 95 | { | 
|---|
| 96 | if (fixP->fx_done == 0 | 
|---|
| 97 | || fixP->fx_r_type != NO_RELOC) | 
|---|
| 98 | { | 
|---|
| 99 | symbolS *sym; | 
|---|
| 100 |  | 
|---|
| 101 | sym = fixP->fx_addsy; | 
|---|
| 102 | while (sym->sy_value.X_op == O_symbol | 
|---|
| 103 | && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) | 
|---|
| 104 | sym = sym->sy_value.X_add_symbol; | 
|---|
| 105 | fixP->fx_addsy = sym; | 
|---|
| 106 |  | 
|---|
| 107 | tc_bout_fix_to_chars (*where, fixP, segment_address_in_file); | 
|---|
| 108 | *where += sizeof (struct relocation_info); | 
|---|
| 109 | }                       /* if there's a symbol  */ | 
|---|
| 110 | }                           /* for each fixup  */ | 
|---|
| 111 | } | 
|---|
| 112 |  | 
|---|
| 113 | /* Aout file generation & utilities .  */ | 
|---|
| 114 |  | 
|---|
| 115 | /* Convert a lvalue to machine dependent data.  */ | 
|---|
| 116 |  | 
|---|
| 117 | void | 
|---|
| 118 | obj_header_append (where, headers) | 
|---|
| 119 | char **where; | 
|---|
| 120 | object_headers *headers; | 
|---|
| 121 | { | 
|---|
| 122 | /* Always leave in host byte order.  */ | 
|---|
| 123 |  | 
|---|
| 124 | headers->header.a_talign = section_alignment[SEG_TEXT]; | 
|---|
| 125 |  | 
|---|
| 126 | /* Force to at least 2.  */ | 
|---|
| 127 | if (headers->header.a_talign < 2) | 
|---|
| 128 | { | 
|---|
| 129 | headers->header.a_talign = 2; | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | headers->header.a_dalign = section_alignment[SEG_DATA]; | 
|---|
| 133 | headers->header.a_balign = section_alignment[SEG_BSS]; | 
|---|
| 134 |  | 
|---|
| 135 | headers->header.a_tload = 0; | 
|---|
| 136 | headers->header.a_dload = | 
|---|
| 137 | md_section_align (SEG_DATA, H_GET_TEXT_SIZE (headers)); | 
|---|
| 138 |  | 
|---|
| 139 | headers->header.a_relaxable = linkrelax; | 
|---|
| 140 |  | 
|---|
| 141 | #ifdef CROSS_COMPILE | 
|---|
| 142 | md_number_to_chars (*where, headers->header.a_magic, sizeof (headers->header.a_magic)); | 
|---|
| 143 | *where += sizeof (headers->header.a_magic); | 
|---|
| 144 | md_number_to_chars (*where, headers->header.a_text, sizeof (headers->header.a_text)); | 
|---|
| 145 | *where += sizeof (headers->header.a_text); | 
|---|
| 146 | md_number_to_chars (*where, headers->header.a_data, sizeof (headers->header.a_data)); | 
|---|
| 147 | *where += sizeof (headers->header.a_data); | 
|---|
| 148 | md_number_to_chars (*where, headers->header.a_bss, sizeof (headers->header.a_bss)); | 
|---|
| 149 | *where += sizeof (headers->header.a_bss); | 
|---|
| 150 | md_number_to_chars (*where, headers->header.a_syms, sizeof (headers->header.a_syms)); | 
|---|
| 151 | *where += sizeof (headers->header.a_syms); | 
|---|
| 152 | md_number_to_chars (*where, headers->header.a_entry, sizeof (headers->header.a_entry)); | 
|---|
| 153 | *where += sizeof (headers->header.a_entry); | 
|---|
| 154 | md_number_to_chars (*where, headers->header.a_trsize, sizeof (headers->header.a_trsize)); | 
|---|
| 155 | *where += sizeof (headers->header.a_trsize); | 
|---|
| 156 | md_number_to_chars (*where, headers->header.a_drsize, sizeof (headers->header.a_drsize)); | 
|---|
| 157 | *where += sizeof (headers->header.a_drsize); | 
|---|
| 158 | md_number_to_chars (*where, headers->header.a_tload, sizeof (headers->header.a_tload)); | 
|---|
| 159 | *where += sizeof (headers->header.a_tload); | 
|---|
| 160 | md_number_to_chars (*where, headers->header.a_dload, sizeof (headers->header.a_dload)); | 
|---|
| 161 | *where += sizeof (headers->header.a_dload); | 
|---|
| 162 | md_number_to_chars (*where, headers->header.a_talign, sizeof (headers->header.a_talign)); | 
|---|
| 163 | *where += sizeof (headers->header.a_talign); | 
|---|
| 164 | md_number_to_chars (*where, headers->header.a_dalign, sizeof (headers->header.a_dalign)); | 
|---|
| 165 | *where += sizeof (headers->header.a_dalign); | 
|---|
| 166 | md_number_to_chars (*where, headers->header.a_balign, sizeof (headers->header.a_balign)); | 
|---|
| 167 | *where += sizeof (headers->header.a_balign); | 
|---|
| 168 | md_number_to_chars (*where, headers->header.a_relaxable, sizeof (headers->header.a_relaxable)); | 
|---|
| 169 | *where += sizeof (headers->header.a_relaxable); | 
|---|
| 170 | #else /* ! CROSS_COMPILE */ | 
|---|
| 171 | append (where, (char *) &headers->header, sizeof (headers->header)); | 
|---|
| 172 | #endif /* ! CROSS_COMPILE */ | 
|---|
| 173 | } | 
|---|
| 174 |  | 
|---|
| 175 | void | 
|---|
| 176 | obj_symbol_to_chars (where, symbolP) | 
|---|
| 177 | char **where; | 
|---|
| 178 | symbolS *symbolP; | 
|---|
| 179 | { | 
|---|
| 180 | md_number_to_chars ((char *) &(S_GET_OFFSET (symbolP)), | 
|---|
| 181 | S_GET_OFFSET (symbolP), | 
|---|
| 182 | sizeof (S_GET_OFFSET (symbolP))); | 
|---|
| 183 |  | 
|---|
| 184 | md_number_to_chars ((char *) &(S_GET_DESC (symbolP)), | 
|---|
| 185 | S_GET_DESC (symbolP), | 
|---|
| 186 | sizeof (S_GET_DESC (symbolP))); | 
|---|
| 187 |  | 
|---|
| 188 | md_number_to_chars ((char *) &symbolP->sy_symbol.n_value, | 
|---|
| 189 | S_GET_VALUE (symbolP), | 
|---|
| 190 | sizeof (symbolP->sy_symbol.n_value)); | 
|---|
| 191 |  | 
|---|
| 192 | append (where, (char *) &symbolP->sy_symbol, sizeof (obj_symbol_type)); | 
|---|
| 193 | } | 
|---|
| 194 |  | 
|---|
| 195 | void | 
|---|
| 196 | obj_emit_symbols (where, symbol_rootP) | 
|---|
| 197 | char **where; | 
|---|
| 198 | symbolS *symbol_rootP; | 
|---|
| 199 | { | 
|---|
| 200 | symbolS *symbolP; | 
|---|
| 201 |  | 
|---|
| 202 | /* Emit all symbols left in the symbol chain.  */ | 
|---|
| 203 | for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) | 
|---|
| 204 | { | 
|---|
| 205 | /* Used to save the offset of the name.  It is used to point to | 
|---|
| 206 | the string in memory but must be a file offset.  */ | 
|---|
| 207 | char *temp; | 
|---|
| 208 |  | 
|---|
| 209 | temp = S_GET_NAME (symbolP); | 
|---|
| 210 | S_SET_OFFSET (symbolP, symbolP->sy_name_offset); | 
|---|
| 211 |  | 
|---|
| 212 | /* Any symbol still undefined and is not a dbg symbol is made N_EXT.  */ | 
|---|
| 213 | if (!S_IS_DEBUG (symbolP) && !S_IS_DEFINED (symbolP)) | 
|---|
| 214 | S_SET_EXTERNAL (symbolP); | 
|---|
| 215 |  | 
|---|
| 216 | obj_symbol_to_chars (where, symbolP); | 
|---|
| 217 | S_SET_NAME (symbolP, temp); | 
|---|
| 218 | } | 
|---|
| 219 | } | 
|---|
| 220 |  | 
|---|
| 221 | void | 
|---|
| 222 | obj_symbol_new_hook (symbolP) | 
|---|
| 223 | symbolS *symbolP; | 
|---|
| 224 | { | 
|---|
| 225 | S_SET_OTHER (symbolP, 0); | 
|---|
| 226 | S_SET_DESC (symbolP, 0); | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | static void | 
|---|
| 230 | obj_bout_line (ignore) | 
|---|
| 231 | int ignore ATTRIBUTE_UNUSED; | 
|---|
| 232 | { | 
|---|
| 233 | /* Assume delimiter is part of expression.  */ | 
|---|
| 234 | /* BSD4.2 as fails with delightful bug, so we are not being | 
|---|
| 235 | incompatible here.  */ | 
|---|
| 236 | new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); | 
|---|
| 237 | demand_empty_rest_of_line (); | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 | void | 
|---|
| 241 | obj_read_begin_hook () | 
|---|
| 242 | { | 
|---|
| 243 | } | 
|---|
| 244 |  | 
|---|
| 245 | void | 
|---|
| 246 | obj_crawl_symbol_chain (headers) | 
|---|
| 247 | object_headers *headers; | 
|---|
| 248 | { | 
|---|
| 249 | symbolS **symbolPP; | 
|---|
| 250 | symbolS *symbolP; | 
|---|
| 251 | int symbol_number = 0; | 
|---|
| 252 |  | 
|---|
| 253 | tc_crawl_symbol_chain (headers); | 
|---|
| 254 |  | 
|---|
| 255 | symbolPP = &symbol_rootP;     /* -> last symbol chain link.  */ | 
|---|
| 256 | while ((symbolP = *symbolPP) != NULL) | 
|---|
| 257 | { | 
|---|
| 258 | if (flag_readonly_data_in_text && (S_GET_SEGMENT (symbolP) == SEG_DATA)) | 
|---|
| 259 | { | 
|---|
| 260 | S_SET_SEGMENT (symbolP, SEG_TEXT); | 
|---|
| 261 | }                       /* if pusing data into text  */ | 
|---|
| 262 |  | 
|---|
| 263 | resolve_symbol_value (symbolP); | 
|---|
| 264 |  | 
|---|
| 265 | /* Skip symbols which were equated to undefined or common | 
|---|
| 266 | symbols.  */ | 
|---|
| 267 | if (symbolP->sy_value.X_op == O_symbol | 
|---|
| 268 | && (! S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP))) | 
|---|
| 269 | { | 
|---|
| 270 | *symbolPP = symbol_next (symbolP); | 
|---|
| 271 | continue; | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | /* OK, here is how we decide which symbols go out into the | 
|---|
| 275 | brave new symtab.  Symbols that do are: | 
|---|
| 276 |  | 
|---|
| 277 | * symbols with no name (stabd's?) | 
|---|
| 278 | * symbols with debug info in their N_TYPE | 
|---|
| 279 |  | 
|---|
| 280 | Symbols that don't are: | 
|---|
| 281 | * symbols that are registers | 
|---|
| 282 | * symbols with \1 as their 3rd character (numeric labels) | 
|---|
| 283 | * "local labels" as defined by S_LOCAL_NAME(name) | 
|---|
| 284 | if the -L switch was passed to gas. | 
|---|
| 285 |  | 
|---|
| 286 | All other symbols are output.  We complain if a deleted | 
|---|
| 287 | symbol was marked external.  */ | 
|---|
| 288 |  | 
|---|
| 289 | if (1 | 
|---|
| 290 | && !S_IS_REGISTER (symbolP) | 
|---|
| 291 | && (!S_GET_NAME (symbolP) | 
|---|
| 292 | || S_IS_DEBUG (symbolP) | 
|---|
| 293 | #ifdef TC_I960 | 
|---|
| 294 | /* FIXME-SOON this ifdef seems highly dubious to me.  xoxorich.  */ | 
|---|
| 295 | || !S_IS_DEFINED (symbolP) | 
|---|
| 296 | || S_IS_EXTERNAL (symbolP) | 
|---|
| 297 | #endif /* TC_I960 */ | 
|---|
| 298 | || (S_GET_NAME (symbolP)[0] != '\001' | 
|---|
| 299 | && (flag_keep_locals || !S_LOCAL_NAME (symbolP))))) | 
|---|
| 300 | { | 
|---|
| 301 | symbolP->sy_number = symbol_number++; | 
|---|
| 302 |  | 
|---|
| 303 | /* The + 1 after strlen account for the \0 at the end of | 
|---|
| 304 | each string.  */ | 
|---|
| 305 | if (!S_IS_STABD (symbolP)) | 
|---|
| 306 | { | 
|---|
| 307 | /* Ordinary case.  */ | 
|---|
| 308 | symbolP->sy_name_offset = string_byte_count; | 
|---|
| 309 | string_byte_count += strlen (S_GET_NAME (symbolP)) + 1; | 
|---|
| 310 | } | 
|---|
| 311 | else                  /* .Stabd case.  */ | 
|---|
| 312 | symbolP->sy_name_offset = 0; | 
|---|
| 313 | symbolPP = &(symbolP->sy_next); | 
|---|
| 314 | } | 
|---|
| 315 | else | 
|---|
| 316 | { | 
|---|
| 317 | if (S_IS_EXTERNAL (symbolP) || !S_IS_DEFINED (symbolP)) | 
|---|
| 318 | { | 
|---|
| 319 | as_bad (_("Local symbol %s never defined"), | 
|---|
| 320 | S_GET_NAME (symbolP)); | 
|---|
| 321 | }                   /* Oops.  */ | 
|---|
| 322 |  | 
|---|
| 323 | /* Unhook it from the chain.  */ | 
|---|
| 324 | *symbolPP = symbol_next (symbolP); | 
|---|
| 325 | }                       /* if this symbol should be in the output  */ | 
|---|
| 326 | }                           /* for each symbol  */ | 
|---|
| 327 |  | 
|---|
| 328 | H_SET_SYMBOL_TABLE_SIZE (headers, symbol_number); | 
|---|
| 329 | } | 
|---|
| 330 |  | 
|---|
| 331 | /* Find strings by crawling along symbol table chain.  */ | 
|---|
| 332 |  | 
|---|
| 333 | void | 
|---|
| 334 | obj_emit_strings (where) | 
|---|
| 335 | char **where; | 
|---|
| 336 | { | 
|---|
| 337 | symbolS *symbolP; | 
|---|
| 338 |  | 
|---|
| 339 | #ifdef CROSS_COMPILE | 
|---|
| 340 | /* Gotta do md_ byte-ordering stuff for string_byte_count first - KWK */ | 
|---|
| 341 | md_number_to_chars (*where, string_byte_count, sizeof (string_byte_count)); | 
|---|
| 342 | *where += sizeof (string_byte_count); | 
|---|
| 343 | #else /* CROSS_COMPILE */ | 
|---|
| 344 | append (where, (char *) &string_byte_count, | 
|---|
| 345 | (unsigned long) sizeof (string_byte_count)); | 
|---|
| 346 | #endif /* CROSS_COMPILE */ | 
|---|
| 347 |  | 
|---|
| 348 | for (symbolP = symbol_rootP; symbolP; symbolP = symbol_next (symbolP)) | 
|---|
| 349 | { | 
|---|
| 350 | if (S_GET_NAME (symbolP)) | 
|---|
| 351 | append (where, S_GET_NAME (symbolP), | 
|---|
| 352 | (unsigned long) (strlen (S_GET_NAME (symbolP)) + 1)); | 
|---|
| 353 | }                           /* Walk symbol chain.  */ | 
|---|
| 354 | } | 
|---|