| 1 | /* b.out object file format |
| 2 | Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 2000 |
| 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} /* 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; |
| 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, 1); |
| 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 | } |