| 1 | /* a.out object file format |
| 2 | Copyright (C) 1989-2019 Free Software Foundation, Inc. |
| 3 | |
| 4 | This file is part of GAS, the GNU Assembler. |
| 5 | |
| 6 | GAS is free software; you can redistribute it and/or modify |
| 7 | it under the terms of the GNU General Public License as |
| 8 | published by the Free Software Foundation; either version 3, |
| 9 | or (at your option) any later version. |
| 10 | |
| 11 | GAS is distributed in the hope that it will be useful, but |
| 12 | WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| 14 | the GNU General Public License for more details. |
| 15 | |
| 16 | You should have received a copy of the GNU General Public License |
| 17 | along with GAS; see the file COPYING. If not, write to the Free |
| 18 | Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
| 19 | 02110-1301, USA. */ |
| 20 | |
| 21 | #define OBJ_HEADER "obj-aout.h" |
| 22 | |
| 23 | #include "as.h" |
| 24 | #undef NO_RELOC |
| 25 | #include "aout/aout64.h" |
| 26 | |
| 27 | void |
| 28 | obj_aout_frob_symbol (symbolS *sym, int *punt ATTRIBUTE_UNUSED) |
| 29 | { |
| 30 | flagword flags; |
| 31 | asection *sec; |
| 32 | int type; |
| 33 | |
| 34 | flags = symbol_get_bfdsym (sym)->flags; |
| 35 | type = aout_symbol (symbol_get_bfdsym (sym))->type; |
| 36 | sec = S_GET_SEGMENT (sym); |
| 37 | |
| 38 | /* Only frob simple symbols this way right now. */ |
| 39 | if (! (type & ~ (N_TYPE | N_EXT))) |
| 40 | { |
| 41 | if (type == (N_UNDF | N_EXT) |
| 42 | && sec == bfd_abs_section_ptr) |
| 43 | { |
| 44 | sec = bfd_und_section_ptr; |
| 45 | S_SET_SEGMENT (sym, sec); |
| 46 | } |
| 47 | |
| 48 | if ((type & N_TYPE) != N_INDR |
| 49 | && (type & N_TYPE) != N_SETA |
| 50 | && (type & N_TYPE) != N_SETT |
| 51 | && (type & N_TYPE) != N_SETD |
| 52 | && (type & N_TYPE) != N_SETB |
| 53 | && type != N_WARNING |
| 54 | && (sec == bfd_abs_section_ptr |
| 55 | || sec == bfd_und_section_ptr)) |
| 56 | return; |
| 57 | if (flags & BSF_EXPORT) |
| 58 | type |= N_EXT; |
| 59 | |
| 60 | switch (type & N_TYPE) |
| 61 | { |
| 62 | case N_SETA: |
| 63 | case N_SETT: |
| 64 | case N_SETD: |
| 65 | case N_SETB: |
| 66 | /* Set the debugging flag for constructor symbols so that |
| 67 | BFD leaves them alone. */ |
| 68 | symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; |
| 69 | |
| 70 | /* You can't put a common symbol in a set. The way a set |
| 71 | element works is that the symbol has a definition and a |
| 72 | name, and the linker adds the definition to the set of |
| 73 | that name. That does not work for a common symbol, |
| 74 | because the linker can't tell which common symbol the |
| 75 | user means. FIXME: Using as_bad here may be |
| 76 | inappropriate, since the user may want to force a |
| 77 | particular type without regard to the semantics of sets; |
| 78 | on the other hand, we certainly don't want anybody to be |
| 79 | mislead into thinking that their code will work. */ |
| 80 | if (S_IS_COMMON (sym)) |
| 81 | as_bad (_("Attempt to put a common symbol into set %s"), |
| 82 | S_GET_NAME (sym)); |
| 83 | /* Similarly, you can't put an undefined symbol in a set. */ |
| 84 | else if (! S_IS_DEFINED (sym)) |
| 85 | as_bad (_("Attempt to put an undefined symbol into set %s"), |
| 86 | S_GET_NAME (sym)); |
| 87 | |
| 88 | break; |
| 89 | case N_INDR: |
| 90 | /* Put indirect symbols in the indirect section. */ |
| 91 | S_SET_SEGMENT (sym, bfd_ind_section_ptr); |
| 92 | symbol_get_bfdsym (sym)->flags |= BSF_INDIRECT; |
| 93 | if (type & N_EXT) |
| 94 | { |
| 95 | symbol_get_bfdsym (sym)->flags |= BSF_EXPORT; |
| 96 | symbol_get_bfdsym (sym)->flags &=~ BSF_LOCAL; |
| 97 | } |
| 98 | break; |
| 99 | case N_WARNING: |
| 100 | /* Mark warning symbols. */ |
| 101 | symbol_get_bfdsym (sym)->flags |= BSF_WARNING; |
| 102 | break; |
| 103 | } |
| 104 | } |
| 105 | else |
| 106 | symbol_get_bfdsym (sym)->flags |= BSF_DEBUGGING; |
| 107 | |
| 108 | aout_symbol (symbol_get_bfdsym (sym))->type = type; |
| 109 | |
| 110 | /* Double check weak symbols. */ |
| 111 | if (S_IS_WEAK (sym) && S_IS_COMMON (sym)) |
| 112 | as_bad (_("Symbol `%s' can not be both weak and common"), |
| 113 | S_GET_NAME (sym)); |
| 114 | } |
| 115 | |
| 116 | void |
| 117 | obj_aout_frob_file_before_fix (void) |
| 118 | { |
| 119 | /* Relocation processing may require knowing the VMAs of the sections. |
| 120 | Since writing to a section will cause the BFD back end to compute the |
| 121 | VMAs, fake it out here.... |
| 122 | Writing to the end of the section ensures the file contents |
| 123 | extend to cover the entire aligned size. We possibly won't know |
| 124 | the aligned size until after VMAs and sizes are set on the first |
| 125 | bfd_set_section_contents call, so it might be necessary to repeat. */ |
| 126 | asection *sec = NULL; |
| 127 | if (data_section->size != 0) |
| 128 | sec = data_section; |
| 129 | else if (text_section->size != 0) |
| 130 | sec = text_section; |
| 131 | if (sec) |
| 132 | { |
| 133 | bfd_size_type size; |
| 134 | do |
| 135 | { |
| 136 | bfd_byte b = 0; |
| 137 | size = sec->size; |
| 138 | gas_assert (bfd_set_section_contents (stdoutput, sec, &b, |
| 139 | size - 1, (bfd_size_type) 1)); |
| 140 | } while (size != sec->size); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | static void |
| 145 | obj_aout_line (int ignore ATTRIBUTE_UNUSED) |
| 146 | { |
| 147 | /* Assume delimiter is part of expression. |
| 148 | BSD4.2 as fails with delightful bug, so we |
| 149 | are not being incompatible here. */ |
| 150 | new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); |
| 151 | demand_empty_rest_of_line (); |
| 152 | } |
| 153 | |
| 154 | /* Handle .weak. This is a GNU extension. */ |
| 155 | |
| 156 | static void |
| 157 | obj_aout_weak (int ignore ATTRIBUTE_UNUSED) |
| 158 | { |
| 159 | char *name; |
| 160 | int c; |
| 161 | symbolS *symbolP; |
| 162 | |
| 163 | do |
| 164 | { |
| 165 | c = get_symbol_name (&name); |
| 166 | symbolP = symbol_find_or_make (name); |
| 167 | (void) restore_line_pointer (c); |
| 168 | SKIP_WHITESPACE (); |
| 169 | S_SET_WEAK (symbolP); |
| 170 | if (c == ',') |
| 171 | { |
| 172 | input_line_pointer++; |
| 173 | SKIP_WHITESPACE (); |
| 174 | if (*input_line_pointer == '\n') |
| 175 | c = '\n'; |
| 176 | } |
| 177 | } |
| 178 | while (c == ','); |
| 179 | demand_empty_rest_of_line (); |
| 180 | } |
| 181 | |
| 182 | /* Handle .type. On {Net,Open}BSD, this is used to set the n_other field, |
| 183 | which is then apparently used when doing dynamic linking. Older |
| 184 | versions of gas ignored the .type pseudo-op, so we also ignore it if |
| 185 | we can't parse it. */ |
| 186 | |
| 187 | static void |
| 188 | obj_aout_type (int ignore ATTRIBUTE_UNUSED) |
| 189 | { |
| 190 | char *name; |
| 191 | int c; |
| 192 | symbolS *sym; |
| 193 | |
| 194 | c = get_symbol_name (&name); |
| 195 | sym = symbol_find_or_make (name); |
| 196 | (void) restore_line_pointer (c); |
| 197 | SKIP_WHITESPACE (); |
| 198 | if (*input_line_pointer == ',') |
| 199 | { |
| 200 | ++input_line_pointer; |
| 201 | SKIP_WHITESPACE (); |
| 202 | if (*input_line_pointer == '@') |
| 203 | { |
| 204 | ++input_line_pointer; |
| 205 | if (strncmp (input_line_pointer, "object", 6) == 0) |
| 206 | S_SET_OTHER (sym, 1); |
| 207 | else if (strncmp (input_line_pointer, "function", 8) == 0) |
| 208 | S_SET_OTHER (sym, 2); |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | /* Ignore everything else on the line. */ |
| 213 | s_ignore (0); |
| 214 | } |
| 215 | |
| 216 | /* Support for an AOUT emulation. */ |
| 217 | |
| 218 | static void |
| 219 | aout_pop_insert (void) |
| 220 | { |
| 221 | pop_insert (aout_pseudo_table); |
| 222 | } |
| 223 | |
| 224 | static int |
| 225 | obj_aout_s_get_other (symbolS *sym) |
| 226 | { |
| 227 | return aout_symbol (symbol_get_bfdsym (sym))->other; |
| 228 | } |
| 229 | |
| 230 | static void |
| 231 | obj_aout_s_set_other (symbolS *sym, int o) |
| 232 | { |
| 233 | aout_symbol (symbol_get_bfdsym (sym))->other = o; |
| 234 | } |
| 235 | |
| 236 | static int |
| 237 | obj_aout_sec_sym_ok_for_reloc (asection *sec ATTRIBUTE_UNUSED) |
| 238 | { |
| 239 | return obj_sec_sym_ok_for_reloc (sec); |
| 240 | } |
| 241 | |
| 242 | static void |
| 243 | obj_aout_process_stab (segT seg ATTRIBUTE_UNUSED, |
| 244 | int w, |
| 245 | const char *s, |
| 246 | int t, |
| 247 | int o, |
| 248 | int d) |
| 249 | { |
| 250 | aout_process_stab (w, s, t, o, d); |
| 251 | } |
| 252 | |
| 253 | static int |
| 254 | obj_aout_s_get_desc (symbolS *sym) |
| 255 | { |
| 256 | return aout_symbol (symbol_get_bfdsym (sym))->desc; |
| 257 | } |
| 258 | |
| 259 | static void |
| 260 | obj_aout_s_set_desc (symbolS *sym, int d) |
| 261 | { |
| 262 | aout_symbol (symbol_get_bfdsym (sym))->desc = d; |
| 263 | } |
| 264 | |
| 265 | static int |
| 266 | obj_aout_s_get_type (symbolS *sym) |
| 267 | { |
| 268 | return aout_symbol (symbol_get_bfdsym (sym))->type; |
| 269 | } |
| 270 | |
| 271 | static void |
| 272 | obj_aout_s_set_type (symbolS *sym, int t) |
| 273 | { |
| 274 | aout_symbol (symbol_get_bfdsym (sym))->type = t; |
| 275 | } |
| 276 | |
| 277 | static int |
| 278 | obj_aout_separate_stab_sections (void) |
| 279 | { |
| 280 | return 0; |
| 281 | } |
| 282 | |
| 283 | /* When changed, make sure these table entries match the single-format |
| 284 | definitions in obj-aout.h. */ |
| 285 | |
| 286 | const struct format_ops aout_format_ops = |
| 287 | { |
| 288 | bfd_target_aout_flavour, |
| 289 | 1, /* dfl_leading_underscore. */ |
| 290 | 0, /* emit_section_symbols. */ |
| 291 | 0, /* begin. */ |
| 292 | 0, /* app_file. */ |
| 293 | obj_aout_frob_symbol, |
| 294 | 0, /* frob_file. */ |
| 295 | 0, /* frob_file_before_adjust. */ |
| 296 | obj_aout_frob_file_before_fix, |
| 297 | 0, /* frob_file_after_relocs. */ |
| 298 | 0, /* s_get_size. */ |
| 299 | 0, /* s_set_size. */ |
| 300 | 0, /* s_get_align. */ |
| 301 | 0, /* s_set_align. */ |
| 302 | obj_aout_s_get_other, |
| 303 | obj_aout_s_set_other, |
| 304 | obj_aout_s_get_desc, |
| 305 | obj_aout_s_set_desc, |
| 306 | obj_aout_s_get_type, |
| 307 | obj_aout_s_set_type, |
| 308 | 0, /* copy_symbol_attributes. */ |
| 309 | 0, /* generate_asm_lineno. */ |
| 310 | obj_aout_process_stab, |
| 311 | obj_aout_separate_stab_sections, |
| 312 | 0, /* init_stab_section. */ |
| 313 | obj_aout_sec_sym_ok_for_reloc, |
| 314 | aout_pop_insert, |
| 315 | 0, /* ecoff_set_ext. */ |
| 316 | 0, /* read_begin_hook. */ |
| 317 | 0, /* symbol_new_hook. */ |
| 318 | 0, /* symbol_clone_hook. */ |
| 319 | 0 /* adjust_symtab. */ |
| 320 | }; |
| 321 | |
| 322 | const pseudo_typeS aout_pseudo_table[] = |
| 323 | { |
| 324 | {"line", obj_aout_line, 0}, /* Source code line number. */ |
| 325 | {"ln", obj_aout_line, 0}, /* COFF line number that we use anyway. */ |
| 326 | |
| 327 | {"weak", obj_aout_weak, 0}, /* Mark symbol as weak. */ |
| 328 | |
| 329 | {"type", obj_aout_type, 0}, |
| 330 | |
| 331 | /* coff debug pseudos (ignored) */ |
| 332 | {"def", s_ignore, 0}, |
| 333 | {"dim", s_ignore, 0}, |
| 334 | {"endef", s_ignore, 0}, |
| 335 | {"ident", s_ignore, 0}, |
| 336 | {"line", s_ignore, 0}, |
| 337 | {"ln", s_ignore, 0}, |
| 338 | {"scl", s_ignore, 0}, |
| 339 | {"size", s_ignore, 0}, |
| 340 | {"tag", s_ignore, 0}, |
| 341 | {"val", s_ignore, 0}, |
| 342 | {"version", s_ignore, 0}, |
| 343 | |
| 344 | {"optim", s_ignore, 0}, /* For sun386i cc (?). */ |
| 345 | |
| 346 | /* other stuff */ |
| 347 | {"ABORT", s_abort, 0}, |
| 348 | |
| 349 | {NULL, NULL, 0} |
| 350 | }; |