1d2201f2fSdrahn /* BFD back-end for mmo objects (MMIX-specific object-format).
2d2201f2fSdrahn Copyright 2001, 2002, 2003
3d2201f2fSdrahn Free Software Foundation, Inc.
4d2201f2fSdrahn Written by Hans-Peter Nilsson (hp@bitrange.com).
5d2201f2fSdrahn Infrastructure and other bits originally copied from srec.c and
6d2201f2fSdrahn binary.c.
7d2201f2fSdrahn
8d2201f2fSdrahn This file is part of BFD, the Binary File Descriptor library.
9d2201f2fSdrahn
10d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
11d2201f2fSdrahn it under the terms of the GNU General Public License as published by
12d2201f2fSdrahn the Free Software Foundation; either version 2 of the License, or
13d2201f2fSdrahn (at your option) any later version.
14d2201f2fSdrahn
15d2201f2fSdrahn This program is distributed in the hope that it will be useful,
16d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
17d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18d2201f2fSdrahn GNU General Public License for more details.
19d2201f2fSdrahn
20d2201f2fSdrahn You should have received a copy of the GNU General Public License
21d2201f2fSdrahn along with this program; if not, write to the Free Software
22d2201f2fSdrahn Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23d2201f2fSdrahn
24d2201f2fSdrahn /*
25d2201f2fSdrahn SECTION
26d2201f2fSdrahn mmo backend
27d2201f2fSdrahn
28d2201f2fSdrahn The mmo object format is used exclusively together with Professor
29d2201f2fSdrahn Donald E.@: Knuth's educational 64-bit processor MMIX. The simulator
30d2201f2fSdrahn @command{mmix} which is available at
31d2201f2fSdrahn @url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz}
32d2201f2fSdrahn understands this format. That package also includes a combined
33d2201f2fSdrahn assembler and linker called @command{mmixal}. The mmo format has
34d2201f2fSdrahn no advantages feature-wise compared to e.g. ELF. It is a simple
35d2201f2fSdrahn non-relocatable object format with no support for archives or
36d2201f2fSdrahn debugging information, except for symbol value information and
37d2201f2fSdrahn line numbers (which is not yet implemented in BFD). See
38d2201f2fSdrahn @url{http://www-cs-faculty.stanford.edu/~knuth/mmix.html} for more
39d2201f2fSdrahn information about MMIX. The ELF format is used for intermediate
40d2201f2fSdrahn object files in the BFD implementation.
41d2201f2fSdrahn
42d2201f2fSdrahn @c We want to xref the symbol table node. A feature in "chew"
43d2201f2fSdrahn @c requires that "commands" do not contain spaces in the
44d2201f2fSdrahn @c arguments. Hence the hyphen in "Symbol-table".
45d2201f2fSdrahn @menu
46d2201f2fSdrahn @* File layout::
47d2201f2fSdrahn @* Symbol-table::
48d2201f2fSdrahn @* mmo section mapping::
49d2201f2fSdrahn @end menu
50d2201f2fSdrahn
51d2201f2fSdrahn INODE
52d2201f2fSdrahn File layout, Symbol-table, mmo, mmo
53d2201f2fSdrahn SUBSECTION
54d2201f2fSdrahn File layout
55d2201f2fSdrahn
56d2201f2fSdrahn The mmo file contents is not partitioned into named sections as
57d2201f2fSdrahn with e.g.@: ELF. Memory areas is formed by specifying the
58d2201f2fSdrahn location of the data that follows. Only the memory area
59d2201f2fSdrahn @samp{0x0000@dots{}00} to @samp{0x01ff@dots{}ff} is executable, so
60d2201f2fSdrahn it is used for code (and constants) and the area
61d2201f2fSdrahn @samp{0x2000@dots{}00} to @samp{0x20ff@dots{}ff} is used for
62d2201f2fSdrahn writable data. @xref{mmo section mapping}.
63d2201f2fSdrahn
64d2201f2fSdrahn Contents is entered as 32-bit words, xor:ed over previous
65d2201f2fSdrahn contents, always zero-initialized. A word that starts with the
66d2201f2fSdrahn byte @samp{0x98} forms a command called a @samp{lopcode}, where
67d2201f2fSdrahn the next byte distinguished between the thirteen lopcodes. The
68d2201f2fSdrahn two remaining bytes, called the @samp{Y} and @samp{Z} fields, or
69d2201f2fSdrahn the @samp{YZ} field (a 16-bit big-endian number), are used for
70d2201f2fSdrahn various purposes different for each lopcode. As documented in
71d2201f2fSdrahn @url{http://www-cs-faculty.stanford.edu/~knuth/mmixal-intro.ps.gz},
72d2201f2fSdrahn the lopcodes are:
73d2201f2fSdrahn
74d2201f2fSdrahn There is provision for specifying ``special data'' of 65536
75d2201f2fSdrahn different types. We use type 80 (decimal), arbitrarily chosen the
76d2201f2fSdrahn same as the ELF <<e_machine>> number for MMIX, filling it with
77d2201f2fSdrahn section information normally found in ELF objects. @xref{mmo
78d2201f2fSdrahn section mapping}.
79d2201f2fSdrahn
80d2201f2fSdrahn @table @code
81d2201f2fSdrahn @item lop_quote
82d2201f2fSdrahn 0x98000001. The next word is contents, regardless of whether it
83d2201f2fSdrahn starts with 0x98 or not.
84d2201f2fSdrahn
85d2201f2fSdrahn @item lop_loc
86d2201f2fSdrahn 0x9801YYZZ, where @samp{Z} is 1 or 2. This is a location
87d2201f2fSdrahn directive, setting the location for the next data to the next
88d2201f2fSdrahn 32-bit word (for @math{Z = 1}) or 64-bit word (for @math{Z = 2}),
89d2201f2fSdrahn plus @math{Y * 2^56}. Normally @samp{Y} is 0 for the text segment
90d2201f2fSdrahn and 2 for the data segment.
91d2201f2fSdrahn
92d2201f2fSdrahn @item lop_skip
93d2201f2fSdrahn 0x9802YYZZ. Increase the current location by @samp{YZ} bytes.
94d2201f2fSdrahn
95d2201f2fSdrahn @item lop_fixo
96d2201f2fSdrahn 0x9803YYZZ, where @samp{Z} is 1 or 2. Store the current location
97d2201f2fSdrahn as 64 bits into the location pointed to by the next 32-bit
98d2201f2fSdrahn (@math{Z = 1}) or 64-bit (@math{Z = 2}) word, plus @math{Y *
99d2201f2fSdrahn 2^56}.
100d2201f2fSdrahn
101d2201f2fSdrahn @item lop_fixr
102d2201f2fSdrahn 0x9804YYZZ. @samp{YZ} is stored into the current location plus
103d2201f2fSdrahn @math{2 - 4 * YZ}.
104d2201f2fSdrahn
105d2201f2fSdrahn @item lop_fixrx
106d2201f2fSdrahn 0x980500ZZ. @samp{Z} is 16 or 24. A value @samp{L} derived from
107d2201f2fSdrahn the following 32-bit word are used in a manner similar to
108d2201f2fSdrahn @samp{YZ} in lop_fixr: it is xor:ed into the current location
109d2201f2fSdrahn minus @math{4 * L}. The first byte of the word is 0 or 1. If it
110d2201f2fSdrahn is 1, then @math{L = (@var{lowest 24 bits of word}) - 2^Z}, if 0,
111d2201f2fSdrahn then @math{L = (@var{lowest 24 bits of word})}.
112d2201f2fSdrahn
113d2201f2fSdrahn @item lop_file
114d2201f2fSdrahn 0x9806YYZZ. @samp{Y} is the file number, @samp{Z} is count of
115d2201f2fSdrahn 32-bit words. Set the file number to @samp{Y} and the line
116d2201f2fSdrahn counter to 0. The next @math{Z * 4} bytes contain the file name,
117d2201f2fSdrahn padded with zeros if the count is not a multiple of four. The
118d2201f2fSdrahn same @samp{Y} may occur multiple times, but @samp{Z} must be 0 for
119d2201f2fSdrahn all but the first occurrence.
120d2201f2fSdrahn
121d2201f2fSdrahn @item lop_line
122d2201f2fSdrahn 0x9807YYZZ. @samp{YZ} is the line number. Together with
123d2201f2fSdrahn lop_file, it forms the source location for the next 32-bit word.
124d2201f2fSdrahn Note that for each non-lopcode 32-bit word, line numbers are
125d2201f2fSdrahn assumed incremented by one.
126d2201f2fSdrahn
127d2201f2fSdrahn @item lop_spec
128d2201f2fSdrahn 0x9808YYZZ. @samp{YZ} is the type number. Data until the next
129d2201f2fSdrahn lopcode other than lop_quote forms special data of type @samp{YZ}.
130d2201f2fSdrahn @xref{mmo section mapping}.
131d2201f2fSdrahn
132d2201f2fSdrahn Other types than 80, (or type 80 with a content that does not
133d2201f2fSdrahn parse) is stored in sections named <<.MMIX.spec_data.@var{n}>>
134d2201f2fSdrahn where @var{n} is the @samp{YZ}-type. The flags for such a
135d2201f2fSdrahn sections say not to allocate or load the data. The vma is 0.
136d2201f2fSdrahn Contents of multiple occurrences of special data @var{n} is
137d2201f2fSdrahn concatenated to the data of the previous lop_spec @var{n}s. The
138d2201f2fSdrahn location in data or code at which the lop_spec occurred is lost.
139d2201f2fSdrahn
140d2201f2fSdrahn @item lop_pre
141d2201f2fSdrahn 0x980901ZZ. The first lopcode in a file. The @samp{Z} field forms the
142d2201f2fSdrahn length of header information in 32-bit words, where the first word
143d2201f2fSdrahn tells the time in seconds since @samp{00:00:00 GMT Jan 1 1970}.
144d2201f2fSdrahn
145d2201f2fSdrahn @item lop_post
146d2201f2fSdrahn 0x980a00ZZ. @math{Z > 32}. This lopcode follows after all
147d2201f2fSdrahn content-generating lopcodes in a program. The @samp{Z} field
148d2201f2fSdrahn denotes the value of @samp{rG} at the beginning of the program.
149d2201f2fSdrahn The following @math{256 - Z} big-endian 64-bit words are loaded
150d2201f2fSdrahn into global registers @samp{$G} @dots{} @samp{$255}.
151d2201f2fSdrahn
152d2201f2fSdrahn @item lop_stab
153d2201f2fSdrahn 0x980b0000. The next-to-last lopcode in a program. Must follow
154d2201f2fSdrahn immediately after the lop_post lopcode and its data. After this
155d2201f2fSdrahn lopcode follows all symbols in a compressed format
156d2201f2fSdrahn (@pxref{Symbol-table}).
157d2201f2fSdrahn
158d2201f2fSdrahn @item lop_end
159d2201f2fSdrahn 0x980cYYZZ. The last lopcode in a program. It must follow the
160d2201f2fSdrahn lop_stab lopcode and its data. The @samp{YZ} field contains the
161d2201f2fSdrahn number of 32-bit words of symbol table information after the
162d2201f2fSdrahn preceding lop_stab lopcode.
163d2201f2fSdrahn @end table
164d2201f2fSdrahn
165d2201f2fSdrahn Note that the lopcode "fixups"; <<lop_fixr>>, <<lop_fixrx>> and
166d2201f2fSdrahn <<lop_fixo>> are not generated by BFD, but are handled. They are
167d2201f2fSdrahn generated by <<mmixal>>.
168d2201f2fSdrahn
169d2201f2fSdrahn EXAMPLE
170d2201f2fSdrahn This trivial one-label, one-instruction file:
171d2201f2fSdrahn
172d2201f2fSdrahn | :Main TRAP 1,2,3
173d2201f2fSdrahn
174d2201f2fSdrahn can be represented this way in mmo:
175d2201f2fSdrahn
176d2201f2fSdrahn | 0x98090101 - lop_pre, one 32-bit word with timestamp.
177d2201f2fSdrahn | <timestamp>
178d2201f2fSdrahn | 0x98010002 - lop_loc, text segment, using a 64-bit address.
179d2201f2fSdrahn | Note that mmixal does not emit this for the file above.
180d2201f2fSdrahn | 0x00000000 - Address, high 32 bits.
181d2201f2fSdrahn | 0x00000000 - Address, low 32 bits.
182d2201f2fSdrahn | 0x98060002 - lop_file, 2 32-bit words for file-name.
183d2201f2fSdrahn | 0x74657374 - "test"
184d2201f2fSdrahn | 0x2e730000 - ".s\0\0"
185d2201f2fSdrahn | 0x98070001 - lop_line, line 1.
186d2201f2fSdrahn | 0x00010203 - TRAP 1,2,3
187d2201f2fSdrahn | 0x980a00ff - lop_post, setting $255 to 0.
188d2201f2fSdrahn | 0x00000000
189d2201f2fSdrahn | 0x00000000
190d2201f2fSdrahn | 0x980b0000 - lop_stab for ":Main" = 0, serial 1.
191d2201f2fSdrahn | 0x203a4040 @xref{Symbol-table}.
192d2201f2fSdrahn | 0x10404020
193d2201f2fSdrahn | 0x4d206120
194d2201f2fSdrahn | 0x69016e00
195d2201f2fSdrahn | 0x81000000
196d2201f2fSdrahn | 0x980c0005 - lop_end; symbol table contained five 32-bit words. */
197d2201f2fSdrahn
198d2201f2fSdrahn #include "bfd.h"
199d2201f2fSdrahn #include "sysdep.h"
200d2201f2fSdrahn #include "libbfd.h"
201d2201f2fSdrahn #include "libiberty.h"
202d2201f2fSdrahn #include "elf/mmix.h"
203d2201f2fSdrahn #include "opcode/mmix.h"
204d2201f2fSdrahn
205d2201f2fSdrahn #define LOP 0x98
206d2201f2fSdrahn #define LOP_QUOTE 0
207d2201f2fSdrahn #define LOP_LOC 1
208d2201f2fSdrahn #define LOP_SKIP 2
209d2201f2fSdrahn #define LOP_FIXO 3
210d2201f2fSdrahn #define LOP_FIXR 4
211d2201f2fSdrahn #define LOP_FIXRX 5
212d2201f2fSdrahn #define LOP_FILE 6
213d2201f2fSdrahn #define LOP_LINE 7
214d2201f2fSdrahn #define LOP_SPEC 8
215d2201f2fSdrahn #define LOP_PRE 9
216d2201f2fSdrahn #define LOP_POST 10
217d2201f2fSdrahn #define LOP_STAB 11
218d2201f2fSdrahn #define LOP_END 12
219d2201f2fSdrahn
220d2201f2fSdrahn #define LOP_QUOTE_NEXT ((LOP << 24) | (LOP_QUOTE << 16) | 1)
221d2201f2fSdrahn #define SPEC_DATA_SECTION 80
222d2201f2fSdrahn #define LOP_SPEC_SECTION \
223d2201f2fSdrahn ((LOP << 24) | (LOP_SPEC << 16) | SPEC_DATA_SECTION)
224d2201f2fSdrahn
225d2201f2fSdrahn /* Must be a power of two. If you change this to be >= 64k, you need a
226d2201f2fSdrahn new test-case; the ld test b-loc64k.d touches chunk-size problem areas. */
227d2201f2fSdrahn #define MMO_SEC_CONTENTS_CHUNK_SIZE (1 << 15)
228d2201f2fSdrahn
229d2201f2fSdrahn /* An arbitrary number for the maximum length section name size. */
230d2201f2fSdrahn #define MAX_SECTION_NAME_SIZE (1024 * 1024)
231d2201f2fSdrahn
232d2201f2fSdrahn /* A quite arbitrary number for the maximum length section size. */
233d2201f2fSdrahn #define MAX_ARTIFICIAL_SECTION_SIZE (1024 * 1024 * 1024)
234d2201f2fSdrahn
235d2201f2fSdrahn #define MMO3_WCHAR 0x80
236d2201f2fSdrahn #define MMO3_LEFT 0x40
237d2201f2fSdrahn #define MMO3_MIDDLE 0x20
238d2201f2fSdrahn #define MMO3_RIGHT 0x10
239d2201f2fSdrahn #define MMO3_TYPEBITS 0xf
240d2201f2fSdrahn #define MMO3_REGQUAL_BITS 0xf
241d2201f2fSdrahn #define MMO3_UNDEF 2
242d2201f2fSdrahn #define MMO3_DATA 8
243d2201f2fSdrahn #define MMO3_SYMBITS 0x2f
244d2201f2fSdrahn
245d2201f2fSdrahn /* Put these everywhere in new code. */
246d2201f2fSdrahn #define FATAL_DEBUG \
247d2201f2fSdrahn _bfd_abort (__FILE__, __LINE__, \
248d2201f2fSdrahn "Internal: Non-debugged code (test-case missing)")
249d2201f2fSdrahn
250d2201f2fSdrahn #define BAD_CASE(x) \
251d2201f2fSdrahn _bfd_abort (__FILE__, __LINE__, \
252d2201f2fSdrahn "bad case for " #x)
253d2201f2fSdrahn
254d2201f2fSdrahn enum mmo_sym_type { mmo_reg_sym, mmo_undef_sym, mmo_data_sym, mmo_abs_sym};
255d2201f2fSdrahn
256d2201f2fSdrahn /* When scanning the mmo file, a linked list of mmo_symbol
257d2201f2fSdrahn structures is built to represent the symbol table (if there is
258d2201f2fSdrahn one). */
259d2201f2fSdrahn
260d2201f2fSdrahn struct mmo_symbol
261d2201f2fSdrahn {
262d2201f2fSdrahn struct mmo_symbol *next;
263d2201f2fSdrahn const char *name;
264d2201f2fSdrahn bfd_vma value;
265d2201f2fSdrahn enum mmo_sym_type sym_type;
266d2201f2fSdrahn unsigned int serno;
267d2201f2fSdrahn };
268d2201f2fSdrahn
269d2201f2fSdrahn struct mmo_data_list_struct
270d2201f2fSdrahn {
271d2201f2fSdrahn struct mmo_data_list_struct *next;
272d2201f2fSdrahn bfd_vma where;
273d2201f2fSdrahn bfd_size_type size;
274d2201f2fSdrahn bfd_size_type allocated_size;
275d2201f2fSdrahn bfd_byte data[1];
276d2201f2fSdrahn };
277d2201f2fSdrahn
278d2201f2fSdrahn typedef struct mmo_data_list_struct mmo_data_list_type;
279d2201f2fSdrahn
280d2201f2fSdrahn struct mmo_symbol_trie
281d2201f2fSdrahn {
282d2201f2fSdrahn struct mmo_symbol_trie *left;
283d2201f2fSdrahn struct mmo_symbol_trie *right;
284d2201f2fSdrahn struct mmo_symbol_trie *middle;
285d2201f2fSdrahn
286d2201f2fSdrahn bfd_byte symchar;
287d2201f2fSdrahn
288d2201f2fSdrahn /* A zero name means there's nothing here. */
289d2201f2fSdrahn struct mmo_symbol sym;
290d2201f2fSdrahn };
291d2201f2fSdrahn
292d2201f2fSdrahn /* The mmo tdata information. */
293d2201f2fSdrahn
294d2201f2fSdrahn struct mmo_data_struct
295d2201f2fSdrahn {
296d2201f2fSdrahn struct mmo_symbol *symbols;
297d2201f2fSdrahn struct mmo_symbol *symtail;
298d2201f2fSdrahn asymbol *csymbols;
299d2201f2fSdrahn
300d2201f2fSdrahn /* File representation of time (NULL) when this file was created. */
301d2201f2fSdrahn bfd_byte created[4];
302d2201f2fSdrahn
303d2201f2fSdrahn /* When we're reading bytes recursively, check this occasionally.
304d2201f2fSdrahn Also holds write errors. */
305d2201f2fSdrahn bfd_boolean have_error;
306d2201f2fSdrahn
307d2201f2fSdrahn /* Max symbol length that may appear in the lop_stab table. Note that
308d2201f2fSdrahn this table might just hold a subset of symbols for not-really large
309d2201f2fSdrahn programs, as it can only be 65536 * 4 bytes large. */
310d2201f2fSdrahn int max_symbol_length;
311d2201f2fSdrahn
312d2201f2fSdrahn /* Here's the symbol we build in lop_stab. */
313d2201f2fSdrahn char *lop_stab_symbol;
314d2201f2fSdrahn
315d2201f2fSdrahn /* Index into lop_stab_symbol for the next character when parsing the
316d2201f2fSdrahn symbol information. */
317d2201f2fSdrahn int symbol_position;
318d2201f2fSdrahn
319d2201f2fSdrahn /* When creating arbitrary sections, we need to count section numbers. */
320d2201f2fSdrahn int sec_no;
321d2201f2fSdrahn
322d2201f2fSdrahn /* When writing or reading byte-wise, we need to count the bytes
323d2201f2fSdrahn within a 32-bit word. */
324d2201f2fSdrahn int byte_no;
325d2201f2fSdrahn
326d2201f2fSdrahn /* We also need a buffer to hold the bytes we count reading or writing. */
327d2201f2fSdrahn bfd_byte buf[4];
328d2201f2fSdrahn };
329d2201f2fSdrahn
330d2201f2fSdrahn typedef struct mmo_data_struct tdata_type;
331d2201f2fSdrahn
332d2201f2fSdrahn struct mmo_section_data_struct
333d2201f2fSdrahn {
334d2201f2fSdrahn mmo_data_list_type *head;
335d2201f2fSdrahn mmo_data_list_type *tail;
336d2201f2fSdrahn };
337d2201f2fSdrahn
338d2201f2fSdrahn #define mmo_section_data(sec) \
339d2201f2fSdrahn ((struct mmo_section_data_struct *) (sec)->used_by_bfd)
340d2201f2fSdrahn
341d2201f2fSdrahn /* These structures are used in bfd_map_over_sections constructs. */
342d2201f2fSdrahn
343d2201f2fSdrahn /* Used when writing out sections; all but the register contents section
344d2201f2fSdrahn which is stored in reg_section. */
345d2201f2fSdrahn struct mmo_write_sec_info
346d2201f2fSdrahn {
347d2201f2fSdrahn asection *reg_section;
348d2201f2fSdrahn bfd_boolean retval;
349d2201f2fSdrahn };
350d2201f2fSdrahn
351d2201f2fSdrahn /* Used when trying to find a section corresponding to addr. */
352d2201f2fSdrahn struct mmo_find_sec_info
353d2201f2fSdrahn {
354d2201f2fSdrahn asection *sec;
355d2201f2fSdrahn bfd_vma addr;
356d2201f2fSdrahn };
357d2201f2fSdrahn
358d2201f2fSdrahn static bfd_boolean mmo_bfd_copy_private_bfd_data
359d2201f2fSdrahn PARAMS ((bfd *, bfd *));
360d2201f2fSdrahn static void mmo_write_section_unless_reg_contents
361d2201f2fSdrahn PARAMS ((bfd *, asection *, PTR));
362d2201f2fSdrahn static void mmo_find_sec_w_addr
363d2201f2fSdrahn PARAMS ((bfd *, asection *, PTR));
364d2201f2fSdrahn static void mmo_find_sec_w_addr_grow
365d2201f2fSdrahn PARAMS ((bfd *, asection *, PTR));
366d2201f2fSdrahn static asection *mmo_make_section
367d2201f2fSdrahn PARAMS ((bfd *, const char *));
368d2201f2fSdrahn static void mmo_get_symbol_info
369d2201f2fSdrahn PARAMS ((bfd *, asymbol *, symbol_info *));
370d2201f2fSdrahn static void mmo_print_symbol
371d2201f2fSdrahn PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type));
372d2201f2fSdrahn static void mmo_init
373d2201f2fSdrahn PARAMS ((void));
374d2201f2fSdrahn static bfd_boolean mmo_mkobject
375d2201f2fSdrahn PARAMS ((bfd *));
376d2201f2fSdrahn static bfd_boolean mmo_scan
377d2201f2fSdrahn PARAMS ((bfd *));
378d2201f2fSdrahn static asection *mmo_decide_section
379d2201f2fSdrahn PARAMS ((bfd *, bfd_vma));
380d2201f2fSdrahn static asection *mmo_get_generic_spec_data_section
381d2201f2fSdrahn PARAMS ((bfd *, int));
382d2201f2fSdrahn static asection *mmo_get_spec_section
383d2201f2fSdrahn PARAMS ((bfd *, int));
384d2201f2fSdrahn static INLINE bfd_byte *mmo_get_loc
385d2201f2fSdrahn PARAMS ((asection *, bfd_vma, int));
386d2201f2fSdrahn static void mmo_xore_64
387d2201f2fSdrahn PARAMS ((asection *, bfd_vma vma, bfd_vma value));
388d2201f2fSdrahn static void mmo_xore_32
389d2201f2fSdrahn PARAMS ((asection *, bfd_vma vma, unsigned int));
390d2201f2fSdrahn static void mmo_xore_16
391d2201f2fSdrahn PARAMS ((asection *, bfd_vma vma, unsigned int));
392d2201f2fSdrahn static const bfd_target *mmo_object_p
393d2201f2fSdrahn PARAMS ((bfd *));
394d2201f2fSdrahn static void mmo_map_set_sizes
395d2201f2fSdrahn PARAMS ((bfd *, asection *, PTR));
396d2201f2fSdrahn static bfd_boolean mmo_get_symbols
397d2201f2fSdrahn PARAMS ((bfd *));
398d2201f2fSdrahn static bfd_boolean mmo_create_symbol
399d2201f2fSdrahn PARAMS ((bfd *, const char *, bfd_vma, enum mmo_sym_type, unsigned int));
400d2201f2fSdrahn static bfd_boolean mmo_get_section_contents
401d2201f2fSdrahn PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type));
402d2201f2fSdrahn static long mmo_get_symtab_upper_bound
403d2201f2fSdrahn PARAMS ((bfd *));
404*cf2f2c56Smiod static long mmo_canonicalize_symtab
405d2201f2fSdrahn PARAMS ((bfd *, asymbol **));
406d2201f2fSdrahn static void mmo_get_symbol_info
407d2201f2fSdrahn PARAMS ((bfd *, asymbol *, symbol_info *));
408d2201f2fSdrahn static void mmo_print_symbol
409d2201f2fSdrahn PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type));
410d2201f2fSdrahn static bfd_boolean mmo_set_section_contents
411*cf2f2c56Smiod PARAMS ((bfd *, sec_ptr, const PTR, file_ptr, bfd_size_type));
412d2201f2fSdrahn static int mmo_sizeof_headers
413d2201f2fSdrahn PARAMS ((bfd *, bfd_boolean));
414d2201f2fSdrahn static long mmo_get_reloc_upper_bound
415d2201f2fSdrahn PARAMS ((bfd *, asection *));
416d2201f2fSdrahn
417d2201f2fSdrahn static bfd_boolean mmo_internal_write_header
418d2201f2fSdrahn PARAMS ((bfd *));
419d2201f2fSdrahn static bfd_boolean mmo_internal_write_post
420d2201f2fSdrahn PARAMS ((bfd *, int, asection *));
421d2201f2fSdrahn static bfd_boolean mmo_internal_add_3_sym
422d2201f2fSdrahn PARAMS ((bfd *, struct mmo_symbol_trie *, const struct mmo_symbol *));
423d2201f2fSdrahn static unsigned int mmo_internal_3_length
424d2201f2fSdrahn PARAMS ((bfd *, struct mmo_symbol_trie *));
425d2201f2fSdrahn static void mmo_internal_3_dump
426d2201f2fSdrahn PARAMS ((bfd *, struct mmo_symbol_trie *));
427d2201f2fSdrahn static void mmo_beb128_out
428d2201f2fSdrahn PARAMS ((bfd *, int, int));
429d2201f2fSdrahn static bfd_boolean mmo_internal_write_section
430d2201f2fSdrahn PARAMS ((bfd *, asection *));
431d2201f2fSdrahn static void mmo_write_tetra
432d2201f2fSdrahn PARAMS ((bfd *, unsigned int));
433d2201f2fSdrahn static void mmo_write_tetra_raw
434d2201f2fSdrahn PARAMS ((bfd *, unsigned int));
435d2201f2fSdrahn static void mmo_write_octa
436d2201f2fSdrahn PARAMS ((bfd *, bfd_vma));
437d2201f2fSdrahn static void mmo_write_octa_raw
438d2201f2fSdrahn PARAMS ((bfd *, bfd_vma));
439d2201f2fSdrahn static bfd_boolean mmo_write_chunk
440d2201f2fSdrahn PARAMS ((bfd *, const bfd_byte *, unsigned int));
441d2201f2fSdrahn static bfd_boolean mmo_flush_chunk
442d2201f2fSdrahn PARAMS ((bfd *));
443d2201f2fSdrahn static bfd_boolean mmo_write_loc_chunk
444d2201f2fSdrahn PARAMS ((bfd *, bfd_vma, const bfd_byte *, unsigned int, bfd_vma *));
445d2201f2fSdrahn static bfd_boolean mmo_write_chunk_list
446d2201f2fSdrahn PARAMS ((bfd *, mmo_data_list_type *));
447d2201f2fSdrahn static bfd_boolean mmo_write_loc_chunk_list
448d2201f2fSdrahn PARAMS ((bfd *, mmo_data_list_type *));
449d2201f2fSdrahn static bfd_boolean mmo_write_symbols_and_terminator
450d2201f2fSdrahn PARAMS ((bfd *));
451d2201f2fSdrahn static flagword mmo_sec_flags_from_bfd_flags
452d2201f2fSdrahn PARAMS ((flagword));
453d2201f2fSdrahn static flagword bfd_sec_flags_from_mmo_flags
454d2201f2fSdrahn PARAMS ((flagword));
455d2201f2fSdrahn static bfd_byte mmo_get_byte
456d2201f2fSdrahn PARAMS ((bfd *));
457d2201f2fSdrahn static void mmo_write_byte
458d2201f2fSdrahn PARAMS ((bfd *, bfd_byte));
459d2201f2fSdrahn static bfd_boolean mmo_new_section_hook
460d2201f2fSdrahn PARAMS ((bfd *, asection *));
461d2201f2fSdrahn static int mmo_sort_mmo_symbols
462d2201f2fSdrahn PARAMS ((const PTR, const PTR));
463d2201f2fSdrahn static bfd_boolean mmo_write_object_contents
464d2201f2fSdrahn PARAMS ((bfd *));
465d2201f2fSdrahn static long mmo_canonicalize_reloc
466d2201f2fSdrahn PARAMS ((bfd *, sec_ptr, arelent **, asymbol **));
467d2201f2fSdrahn
468d2201f2fSdrahn /* Global "const" variables initialized once. Must not depend on
469d2201f2fSdrahn particular input or caller; put such things into the bfd or elsewhere.
470d2201f2fSdrahn Look ma, no static per-invocation data! */
471d2201f2fSdrahn
472d2201f2fSdrahn static unsigned
473d2201f2fSdrahn char valid_mmo_symbol_character_set[/* A-Z a-z (we assume consecutive
474d2201f2fSdrahn codes; sorry EBCDIC:ers!). */
475d2201f2fSdrahn + 'Z' - 'A' + 1 + 'z' - 'a' + 1
476d2201f2fSdrahn /* Digits. */
477d2201f2fSdrahn + 10
478d2201f2fSdrahn /* ':' and '_'. */
479d2201f2fSdrahn + 1 + 1
480d2201f2fSdrahn /* Codes higher than 126. */
481d2201f2fSdrahn + 256 - 126
482d2201f2fSdrahn /* Ending zero. */
483d2201f2fSdrahn + 1];
484d2201f2fSdrahn
485d2201f2fSdrahn
486d2201f2fSdrahn /* Get section SECNAME or create one if it doesn't exist. When creating
487d2201f2fSdrahn one, new memory for the name is allocated. */
488d2201f2fSdrahn
489d2201f2fSdrahn static asection *
mmo_make_section(abfd,secname)490d2201f2fSdrahn mmo_make_section (abfd, secname)
491d2201f2fSdrahn bfd *abfd;
492d2201f2fSdrahn const char *secname;
493d2201f2fSdrahn {
494d2201f2fSdrahn asection *sec = bfd_get_section_by_name (abfd, secname);
495d2201f2fSdrahn
496d2201f2fSdrahn if (sec == NULL)
497d2201f2fSdrahn {
498d2201f2fSdrahn char *newsecname = strdup (secname);
499d2201f2fSdrahn
500d2201f2fSdrahn if (newsecname == NULL)
501d2201f2fSdrahn {
502d2201f2fSdrahn (*_bfd_error_handler)
503d2201f2fSdrahn (_("%s: No core to allocate section name %s\n"),
504d2201f2fSdrahn bfd_get_filename (abfd), secname);
505d2201f2fSdrahn bfd_set_error (bfd_error_system_call);
506d2201f2fSdrahn return NULL;
507d2201f2fSdrahn }
508d2201f2fSdrahn sec = bfd_make_section (abfd, newsecname);
509d2201f2fSdrahn }
510d2201f2fSdrahn
511d2201f2fSdrahn return sec;
512d2201f2fSdrahn }
513d2201f2fSdrahn
514d2201f2fSdrahn /* Nothing to do, but keep as a placeholder if we need it.
515d2201f2fSdrahn Note that state that might differ between bfd:s must not be initialized
516d2201f2fSdrahn here, nor must it be static. Add it to tdata information instead. */
517d2201f2fSdrahn
518d2201f2fSdrahn static void
mmo_init()519d2201f2fSdrahn mmo_init ()
520d2201f2fSdrahn {
521d2201f2fSdrahn static bfd_boolean inited = FALSE;
522d2201f2fSdrahn int i = 0;
523d2201f2fSdrahn int j = 0;
524d2201f2fSdrahn static const char letters[]
525d2201f2fSdrahn = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:_";
526d2201f2fSdrahn
527d2201f2fSdrahn if (inited)
528d2201f2fSdrahn return;
529d2201f2fSdrahn inited = TRUE;
530d2201f2fSdrahn
531d2201f2fSdrahn /* Fill in the set of valid symbol characters. */
532d2201f2fSdrahn strcpy (valid_mmo_symbol_character_set, letters);
533d2201f2fSdrahn i = strlen (letters);
534d2201f2fSdrahn
535d2201f2fSdrahn for (j = 126; j < 256; j++)
536d2201f2fSdrahn valid_mmo_symbol_character_set[i++] = j;
537d2201f2fSdrahn }
538d2201f2fSdrahn
539d2201f2fSdrahn /* Check whether an existing file is an mmo file. */
540d2201f2fSdrahn
541d2201f2fSdrahn static const bfd_target *
mmo_object_p(abfd)542d2201f2fSdrahn mmo_object_p (abfd)
543d2201f2fSdrahn bfd *abfd;
544d2201f2fSdrahn {
545d2201f2fSdrahn struct stat statbuf;
546d2201f2fSdrahn bfd_byte b[4];
547d2201f2fSdrahn
548d2201f2fSdrahn mmo_init ();
549d2201f2fSdrahn
550d2201f2fSdrahn if (bfd_stat (abfd, &statbuf) < 0
551d2201f2fSdrahn || bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
552d2201f2fSdrahn || bfd_bread (b, 4, abfd) != 4)
553d2201f2fSdrahn goto bad_final;
554d2201f2fSdrahn
555d2201f2fSdrahn /* All mmo files are a multiple of four bytes long.
556d2201f2fSdrahn Only recognize version one. */
557d2201f2fSdrahn if ((statbuf.st_size % 4) != 0
558d2201f2fSdrahn || b[0] != LOP || b[1] != LOP_PRE || b[2] != 1)
559d2201f2fSdrahn goto bad_format;
560d2201f2fSdrahn
561d2201f2fSdrahn /* Get the last 32-bit word. */
562d2201f2fSdrahn if (bfd_seek (abfd, (file_ptr) statbuf.st_size - 4, SEEK_SET) != 0
563d2201f2fSdrahn || bfd_bread (b, 4, abfd) != 4)
564d2201f2fSdrahn goto bad_final;
565d2201f2fSdrahn
566d2201f2fSdrahn /* Check if the file ends in a lop_end lopcode. */
567d2201f2fSdrahn if (b[0] != LOP || b[1] != LOP_END || ! mmo_mkobject (abfd))
568d2201f2fSdrahn goto bad_format;
569d2201f2fSdrahn
570d2201f2fSdrahn /* Compute an upper bound on the max symbol length. Not really
571d2201f2fSdrahn important as all of the symbol information can only be 256k. */
572d2201f2fSdrahn abfd->tdata.mmo_data->max_symbol_length = (b[2] * 256 + b[3]) * 4;
573d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol
574d2201f2fSdrahn = bfd_malloc (abfd->tdata.mmo_data->max_symbol_length + 1);
575d2201f2fSdrahn
576d2201f2fSdrahn if (abfd->tdata.mmo_data->lop_stab_symbol == NULL)
577d2201f2fSdrahn {
578d2201f2fSdrahn (*_bfd_error_handler)
579d2201f2fSdrahn (_("%s: No core to allocate a symbol %d bytes long\n"),
580d2201f2fSdrahn bfd_get_filename (abfd), abfd->tdata.mmo_data->max_symbol_length);
581d2201f2fSdrahn goto bad_final;
582d2201f2fSdrahn }
583d2201f2fSdrahn
584d2201f2fSdrahn /* Read in everything. */
585d2201f2fSdrahn if (! mmo_scan (abfd))
586d2201f2fSdrahn goto bad_format_free;
587d2201f2fSdrahn
588d2201f2fSdrahn if (abfd->symcount > 0)
589d2201f2fSdrahn abfd->flags |= HAS_SYMS;
590d2201f2fSdrahn
591d2201f2fSdrahn /* You'll have to tweak this if you want to use this format for other
592d2201f2fSdrahn arches (not recommended due to its small-size limitations). Look at
593d2201f2fSdrahn the ELF format for how to make it target-generic. */
594d2201f2fSdrahn if (! bfd_default_set_arch_mach (abfd, bfd_arch_mmix, 0))
595d2201f2fSdrahn goto bad_format_free;
596d2201f2fSdrahn
597d2201f2fSdrahn return abfd->xvec;
598d2201f2fSdrahn
599d2201f2fSdrahn bad_format_free:
600d2201f2fSdrahn free (abfd->tdata.mmo_data->lop_stab_symbol);
601d2201f2fSdrahn bad_format:
602d2201f2fSdrahn bfd_set_error (bfd_error_wrong_format);
603d2201f2fSdrahn bad_final:
604d2201f2fSdrahn return NULL;
605d2201f2fSdrahn }
606d2201f2fSdrahn
607d2201f2fSdrahn /* Set up the mmo tdata information. */
608d2201f2fSdrahn
609d2201f2fSdrahn static bfd_boolean
mmo_mkobject(abfd)610d2201f2fSdrahn mmo_mkobject (abfd)
611d2201f2fSdrahn bfd *abfd;
612d2201f2fSdrahn {
613d2201f2fSdrahn mmo_init ();
614d2201f2fSdrahn
615d2201f2fSdrahn if (abfd->tdata.mmo_data == NULL)
616d2201f2fSdrahn {
617d2201f2fSdrahn time_t created;
618d2201f2fSdrahn
619d2201f2fSdrahn /* All fields are zero-initialized, so we don't have to explicitly
620d2201f2fSdrahn initialize most. */
621d2201f2fSdrahn tdata_type *tdata = (tdata_type *) bfd_zmalloc (sizeof (tdata_type));
622d2201f2fSdrahn if (tdata == NULL)
623d2201f2fSdrahn return FALSE;
624d2201f2fSdrahn
625d2201f2fSdrahn created = time (NULL);
626d2201f2fSdrahn bfd_put_32 (abfd, created, tdata->created);
627d2201f2fSdrahn
628d2201f2fSdrahn abfd->tdata.mmo_data = tdata;
629d2201f2fSdrahn }
630d2201f2fSdrahn
631d2201f2fSdrahn return TRUE;
632d2201f2fSdrahn }
633d2201f2fSdrahn
634d2201f2fSdrahn static bfd_boolean
mmo_bfd_copy_private_bfd_data(ibfd,obfd)635d2201f2fSdrahn mmo_bfd_copy_private_bfd_data (ibfd, obfd)
636d2201f2fSdrahn bfd *ibfd;
637d2201f2fSdrahn bfd *obfd;
638d2201f2fSdrahn {
639d2201f2fSdrahn if (bfd_get_flavour (ibfd) != bfd_target_mmo_flavour
640d2201f2fSdrahn || bfd_get_flavour (obfd) != bfd_target_mmo_flavour)
641d2201f2fSdrahn return TRUE;
642d2201f2fSdrahn
643d2201f2fSdrahn /* Copy the time the copied-from file was created. If people want the
644d2201f2fSdrahn time the file was last *modified*, they have that in the normal file
645d2201f2fSdrahn information. */
646d2201f2fSdrahn memcpy (obfd->tdata.mmo_data->created, ibfd->tdata.mmo_data->created,
647d2201f2fSdrahn sizeof (obfd->tdata.mmo_data->created));
648d2201f2fSdrahn return TRUE;
649d2201f2fSdrahn }
650d2201f2fSdrahn
651d2201f2fSdrahn /* Helper functions for mmo_decide_section, used through
652d2201f2fSdrahn bfd_map_over_sections. */
653d2201f2fSdrahn
654d2201f2fSdrahn static void
mmo_find_sec_w_addr(abfd,sec,p)655d2201f2fSdrahn mmo_find_sec_w_addr (abfd, sec, p)
656d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
657d2201f2fSdrahn asection *sec;
658d2201f2fSdrahn PTR p;
659d2201f2fSdrahn {
660d2201f2fSdrahn struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
661d2201f2fSdrahn bfd_vma vma = bfd_get_section_vma (abfd, sec);
662d2201f2fSdrahn
663d2201f2fSdrahn /* Ignore sections that aren't loaded. */
664d2201f2fSdrahn if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
665d2201f2fSdrahn != (SEC_LOAD | SEC_ALLOC))
666d2201f2fSdrahn return;
667d2201f2fSdrahn
668d2201f2fSdrahn if (infop->addr >= vma && infop->addr < vma + sec->_raw_size)
669d2201f2fSdrahn infop->sec = sec;
670d2201f2fSdrahn }
671d2201f2fSdrahn
672d2201f2fSdrahn static void
mmo_find_sec_w_addr_grow(abfd,sec,p)673d2201f2fSdrahn mmo_find_sec_w_addr_grow (abfd, sec, p)
674d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
675d2201f2fSdrahn asection *sec;
676d2201f2fSdrahn PTR p;
677d2201f2fSdrahn {
678d2201f2fSdrahn struct mmo_find_sec_info *infop = (struct mmo_find_sec_info *) p;
679d2201f2fSdrahn bfd_vma vma = bfd_get_section_vma (abfd, sec);
680d2201f2fSdrahn
681d2201f2fSdrahn /* Ignore sections that aren't loaded. */
682d2201f2fSdrahn if ((bfd_get_section_flags (abfd, sec) & (SEC_LOAD | SEC_ALLOC))
683d2201f2fSdrahn != (SEC_LOAD | SEC_ALLOC))
684d2201f2fSdrahn return;
685d2201f2fSdrahn
686d2201f2fSdrahn if (infop->addr >= vma && infop->addr < vma + MAX_ARTIFICIAL_SECTION_SIZE)
687d2201f2fSdrahn infop->sec = sec;
688d2201f2fSdrahn }
689d2201f2fSdrahn
690d2201f2fSdrahn /* Find a section that corresponds to a VMA. Automatically create .text
691d2201f2fSdrahn or .data and set current section to it, depending on what vma. If we
692d2201f2fSdrahn can't deduce a section, make one up as ".MMIX.sec.N", where N is an
693d2201f2fSdrahn increasing number. */
694d2201f2fSdrahn
695d2201f2fSdrahn static asection *
mmo_decide_section(abfd,vma)696d2201f2fSdrahn mmo_decide_section (abfd, vma)
697d2201f2fSdrahn bfd *abfd;
698d2201f2fSdrahn bfd_vma vma;
699d2201f2fSdrahn {
700d2201f2fSdrahn asection *sec = NULL;
701d2201f2fSdrahn char sec_name[sizeof (".MMIX.sec.") + 20];
702d2201f2fSdrahn struct mmo_find_sec_info info;
703d2201f2fSdrahn
704d2201f2fSdrahn info.addr = vma;
705d2201f2fSdrahn info.sec = NULL;
706d2201f2fSdrahn
707d2201f2fSdrahn /* First see if there's a section that would match exactly. */
708d2201f2fSdrahn bfd_map_over_sections (abfd, mmo_find_sec_w_addr, &info);
709d2201f2fSdrahn
710d2201f2fSdrahn if (info.sec != NULL)
711d2201f2fSdrahn return info.sec;
712d2201f2fSdrahn
713d2201f2fSdrahn /* If there's no such section, try and expand one of the existing ones,
714d2201f2fSdrahn up to a limit. Make sure we have .text and .data before we try that;
715d2201f2fSdrahn create them corresponding to expected addresses and set flags to make
716d2201f2fSdrahn them match the "loaded and with contents" expectation. */
717d2201f2fSdrahn if ((vma >> 56) == 0)
718d2201f2fSdrahn {
719d2201f2fSdrahn sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
720d2201f2fSdrahn
721d2201f2fSdrahn if (sec == NULL)
722d2201f2fSdrahn return NULL;
723d2201f2fSdrahn
724d2201f2fSdrahn if (! sec->user_set_vma)
725d2201f2fSdrahn bfd_set_section_vma (abfd, sec, vma);
726d2201f2fSdrahn if (! bfd_set_section_flags (abfd, sec,
727d2201f2fSdrahn bfd_get_section_flags (abfd, sec)
728d2201f2fSdrahn | SEC_CODE | SEC_LOAD | SEC_ALLOC))
729d2201f2fSdrahn return NULL;
730d2201f2fSdrahn }
731d2201f2fSdrahn else if ((vma >> 56) == 0x20)
732d2201f2fSdrahn {
733d2201f2fSdrahn sec = bfd_make_section_old_way (abfd, MMO_DATA_SECTION_NAME);
734d2201f2fSdrahn
735d2201f2fSdrahn if (sec == NULL)
736d2201f2fSdrahn return NULL;
737d2201f2fSdrahn
738d2201f2fSdrahn if (! sec->user_set_vma)
739d2201f2fSdrahn bfd_set_section_vma (abfd, sec, vma);
740d2201f2fSdrahn if (! bfd_set_section_flags (abfd, sec,
741d2201f2fSdrahn bfd_get_section_flags (abfd, sec)
742d2201f2fSdrahn | SEC_LOAD | SEC_ALLOC))
743d2201f2fSdrahn return NULL;
744d2201f2fSdrahn }
745d2201f2fSdrahn
746d2201f2fSdrahn bfd_map_over_sections (abfd, mmo_find_sec_w_addr_grow, &info);
747d2201f2fSdrahn
748d2201f2fSdrahn if (info.sec != NULL)
749d2201f2fSdrahn return info.sec;
750d2201f2fSdrahn
751d2201f2fSdrahn /* If there's still no suitable section, make a new one. */
752d2201f2fSdrahn sprintf (sec_name, ".MMIX.sec.%d", abfd->tdata.mmo_data->sec_no++);
753d2201f2fSdrahn sec = mmo_make_section (abfd, sec_name);
754d2201f2fSdrahn if (! sec->user_set_vma)
755d2201f2fSdrahn bfd_set_section_vma (abfd, sec, vma);
756d2201f2fSdrahn
757d2201f2fSdrahn if (! bfd_set_section_flags (abfd, sec,
758d2201f2fSdrahn bfd_get_section_flags (abfd, sec)
759d2201f2fSdrahn | SEC_LOAD | SEC_ALLOC))
760d2201f2fSdrahn return NULL;
761d2201f2fSdrahn return sec;
762d2201f2fSdrahn }
763d2201f2fSdrahn
764d2201f2fSdrahn /* Xor in a 64-bit value VALUE at VMA. */
765d2201f2fSdrahn
766d2201f2fSdrahn static INLINE void
mmo_xore_64(sec,vma,value)767d2201f2fSdrahn mmo_xore_64 (sec, vma, value)
768d2201f2fSdrahn asection *sec;
769d2201f2fSdrahn bfd_vma vma;
770d2201f2fSdrahn bfd_vma value;
771d2201f2fSdrahn {
772d2201f2fSdrahn bfd_byte *loc = mmo_get_loc (sec, vma, 8);
773d2201f2fSdrahn bfd_vma prev = bfd_get_64 (sec->owner, loc);
774d2201f2fSdrahn
775d2201f2fSdrahn value ^= prev;
776d2201f2fSdrahn bfd_put_64 (sec->owner, value, loc);
777d2201f2fSdrahn }
778d2201f2fSdrahn
779d2201f2fSdrahn /* Xor in a 32-bit value VALUE at VMA. */
780d2201f2fSdrahn
781d2201f2fSdrahn static INLINE void
mmo_xore_32(sec,vma,value)782d2201f2fSdrahn mmo_xore_32 (sec, vma, value)
783d2201f2fSdrahn asection *sec;
784d2201f2fSdrahn bfd_vma vma;
785d2201f2fSdrahn unsigned int value;
786d2201f2fSdrahn {
787d2201f2fSdrahn bfd_byte *loc = mmo_get_loc (sec, vma, 4);
788d2201f2fSdrahn unsigned int prev = bfd_get_32 (sec->owner, loc);
789d2201f2fSdrahn
790d2201f2fSdrahn value ^= prev;
791d2201f2fSdrahn bfd_put_32 (sec->owner, value, loc);
792d2201f2fSdrahn }
793d2201f2fSdrahn
794d2201f2fSdrahn /* Xor in a 16-bit value VALUE at VMA. */
795d2201f2fSdrahn
796d2201f2fSdrahn static INLINE void
mmo_xore_16(sec,vma,value)797d2201f2fSdrahn mmo_xore_16 (sec, vma, value)
798d2201f2fSdrahn asection *sec;
799d2201f2fSdrahn bfd_vma vma;
800d2201f2fSdrahn unsigned int value;
801d2201f2fSdrahn {
802d2201f2fSdrahn bfd_byte *loc = mmo_get_loc (sec, vma, 2);
803d2201f2fSdrahn unsigned int prev = bfd_get_16 (sec->owner, loc);
804d2201f2fSdrahn
805d2201f2fSdrahn value ^= prev;
806d2201f2fSdrahn bfd_put_16 (sec->owner, value, loc);
807d2201f2fSdrahn }
808d2201f2fSdrahn
809d2201f2fSdrahn /* Write a 32-bit word to output file, no lop_quote generated. */
810d2201f2fSdrahn
811d2201f2fSdrahn static INLINE void
mmo_write_tetra_raw(abfd,value)812d2201f2fSdrahn mmo_write_tetra_raw (abfd, value)
813d2201f2fSdrahn bfd *abfd;
814d2201f2fSdrahn unsigned int value;
815d2201f2fSdrahn {
816d2201f2fSdrahn bfd_byte buf[4];
817d2201f2fSdrahn
818d2201f2fSdrahn bfd_put_32 (abfd, value, buf);
819d2201f2fSdrahn
820d2201f2fSdrahn if (bfd_bwrite ((PTR) buf, 4, abfd) != 4)
821d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
822d2201f2fSdrahn }
823d2201f2fSdrahn
824d2201f2fSdrahn /* Write a 32-bit word to output file; lop_quote if necessary. */
825d2201f2fSdrahn
826d2201f2fSdrahn static INLINE void
mmo_write_tetra(abfd,value)827d2201f2fSdrahn mmo_write_tetra (abfd, value)
828d2201f2fSdrahn bfd *abfd;
829d2201f2fSdrahn unsigned int value;
830d2201f2fSdrahn {
831d2201f2fSdrahn if (((value >> 24) & 0xff) == LOP)
832d2201f2fSdrahn mmo_write_tetra_raw (abfd, LOP_QUOTE_NEXT);
833d2201f2fSdrahn
834d2201f2fSdrahn mmo_write_tetra_raw (abfd, value);
835d2201f2fSdrahn }
836d2201f2fSdrahn
837d2201f2fSdrahn /* Write a 64-bit word to output file, perhaps with lop_quoting. */
838d2201f2fSdrahn
839d2201f2fSdrahn static INLINE void
mmo_write_octa(abfd,value)840d2201f2fSdrahn mmo_write_octa (abfd, value)
841d2201f2fSdrahn bfd *abfd;
842d2201f2fSdrahn bfd_vma value;
843d2201f2fSdrahn {
844d2201f2fSdrahn mmo_write_tetra (abfd, (unsigned int) (value >> 32));
845d2201f2fSdrahn mmo_write_tetra (abfd, (unsigned int) value);
846d2201f2fSdrahn }
847d2201f2fSdrahn
848d2201f2fSdrahn /* Write a 64-bit word to output file, without lop_quoting. */
849d2201f2fSdrahn
850d2201f2fSdrahn static INLINE void
mmo_write_octa_raw(abfd,value)851d2201f2fSdrahn mmo_write_octa_raw (abfd, value)
852d2201f2fSdrahn bfd *abfd;
853d2201f2fSdrahn bfd_vma value;
854d2201f2fSdrahn {
855d2201f2fSdrahn mmo_write_tetra_raw (abfd, (unsigned int) (value >> 32));
856d2201f2fSdrahn mmo_write_tetra_raw (abfd, (unsigned int) value);
857d2201f2fSdrahn }
858d2201f2fSdrahn
859d2201f2fSdrahn /* Write quoted contents. Intended to be called multiple times in
860d2201f2fSdrahn sequence, followed by a call to mmo_flush_chunk. */
861d2201f2fSdrahn
862d2201f2fSdrahn static INLINE bfd_boolean
mmo_write_chunk(abfd,loc,len)863d2201f2fSdrahn mmo_write_chunk (abfd, loc, len)
864d2201f2fSdrahn bfd *abfd;
865d2201f2fSdrahn const bfd_byte *loc;
866d2201f2fSdrahn unsigned int len;
867d2201f2fSdrahn {
868d2201f2fSdrahn bfd_boolean retval = TRUE;
869d2201f2fSdrahn
870d2201f2fSdrahn /* Fill up a tetra from bytes remaining from a previous chunk. */
871d2201f2fSdrahn if (abfd->tdata.mmo_data->byte_no != 0)
872d2201f2fSdrahn {
873d2201f2fSdrahn while (abfd->tdata.mmo_data->byte_no < 4 && len != 0)
874d2201f2fSdrahn {
875d2201f2fSdrahn abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no++] = *loc++;
876d2201f2fSdrahn len--;
877d2201f2fSdrahn }
878d2201f2fSdrahn
879d2201f2fSdrahn if (abfd->tdata.mmo_data->byte_no == 4)
880d2201f2fSdrahn {
881d2201f2fSdrahn mmo_write_tetra (abfd,
882d2201f2fSdrahn bfd_get_32 (abfd, abfd->tdata.mmo_data->buf));
883d2201f2fSdrahn abfd->tdata.mmo_data->byte_no = 0;
884d2201f2fSdrahn }
885d2201f2fSdrahn }
886d2201f2fSdrahn
887d2201f2fSdrahn while (len >= 4)
888d2201f2fSdrahn {
889d2201f2fSdrahn if (loc[0] == LOP)
890d2201f2fSdrahn mmo_write_tetra_raw (abfd, LOP_QUOTE_NEXT);
891d2201f2fSdrahn
892d2201f2fSdrahn retval = (retval
893d2201f2fSdrahn && ! abfd->tdata.mmo_data->have_error
894d2201f2fSdrahn && 4 == bfd_bwrite ((PTR) loc, 4, abfd));
895d2201f2fSdrahn
896d2201f2fSdrahn loc += 4;
897d2201f2fSdrahn len -= 4;
898d2201f2fSdrahn }
899d2201f2fSdrahn
900d2201f2fSdrahn if (len)
901d2201f2fSdrahn {
902d2201f2fSdrahn memcpy (abfd->tdata.mmo_data->buf, loc, len);
903d2201f2fSdrahn abfd->tdata.mmo_data->byte_no = len;
904d2201f2fSdrahn }
905d2201f2fSdrahn
906d2201f2fSdrahn if (! retval)
907d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
908d2201f2fSdrahn return retval;
909d2201f2fSdrahn }
910d2201f2fSdrahn
911d2201f2fSdrahn /* Flush remaining bytes, from a previous mmo_write_chunk, zero-padded to
912d2201f2fSdrahn 4 bytes. */
913d2201f2fSdrahn
914d2201f2fSdrahn static INLINE bfd_boolean
mmo_flush_chunk(abfd)915d2201f2fSdrahn mmo_flush_chunk (abfd)
916d2201f2fSdrahn bfd *abfd;
917d2201f2fSdrahn {
918d2201f2fSdrahn if (abfd->tdata.mmo_data->byte_no != 0)
919d2201f2fSdrahn {
920d2201f2fSdrahn memset (abfd->tdata.mmo_data->buf + abfd->tdata.mmo_data->byte_no,
921d2201f2fSdrahn 0, 4 - abfd->tdata.mmo_data->byte_no);
922d2201f2fSdrahn mmo_write_tetra (abfd,
923d2201f2fSdrahn bfd_get_32 (abfd, abfd->tdata.mmo_data->buf));
924d2201f2fSdrahn abfd->tdata.mmo_data->byte_no = 0;
925d2201f2fSdrahn }
926d2201f2fSdrahn
927d2201f2fSdrahn return ! abfd->tdata.mmo_data->have_error;
928d2201f2fSdrahn }
929d2201f2fSdrahn
930d2201f2fSdrahn /* Same, but from a list. */
931d2201f2fSdrahn
932d2201f2fSdrahn static INLINE bfd_boolean
mmo_write_chunk_list(abfd,datap)933d2201f2fSdrahn mmo_write_chunk_list (abfd, datap)
934d2201f2fSdrahn bfd *abfd;
935d2201f2fSdrahn mmo_data_list_type *datap;
936d2201f2fSdrahn {
937d2201f2fSdrahn for (; datap != NULL; datap = datap->next)
938d2201f2fSdrahn if (! mmo_write_chunk (abfd, datap->data, datap->size))
939d2201f2fSdrahn return FALSE;
940d2201f2fSdrahn
941d2201f2fSdrahn return mmo_flush_chunk (abfd);
942d2201f2fSdrahn }
943d2201f2fSdrahn
944d2201f2fSdrahn /* Write a lop_loc and some contents. A caller needs to call
945d2201f2fSdrahn mmo_flush_chunk after calling this function. The location is only
946d2201f2fSdrahn output if different than *LAST_VMAP, which is updated after this call. */
947d2201f2fSdrahn
948d2201f2fSdrahn static bfd_boolean
mmo_write_loc_chunk(abfd,vma,loc,len,last_vmap)949d2201f2fSdrahn mmo_write_loc_chunk (abfd, vma, loc, len, last_vmap)
950d2201f2fSdrahn bfd *abfd;
951d2201f2fSdrahn bfd_vma vma;
952d2201f2fSdrahn const bfd_byte *loc;
953d2201f2fSdrahn unsigned int len;
954d2201f2fSdrahn bfd_vma *last_vmap;
955d2201f2fSdrahn {
956d2201f2fSdrahn /* Find an initial and trailing section of zero tetras; we don't need to
957d2201f2fSdrahn write out zeros. FIXME: When we do this, we should emit section size
958d2201f2fSdrahn and address specifiers, else objcopy can't always perform an identity
959d2201f2fSdrahn translation. Only do this if we *don't* have left-over data from a
960d2201f2fSdrahn previous write or the vma of this chunk is *not* the next address,
961d2201f2fSdrahn because then data isn't tetrabyte-aligned and we're concatenating to
962d2201f2fSdrahn that left-over data. */
963d2201f2fSdrahn
964d2201f2fSdrahn if (abfd->tdata.mmo_data->byte_no == 0 || vma != *last_vmap)
965d2201f2fSdrahn {
966d2201f2fSdrahn while (len >= 4 && bfd_get_32 (abfd, loc) == 0)
967d2201f2fSdrahn {
968d2201f2fSdrahn vma += 4;
969d2201f2fSdrahn len -= 4;
970d2201f2fSdrahn loc += 4;
971d2201f2fSdrahn }
972d2201f2fSdrahn
973d2201f2fSdrahn while (len >= 4 && bfd_get_32 (abfd, loc + len - 4) == 0)
974d2201f2fSdrahn len -= 4;
975d2201f2fSdrahn }
976d2201f2fSdrahn
977d2201f2fSdrahn /* Only write out the location if it's different than the one the caller
978d2201f2fSdrahn (supposedly) previously handled, accounting for omitted leading zeros. */
979d2201f2fSdrahn if (vma != *last_vmap)
980d2201f2fSdrahn {
981d2201f2fSdrahn /* We might be in the middle of a sequence. */
982d2201f2fSdrahn mmo_flush_chunk (abfd);
983d2201f2fSdrahn
984d2201f2fSdrahn /* We always write the location as 64 bits; no use saving bytes
985d2201f2fSdrahn here. */
986d2201f2fSdrahn mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_LOC << 16) | 2);
987d2201f2fSdrahn mmo_write_octa_raw (abfd, vma);
988d2201f2fSdrahn }
989d2201f2fSdrahn
990d2201f2fSdrahn /* Update to reflect end of this chunk, with trailing zeros omitted. */
991d2201f2fSdrahn *last_vmap = vma + len;
992d2201f2fSdrahn
993d2201f2fSdrahn return (! abfd->tdata.mmo_data->have_error
994d2201f2fSdrahn && mmo_write_chunk (abfd, loc, len));
995d2201f2fSdrahn }
996d2201f2fSdrahn
997d2201f2fSdrahn /* Same, but from a list. */
998d2201f2fSdrahn
999d2201f2fSdrahn static INLINE bfd_boolean
mmo_write_loc_chunk_list(abfd,datap)1000d2201f2fSdrahn mmo_write_loc_chunk_list (abfd, datap)
1001d2201f2fSdrahn bfd *abfd;
1002d2201f2fSdrahn mmo_data_list_type *datap;
1003d2201f2fSdrahn {
1004d2201f2fSdrahn /* Get an address different than the address of the first chunk. */
1005d2201f2fSdrahn bfd_vma last_vma = datap ? datap->where - 1 : 0;
1006d2201f2fSdrahn
1007d2201f2fSdrahn for (; datap != NULL; datap = datap->next)
1008d2201f2fSdrahn if (! mmo_write_loc_chunk (abfd, datap->where, datap->data, datap->size,
1009d2201f2fSdrahn &last_vma))
1010d2201f2fSdrahn return FALSE;
1011d2201f2fSdrahn
1012d2201f2fSdrahn return mmo_flush_chunk (abfd);
1013d2201f2fSdrahn }
1014d2201f2fSdrahn
1015d2201f2fSdrahn /* Make a .MMIX.spec_data.N section. */
1016d2201f2fSdrahn
1017d2201f2fSdrahn static asection *
mmo_get_generic_spec_data_section(abfd,spec_data_number)1018d2201f2fSdrahn mmo_get_generic_spec_data_section (abfd, spec_data_number)
1019d2201f2fSdrahn bfd *abfd;
1020d2201f2fSdrahn int spec_data_number;
1021d2201f2fSdrahn {
1022d2201f2fSdrahn asection *sec;
1023d2201f2fSdrahn char secname[sizeof (MMIX_OTHER_SPEC_SECTION_PREFIX) + 20]
1024d2201f2fSdrahn = MMIX_OTHER_SPEC_SECTION_PREFIX;
1025d2201f2fSdrahn
1026d2201f2fSdrahn sprintf (secname + strlen (MMIX_OTHER_SPEC_SECTION_PREFIX),
1027d2201f2fSdrahn "%d", spec_data_number);
1028d2201f2fSdrahn
1029d2201f2fSdrahn sec = mmo_make_section (abfd, secname);
1030d2201f2fSdrahn
1031d2201f2fSdrahn return sec;
1032d2201f2fSdrahn }
1033d2201f2fSdrahn
1034d2201f2fSdrahn /* Make a special section for SPEC_DATA_NUMBER. If it is the one we use
1035d2201f2fSdrahn ourselves, parse some of its data to get at the section name. */
1036d2201f2fSdrahn
1037d2201f2fSdrahn static asection *
mmo_get_spec_section(abfd,spec_data_number)1038d2201f2fSdrahn mmo_get_spec_section (abfd, spec_data_number)
1039d2201f2fSdrahn bfd *abfd;
1040d2201f2fSdrahn int spec_data_number;
1041d2201f2fSdrahn {
1042d2201f2fSdrahn bfd_byte *secname;
1043d2201f2fSdrahn asection *sec;
1044d2201f2fSdrahn bfd_byte buf[4];
1045d2201f2fSdrahn unsigned int secname_length;
1046d2201f2fSdrahn unsigned int i;
1047d2201f2fSdrahn bfd_vma section_length;
1048d2201f2fSdrahn bfd_vma section_vma;
1049d2201f2fSdrahn mmo_data_list_type *loc;
1050d2201f2fSdrahn flagword flags;
1051d2201f2fSdrahn long orig_pos;
1052d2201f2fSdrahn
1053d2201f2fSdrahn /* If this isn't the "special" special data, then make a placeholder
1054d2201f2fSdrahn section. */
1055d2201f2fSdrahn if (spec_data_number != SPEC_DATA_SECTION)
1056d2201f2fSdrahn return mmo_get_generic_spec_data_section (abfd, spec_data_number);
1057d2201f2fSdrahn
1058d2201f2fSdrahn /* Seek back to this position if there was a format error. */
1059d2201f2fSdrahn orig_pos = bfd_tell (abfd);
1060d2201f2fSdrahn
1061d2201f2fSdrahn /* Read the length (in 32-bit words). */
1062d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1063d2201f2fSdrahn goto format_error;
1064d2201f2fSdrahn
1065d2201f2fSdrahn if (buf[0] == LOP)
1066d2201f2fSdrahn {
1067d2201f2fSdrahn if (buf[1] != LOP_QUOTE)
1068d2201f2fSdrahn goto format_error;
1069d2201f2fSdrahn
1070d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1071d2201f2fSdrahn goto format_error;
1072d2201f2fSdrahn }
1073d2201f2fSdrahn
1074d2201f2fSdrahn /* We don't care to keep the name length accurate. It's
1075d2201f2fSdrahn zero-terminated. */
1076d2201f2fSdrahn secname_length = bfd_get_32 (abfd, buf) * 4;
1077d2201f2fSdrahn
1078d2201f2fSdrahn /* Check section name length for sanity. */
1079d2201f2fSdrahn if (secname_length > MAX_SECTION_NAME_SIZE)
1080d2201f2fSdrahn goto format_error;
1081d2201f2fSdrahn
1082d2201f2fSdrahn /* This should be free'd regardless if a section is created. */
1083d2201f2fSdrahn secname = bfd_malloc (secname_length + 1);
1084d2201f2fSdrahn secname[secname_length] = 0;
1085d2201f2fSdrahn
1086d2201f2fSdrahn for (i = 0; i < secname_length / 4; i++)
1087d2201f2fSdrahn {
1088d2201f2fSdrahn if (bfd_bread (secname + i * 4, 4, abfd) != 4)
1089d2201f2fSdrahn goto format_error_free;
1090d2201f2fSdrahn
1091d2201f2fSdrahn if (secname[i * 4] == LOP)
1092d2201f2fSdrahn {
1093d2201f2fSdrahn /* A bit of overkill, but we handle char 0x98 in a section name,
1094d2201f2fSdrahn and recognize misparsing. */
1095d2201f2fSdrahn if (secname[i * 4 + 1] != LOP_QUOTE
1096d2201f2fSdrahn || bfd_bread (secname + i * 4, 4, abfd) != 4)
1097d2201f2fSdrahn /* Whoops. We thought this was a name, and now we found a
1098d2201f2fSdrahn non-lop_quote lopcode before we parsed the whole length of
1099d2201f2fSdrahn the name. Signal end-of-file in the same manner. */
1100d2201f2fSdrahn goto format_error_free;
1101d2201f2fSdrahn }
1102d2201f2fSdrahn }
1103d2201f2fSdrahn
1104d2201f2fSdrahn /* Get the section flags. */
1105d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4
1106d2201f2fSdrahn || (buf[0] == LOP
1107d2201f2fSdrahn && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
1108d2201f2fSdrahn goto format_error_free;
1109d2201f2fSdrahn
1110d2201f2fSdrahn flags = bfd_get_32 (abfd, buf);
1111d2201f2fSdrahn
1112d2201f2fSdrahn /* Get the section length. */
1113d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4
1114d2201f2fSdrahn || (buf[0] == LOP
1115d2201f2fSdrahn && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
1116d2201f2fSdrahn goto format_error_free;
1117d2201f2fSdrahn
1118d2201f2fSdrahn section_length = (bfd_vma) bfd_get_32 (abfd, buf) << 32;
1119d2201f2fSdrahn
1120d2201f2fSdrahn /* That's the first, high-part. Now get the low part. */
1121d2201f2fSdrahn
1122d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4
1123d2201f2fSdrahn || (buf[0] == LOP
1124d2201f2fSdrahn && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
1125d2201f2fSdrahn goto format_error_free;
1126d2201f2fSdrahn
1127d2201f2fSdrahn section_length |= (bfd_vma) bfd_get_32 (abfd, buf);
1128d2201f2fSdrahn
1129d2201f2fSdrahn /* Check the section length for sanity. */
1130d2201f2fSdrahn if (section_length > MAX_ARTIFICIAL_SECTION_SIZE)
1131d2201f2fSdrahn goto format_error_free;
1132d2201f2fSdrahn
1133d2201f2fSdrahn /* Get the section VMA. */
1134d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4
1135d2201f2fSdrahn || (buf[0] == LOP
1136d2201f2fSdrahn && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
1137d2201f2fSdrahn goto format_error_free;
1138d2201f2fSdrahn
1139d2201f2fSdrahn section_vma = (bfd_vma) bfd_get_32 (abfd, buf) << 32;
1140d2201f2fSdrahn
1141d2201f2fSdrahn /* That's the first, high-part. Now get the low part. */
1142d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4
1143d2201f2fSdrahn || (buf[0] == LOP
1144d2201f2fSdrahn && (buf[1] != LOP_QUOTE || bfd_bread (buf, 4, abfd) != 4)))
1145d2201f2fSdrahn goto format_error_free;
1146d2201f2fSdrahn
1147d2201f2fSdrahn section_vma |= (bfd_vma) bfd_get_32 (abfd, buf);
1148d2201f2fSdrahn
1149d2201f2fSdrahn sec = mmo_make_section (abfd, secname);
1150d2201f2fSdrahn free (secname);
1151d2201f2fSdrahn if (sec == NULL)
1152d2201f2fSdrahn goto format_error;
1153d2201f2fSdrahn
1154d2201f2fSdrahn /* We allocate a buffer here for the advertised size, with head room for
1155d2201f2fSdrahn tetrabyte alignment. */
1156d2201f2fSdrahn loc = bfd_zmalloc (section_length + 3
1157d2201f2fSdrahn + sizeof (struct mmo_data_list_struct));
1158d2201f2fSdrahn if (loc == NULL)
1159d2201f2fSdrahn goto format_error;
1160d2201f2fSdrahn
1161d2201f2fSdrahn /* Use a TETRA-rounded size for the allocated buffer; we set the
1162d2201f2fSdrahn "visible" section size below. */
1163d2201f2fSdrahn loc->size = (section_length + 3) & ~3;
1164d2201f2fSdrahn
1165d2201f2fSdrahn /* Add in the section flags we found to those bfd entered during this
1166d2201f2fSdrahn process and set the contents. */
1167d2201f2fSdrahn if (! bfd_set_section_flags (abfd, sec,
1168d2201f2fSdrahn bfd_sec_flags_from_mmo_flags (flags)
1169d2201f2fSdrahn | bfd_get_section_flags (abfd, sec)
1170d2201f2fSdrahn | (section_length != 0 ? SEC_HAS_CONTENTS : 0))
1171d2201f2fSdrahn || ! bfd_set_section_size (abfd, sec,
1172d2201f2fSdrahn sec->_cooked_size + section_length)
1173d2201f2fSdrahn /* Set VMA only for the first occurrence. */
1174d2201f2fSdrahn || (! sec->user_set_vma
1175d2201f2fSdrahn && ! bfd_set_section_vma (abfd, sec, section_vma)))
1176d2201f2fSdrahn {
1177d2201f2fSdrahn /* If we get an error for any of the calls above, signal more than
1178d2201f2fSdrahn just a format error for the spec section. */
1179d2201f2fSdrahn return NULL;
1180d2201f2fSdrahn }
1181d2201f2fSdrahn
1182d2201f2fSdrahn loc->next = NULL;
1183d2201f2fSdrahn if (mmo_section_data (sec)->tail != NULL)
1184d2201f2fSdrahn mmo_section_data (sec)->tail->next = loc;
1185d2201f2fSdrahn else
1186d2201f2fSdrahn mmo_section_data (sec)->head = loc;
1187d2201f2fSdrahn mmo_section_data (sec)->tail = loc;
1188d2201f2fSdrahn loc->where = section_vma;
1189d2201f2fSdrahn
1190d2201f2fSdrahn return sec;
1191d2201f2fSdrahn
1192d2201f2fSdrahn format_error_free:
1193d2201f2fSdrahn free (secname);
1194d2201f2fSdrahn format_error:
1195d2201f2fSdrahn if (bfd_seek (abfd, orig_pos, SEEK_SET) != 0)
1196d2201f2fSdrahn return NULL;
1197d2201f2fSdrahn
1198d2201f2fSdrahn return mmo_get_generic_spec_data_section (abfd, spec_data_number);
1199d2201f2fSdrahn }
1200d2201f2fSdrahn
1201d2201f2fSdrahn /* Read a byte, but read from file in multiples of 32-bit words. */
1202d2201f2fSdrahn
1203d2201f2fSdrahn static bfd_byte
mmo_get_byte(abfd)1204d2201f2fSdrahn mmo_get_byte (abfd)
1205d2201f2fSdrahn bfd *abfd;
1206d2201f2fSdrahn {
1207d2201f2fSdrahn bfd_byte retval;
1208d2201f2fSdrahn
1209d2201f2fSdrahn if (abfd->tdata.mmo_data->byte_no == 0)
1210d2201f2fSdrahn {
1211d2201f2fSdrahn if (! abfd->tdata.mmo_data->have_error
1212d2201f2fSdrahn && bfd_bread (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
1213d2201f2fSdrahn {
1214d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
1215d2201f2fSdrahn
1216d2201f2fSdrahn /* A value somewhat safe against tripping on some inconsistency
1217d2201f2fSdrahn when mopping up after this error. */
1218d2201f2fSdrahn return 128;
1219d2201f2fSdrahn }
1220d2201f2fSdrahn }
1221d2201f2fSdrahn
1222d2201f2fSdrahn retval = abfd->tdata.mmo_data->buf[abfd->tdata.mmo_data->byte_no];
1223d2201f2fSdrahn abfd->tdata.mmo_data->byte_no = (abfd->tdata.mmo_data->byte_no + 1) % 4;
1224d2201f2fSdrahn
1225d2201f2fSdrahn return retval;
1226d2201f2fSdrahn }
1227d2201f2fSdrahn
1228d2201f2fSdrahn /* Write a byte, in multiples of 32-bit words. */
1229d2201f2fSdrahn
1230d2201f2fSdrahn static void
mmo_write_byte(abfd,value)1231d2201f2fSdrahn mmo_write_byte (abfd, value)
1232d2201f2fSdrahn bfd *abfd;
1233d2201f2fSdrahn bfd_byte value;
1234d2201f2fSdrahn {
1235d2201f2fSdrahn abfd->tdata.mmo_data->buf[(abfd->tdata.mmo_data->byte_no++ % 4)] = value;
1236d2201f2fSdrahn if ((abfd->tdata.mmo_data->byte_no % 4) == 0)
1237d2201f2fSdrahn {
1238d2201f2fSdrahn if (! abfd->tdata.mmo_data->have_error
1239d2201f2fSdrahn && bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
1240d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
1241d2201f2fSdrahn }
1242d2201f2fSdrahn }
1243d2201f2fSdrahn
1244d2201f2fSdrahn /* Create a symbol. */
1245d2201f2fSdrahn
1246d2201f2fSdrahn static bfd_boolean
mmo_create_symbol(abfd,symname,addr,sym_type,serno)1247d2201f2fSdrahn mmo_create_symbol (abfd, symname, addr, sym_type, serno)
1248d2201f2fSdrahn bfd *abfd;
1249d2201f2fSdrahn const char *symname;
1250d2201f2fSdrahn bfd_vma addr;
1251d2201f2fSdrahn enum mmo_sym_type sym_type;
1252d2201f2fSdrahn unsigned int serno;
1253d2201f2fSdrahn {
1254d2201f2fSdrahn struct mmo_symbol *n;
1255d2201f2fSdrahn
1256d2201f2fSdrahn n = (struct mmo_symbol *) bfd_alloc (abfd, sizeof (struct mmo_symbol));
1257d2201f2fSdrahn if (n == NULL)
1258d2201f2fSdrahn return FALSE;
1259d2201f2fSdrahn
1260d2201f2fSdrahn n->name = bfd_alloc (abfd, strlen (symname) + 1);
1261d2201f2fSdrahn if (n->name == NULL)
1262d2201f2fSdrahn return FALSE;
1263d2201f2fSdrahn
1264d2201f2fSdrahn strcpy ((PTR) n->name, symname);
1265d2201f2fSdrahn
1266d2201f2fSdrahn n->value = addr;
1267d2201f2fSdrahn n->sym_type = sym_type;
1268d2201f2fSdrahn n->serno = serno;
1269d2201f2fSdrahn
1270d2201f2fSdrahn if (abfd->tdata.mmo_data->symbols == NULL)
1271d2201f2fSdrahn abfd->tdata.mmo_data->symbols = n;
1272d2201f2fSdrahn else
1273d2201f2fSdrahn abfd->tdata.mmo_data->symtail->next = n;
1274d2201f2fSdrahn abfd->tdata.mmo_data->symtail = n;
1275d2201f2fSdrahn n->next = NULL;
1276d2201f2fSdrahn
1277d2201f2fSdrahn ++abfd->symcount;
1278d2201f2fSdrahn
1279d2201f2fSdrahn /* Check that :Main equals the last octa of the .MMIX.reg_contents
1280d2201f2fSdrahn section, as it's the one place we're sure to pass when reading a mmo
1281d2201f2fSdrahn object. For written objects, we do it while setting the symbol
1282d2201f2fSdrahn table. */
1283d2201f2fSdrahn if (strcmp (symname, MMIX_START_SYMBOL_NAME) == 0
1284d2201f2fSdrahn && bfd_get_start_address (abfd) != addr)
1285d2201f2fSdrahn {
1286d2201f2fSdrahn (*_bfd_error_handler)
1287d2201f2fSdrahn (_("%s: invalid mmo file: initialization value for $255 is not `Main'\n"),
1288d2201f2fSdrahn bfd_get_filename (abfd));
1289d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1290d2201f2fSdrahn return FALSE;
1291d2201f2fSdrahn }
1292d2201f2fSdrahn
1293d2201f2fSdrahn return TRUE;
1294d2201f2fSdrahn }
1295d2201f2fSdrahn
1296d2201f2fSdrahn /* Read in symbols. */
1297d2201f2fSdrahn
1298d2201f2fSdrahn static bfd_boolean
mmo_get_symbols(abfd)1299d2201f2fSdrahn mmo_get_symbols (abfd)
1300d2201f2fSdrahn bfd *abfd;
1301d2201f2fSdrahn {
1302d2201f2fSdrahn /*
1303d2201f2fSdrahn INODE
1304d2201f2fSdrahn Symbol-table, mmo section mapping, File layout, mmo
1305d2201f2fSdrahn SUBSECTION
1306d2201f2fSdrahn Symbol table format
1307d2201f2fSdrahn
1308d2201f2fSdrahn From mmixal.w (or really, the generated mmixal.tex) in
1309d2201f2fSdrahn @url{http://www-cs-faculty.stanford.edu/~knuth/programs/mmix.tar.gz}):
1310d2201f2fSdrahn ``Symbols are stored and retrieved by means of a @samp{ternary
1311d2201f2fSdrahn search trie}, following ideas of Bentley and Sedgewick. (See
1312d2201f2fSdrahn ACM--SIAM Symp.@: on Discrete Algorithms @samp{8} (1997), 360--369;
1313d2201f2fSdrahn R.@:Sedgewick, @samp{Algorithms in C} (Reading, Mass.@:
1314d2201f2fSdrahn Addison--Wesley, 1998), @samp{15.4}.) Each trie node stores a
1315d2201f2fSdrahn character, and there are branches to subtries for the cases where
1316d2201f2fSdrahn a given character is less than, equal to, or greater than the
1317d2201f2fSdrahn character in the trie. There also is a pointer to a symbol table
1318d2201f2fSdrahn entry if a symbol ends at the current node.''
1319d2201f2fSdrahn
1320d2201f2fSdrahn So it's a tree encoded as a stream of bytes. The stream of bytes
1321d2201f2fSdrahn acts on a single virtual global symbol, adding and removing
1322d2201f2fSdrahn characters and signalling complete symbol points. Here, we read
1323d2201f2fSdrahn the stream and create symbols at the completion points.
1324d2201f2fSdrahn
1325d2201f2fSdrahn First, there's a control byte <<m>>. If any of the listed bits
1326d2201f2fSdrahn in <<m>> is nonzero, we execute what stands at the right, in
1327d2201f2fSdrahn the listed order:
1328d2201f2fSdrahn
1329d2201f2fSdrahn | (MMO3_LEFT)
1330d2201f2fSdrahn | 0x40 - Traverse left trie.
1331d2201f2fSdrahn | (Read a new command byte and recurse.)
1332d2201f2fSdrahn |
1333d2201f2fSdrahn | (MMO3_SYMBITS)
1334d2201f2fSdrahn | 0x2f - Read the next byte as a character and store it in the
1335d2201f2fSdrahn | current character position; increment character position.
1336d2201f2fSdrahn | Test the bits of <<m>>:
1337d2201f2fSdrahn |
1338d2201f2fSdrahn | (MMO3_WCHAR)
1339d2201f2fSdrahn | 0x80 - The character is 16-bit (so read another byte,
1340d2201f2fSdrahn | merge into current character.
1341d2201f2fSdrahn |
1342d2201f2fSdrahn | (MMO3_TYPEBITS)
1343d2201f2fSdrahn | 0xf - We have a complete symbol; parse the type, value
1344d2201f2fSdrahn | and serial number and do what should be done
1345d2201f2fSdrahn | with a symbol. The type and length information
1346d2201f2fSdrahn | is in j = (m & 0xf).
1347d2201f2fSdrahn |
1348d2201f2fSdrahn | (MMO3_REGQUAL_BITS)
1349d2201f2fSdrahn | j == 0xf: A register variable. The following
1350d2201f2fSdrahn | byte tells which register.
1351d2201f2fSdrahn | j <= 8: An absolute symbol. Read j bytes as the
1352d2201f2fSdrahn | big-endian number the symbol equals.
1353d2201f2fSdrahn | A j = 2 with two zero bytes denotes an
1354d2201f2fSdrahn | unknown symbol.
1355d2201f2fSdrahn | j > 8: As with j <= 8, but add (0x20 << 56)
1356d2201f2fSdrahn | to the value in the following j - 8
1357d2201f2fSdrahn | bytes.
1358d2201f2fSdrahn |
1359d2201f2fSdrahn | Then comes the serial number, as a variant of
1360d2201f2fSdrahn | uleb128, but better named ubeb128:
1361d2201f2fSdrahn | Read bytes and shift the previous value left 7
1362d2201f2fSdrahn | (multiply by 128). Add in the new byte, repeat
1363d2201f2fSdrahn | until a byte has bit 7 set. The serial number
1364d2201f2fSdrahn | is the computed value minus 128.
1365d2201f2fSdrahn |
1366d2201f2fSdrahn | (MMO3_MIDDLE)
1367d2201f2fSdrahn | 0x20 - Traverse middle trie. (Read a new command byte
1368d2201f2fSdrahn | and recurse.) Decrement character position.
1369d2201f2fSdrahn |
1370d2201f2fSdrahn | (MMO3_RIGHT)
1371d2201f2fSdrahn | 0x10 - Traverse right trie. (Read a new command byte and
1372d2201f2fSdrahn | recurse.)
1373d2201f2fSdrahn
1374d2201f2fSdrahn Let's look again at the <<lop_stab>> for the trivial file
1375d2201f2fSdrahn (@pxref{File layout}).
1376d2201f2fSdrahn
1377d2201f2fSdrahn | 0x980b0000 - lop_stab for ":Main" = 0, serial 1.
1378d2201f2fSdrahn | 0x203a4040
1379d2201f2fSdrahn | 0x10404020
1380d2201f2fSdrahn | 0x4d206120
1381d2201f2fSdrahn | 0x69016e00
1382d2201f2fSdrahn | 0x81000000
1383d2201f2fSdrahn
1384d2201f2fSdrahn This forms the trivial trie (note that the path between ``:'' and
1385d2201f2fSdrahn ``M'' is redundant):
1386d2201f2fSdrahn
1387d2201f2fSdrahn | 203a ":"
1388d2201f2fSdrahn | 40 /
1389d2201f2fSdrahn | 40 /
1390d2201f2fSdrahn | 10 \
1391d2201f2fSdrahn | 40 /
1392d2201f2fSdrahn | 40 /
1393d2201f2fSdrahn | 204d "M"
1394d2201f2fSdrahn | 2061 "a"
1395d2201f2fSdrahn | 2069 "i"
1396d2201f2fSdrahn | 016e "n" is the last character in a full symbol, and
1397d2201f2fSdrahn | with a value represented in one byte.
1398d2201f2fSdrahn | 00 The value is 0.
1399d2201f2fSdrahn | 81 The serial number is 1. */
1400d2201f2fSdrahn
1401d2201f2fSdrahn bfd_byte m = mmo_get_byte (abfd);
1402d2201f2fSdrahn
1403d2201f2fSdrahn /* Check first if we have a bad hair day. */
1404d2201f2fSdrahn if (abfd->tdata.mmo_data->have_error)
1405d2201f2fSdrahn return FALSE;
1406d2201f2fSdrahn
1407d2201f2fSdrahn if (m & MMO3_LEFT)
1408d2201f2fSdrahn /* Traverse left trie. */
1409d2201f2fSdrahn mmo_get_symbols (abfd);
1410d2201f2fSdrahn
1411d2201f2fSdrahn if (m & MMO3_SYMBITS)
1412d2201f2fSdrahn {
1413d2201f2fSdrahn bfd_byte c = mmo_get_byte (abfd);
1414d2201f2fSdrahn bfd_byte j = m & MMO3_TYPEBITS;
1415d2201f2fSdrahn bfd_vma addr = 0;
1416d2201f2fSdrahn enum mmo_sym_type sym_type;
1417d2201f2fSdrahn unsigned int serno = 0;
1418d2201f2fSdrahn bfd_byte k;
1419d2201f2fSdrahn
1420d2201f2fSdrahn if (m & MMO3_WCHAR)
1421d2201f2fSdrahn {
1422d2201f2fSdrahn bfd_byte c2 = mmo_get_byte (abfd);
1423d2201f2fSdrahn
1424d2201f2fSdrahn /* A two-byte character. We can't grok this, but neither can
1425d2201f2fSdrahn mmotype, for other cases than the second byte being zero. */
1426d2201f2fSdrahn
1427d2201f2fSdrahn if (c != 0)
1428d2201f2fSdrahn {
1429d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol
1430d2201f2fSdrahn [abfd->tdata.mmo_data->symbol_position] = 0;
1431d2201f2fSdrahn
1432d2201f2fSdrahn (*_bfd_error_handler)
1433d2201f2fSdrahn (_("%s: unsupported wide character sequence\
1434d2201f2fSdrahn 0x%02X 0x%02X after symbol name starting with `%s'\n"),
1435d2201f2fSdrahn bfd_get_filename (abfd), c, c2,
1436d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol);
1437d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1438d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
1439d2201f2fSdrahn return FALSE;
1440d2201f2fSdrahn }
1441d2201f2fSdrahn else
1442d2201f2fSdrahn c = c2;
1443d2201f2fSdrahn }
1444d2201f2fSdrahn
1445d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position++] = c;
1446d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol[abfd->tdata.mmo_data->symbol_position] = 0;
1447d2201f2fSdrahn
1448d2201f2fSdrahn if (j & MMO3_REGQUAL_BITS)
1449d2201f2fSdrahn {
1450d2201f2fSdrahn if (j == MMO3_REGQUAL_BITS)
1451d2201f2fSdrahn {
1452d2201f2fSdrahn sym_type = mmo_reg_sym;
1453d2201f2fSdrahn addr = mmo_get_byte (abfd);
1454d2201f2fSdrahn }
1455d2201f2fSdrahn else if (j <= 8)
1456d2201f2fSdrahn {
1457d2201f2fSdrahn unsigned int i;
1458d2201f2fSdrahn
1459d2201f2fSdrahn for (i = 0; i < j; i++)
1460d2201f2fSdrahn addr = (addr << 8) + mmo_get_byte (abfd);
1461d2201f2fSdrahn
1462d2201f2fSdrahn if (addr == 0 && j == MMO3_UNDEF)
1463d2201f2fSdrahn sym_type = mmo_undef_sym;
1464d2201f2fSdrahn else
1465d2201f2fSdrahn sym_type = mmo_abs_sym;
1466d2201f2fSdrahn }
1467d2201f2fSdrahn else
1468d2201f2fSdrahn {
1469d2201f2fSdrahn unsigned int i;
1470d2201f2fSdrahn
1471d2201f2fSdrahn for (i = MMO3_DATA; i < j; i++)
1472d2201f2fSdrahn addr = (addr << 8) + mmo_get_byte (abfd);
1473d2201f2fSdrahn
1474d2201f2fSdrahn addr += (bfd_vma) 0x20 << 56;
1475d2201f2fSdrahn sym_type = mmo_data_sym;
1476d2201f2fSdrahn }
1477d2201f2fSdrahn
1478d2201f2fSdrahn /* Get the serial number. */
1479d2201f2fSdrahn do
1480d2201f2fSdrahn {
1481d2201f2fSdrahn k = mmo_get_byte (abfd);
1482d2201f2fSdrahn serno = (serno << 7) + k;
1483d2201f2fSdrahn }
1484d2201f2fSdrahn while (k < 128);
1485d2201f2fSdrahn serno -= 128;
1486d2201f2fSdrahn
1487d2201f2fSdrahn /* Got it. Now enter it. Skip a leading ":". */
1488d2201f2fSdrahn if (! abfd->tdata.mmo_data->have_error
1489d2201f2fSdrahn && ! mmo_create_symbol (abfd,
1490d2201f2fSdrahn abfd->tdata.mmo_data->lop_stab_symbol
1491d2201f2fSdrahn + 1,
1492d2201f2fSdrahn addr, sym_type, serno))
1493d2201f2fSdrahn abfd->tdata.mmo_data->have_error = TRUE;
1494d2201f2fSdrahn }
1495d2201f2fSdrahn
1496d2201f2fSdrahn if (m & MMO3_MIDDLE)
1497d2201f2fSdrahn /* Traverse middle trie. */
1498d2201f2fSdrahn mmo_get_symbols (abfd);
1499d2201f2fSdrahn
1500d2201f2fSdrahn abfd->tdata.mmo_data->symbol_position--;
1501d2201f2fSdrahn }
1502d2201f2fSdrahn
1503d2201f2fSdrahn if (m & MMO3_RIGHT)
1504d2201f2fSdrahn /* Traverse right trie. */
1505d2201f2fSdrahn mmo_get_symbols (abfd);
1506d2201f2fSdrahn
1507d2201f2fSdrahn return ! abfd->tdata.mmo_data->have_error;
1508d2201f2fSdrahn }
1509d2201f2fSdrahn
1510d2201f2fSdrahn /* Get the location of memory area [VMA..VMA + SIZE - 1], which we think
1511d2201f2fSdrahn is in section SEC. Adjust and reallocate zero-initialized contents.
1512d2201f2fSdrahn If there's new contents, allocate to the next multiple of
1513d2201f2fSdrahn MMO_SEC_CONTENTS_CHUNK_SIZE. */
1514d2201f2fSdrahn
1515d2201f2fSdrahn static INLINE bfd_byte *
mmo_get_loc(sec,vma,size)1516d2201f2fSdrahn mmo_get_loc (sec, vma, size)
1517d2201f2fSdrahn asection *sec;
1518d2201f2fSdrahn bfd_vma vma;
1519d2201f2fSdrahn int size;
1520d2201f2fSdrahn {
1521d2201f2fSdrahn bfd_size_type allocated_size;
1522d2201f2fSdrahn struct mmo_section_data_struct *sdatap = mmo_section_data (sec);
1523d2201f2fSdrahn struct mmo_data_list_struct *datap = sdatap->head;
1524d2201f2fSdrahn struct mmo_data_list_struct *entry;
1525d2201f2fSdrahn
1526d2201f2fSdrahn /* First search the list to see if we have the requested chunk in one
1527d2201f2fSdrahn piece, or perhaps if we have a suitable chunk with room to fit. */
1528d2201f2fSdrahn for (; datap != NULL; datap = datap->next)
1529d2201f2fSdrahn {
1530d2201f2fSdrahn if (datap->where <= vma
1531d2201f2fSdrahn && datap->where + datap->size >= vma + size)
1532d2201f2fSdrahn return datap->data + vma - datap->where;
1533d2201f2fSdrahn else if (datap->where <= vma
1534d2201f2fSdrahn && datap->where + datap->allocated_size >= vma + size
1535d2201f2fSdrahn /* Only munch on the "allocated size" if it does not
1536d2201f2fSdrahn overlap the next chunk. */
1537d2201f2fSdrahn && (datap->next == NULL || datap->next->where >= vma + size))
1538d2201f2fSdrahn {
1539d2201f2fSdrahn /* There was room allocated, but the size wasn't set to include
1540d2201f2fSdrahn it. Do that now. */
1541d2201f2fSdrahn datap->size += (vma + size) - (datap->where + datap->size);
1542d2201f2fSdrahn
1543d2201f2fSdrahn /* Update the section size. This happens only if we update the
1544d2201f2fSdrahn 32-bit-aligned chunk size. Callers that have
1545d2201f2fSdrahn non-32-bit-aligned sections should do all allocation and
1546d2201f2fSdrahn size-setting by themselves or at least set the section size
1547d2201f2fSdrahn after the last allocating call to this function. */
1548d2201f2fSdrahn if (vma + size > sec->vma + sec->_raw_size)
1549d2201f2fSdrahn sec->_raw_size += (vma + size) - (sec->vma + sec->_raw_size);
1550d2201f2fSdrahn
1551d2201f2fSdrahn return datap->data + vma - datap->where;
1552d2201f2fSdrahn }
1553d2201f2fSdrahn }
1554d2201f2fSdrahn
1555d2201f2fSdrahn /* Not found; allocate a new block. First check in case we get a
1556d2201f2fSdrahn request for a size split up over several blocks; we'll have to return
1557d2201f2fSdrahn NULL for those cases, requesting the caller to split up the request.
1558d2201f2fSdrahn Requests with an address aligned on MMO_SEC_CONTENTS_CHUNK_SIZE bytes and
1559d2201f2fSdrahn for no more than MMO_SEC_CONTENTS_CHUNK_SIZE will always get resolved. */
1560d2201f2fSdrahn
1561d2201f2fSdrahn for (datap = sdatap->head; datap != NULL; datap = datap->next)
1562d2201f2fSdrahn if ((datap->where <= vma && datap->where + datap->size > vma)
1563d2201f2fSdrahn || (datap->where < vma + size
1564d2201f2fSdrahn && datap->where + datap->size >= vma + size))
1565d2201f2fSdrahn return NULL;
1566d2201f2fSdrahn
1567d2201f2fSdrahn allocated_size
1568d2201f2fSdrahn = (size + MMO_SEC_CONTENTS_CHUNK_SIZE - 1) & ~(MMO_SEC_CONTENTS_CHUNK_SIZE - 1);
1569d2201f2fSdrahn entry = (mmo_data_list_type *)
1570d2201f2fSdrahn bfd_zalloc (sec->owner, sizeof (mmo_data_list_type) + allocated_size);
1571d2201f2fSdrahn if (entry == NULL)
1572d2201f2fSdrahn return NULL;
1573d2201f2fSdrahn entry->where = vma;
1574d2201f2fSdrahn entry->size = size;
1575d2201f2fSdrahn entry->allocated_size = allocated_size;
1576d2201f2fSdrahn
1577d2201f2fSdrahn datap = sdatap->head;
1578d2201f2fSdrahn
1579d2201f2fSdrahn /* Sort the records by address. Optimize for the common case of adding
1580d2201f2fSdrahn a record to the end of the list. */
1581d2201f2fSdrahn if (sdatap->tail != NULL && entry->where >= sdatap->tail->where)
1582d2201f2fSdrahn {
1583d2201f2fSdrahn sdatap->tail->next = entry;
1584d2201f2fSdrahn entry->next = NULL;
1585d2201f2fSdrahn sdatap->tail = entry;
1586d2201f2fSdrahn }
1587d2201f2fSdrahn else
1588d2201f2fSdrahn {
1589d2201f2fSdrahn mmo_data_list_type **look;
1590d2201f2fSdrahn for (look = &sdatap->head;
1591d2201f2fSdrahn *look != NULL && (*look)->where < entry->where;
1592d2201f2fSdrahn look = &(*look)->next)
1593d2201f2fSdrahn ;
1594d2201f2fSdrahn entry->next = *look;
1595d2201f2fSdrahn *look = entry;
1596d2201f2fSdrahn if (entry->next == NULL)
1597d2201f2fSdrahn {
1598d2201f2fSdrahn sdatap->tail = entry;
1599d2201f2fSdrahn
1600d2201f2fSdrahn /* We get here for the first time (at other times too) for this
1601d2201f2fSdrahn section. Say we have contents. */
1602d2201f2fSdrahn if (! bfd_set_section_flags (sec->owner, sec,
1603d2201f2fSdrahn bfd_get_section_flags (sec->owner, sec)
1604d2201f2fSdrahn | SEC_HAS_CONTENTS))
1605d2201f2fSdrahn return NULL;
1606d2201f2fSdrahn }
1607d2201f2fSdrahn }
1608d2201f2fSdrahn
1609d2201f2fSdrahn /* Update the section size. This happens only when we add contents and
1610d2201f2fSdrahn re-size as we go. The section size will then be aligned to 32 bits. */
1611d2201f2fSdrahn if (vma + size > sec->vma + sec->_raw_size)
1612d2201f2fSdrahn sec->_raw_size += (vma + size) - (sec->vma + sec->_raw_size);
1613d2201f2fSdrahn return entry->data;
1614d2201f2fSdrahn }
1615d2201f2fSdrahn
1616d2201f2fSdrahn /* Set sizes once we've read in all sections. */
1617d2201f2fSdrahn
1618d2201f2fSdrahn static void
mmo_map_set_sizes(abfd,sec,ignored)1619d2201f2fSdrahn mmo_map_set_sizes (abfd, sec, ignored)
1620d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
1621d2201f2fSdrahn asection *sec;
1622d2201f2fSdrahn PTR ignored ATTRIBUTE_UNUSED;
1623d2201f2fSdrahn {
1624d2201f2fSdrahn sec->_cooked_size = sec->_raw_size;
1625d2201f2fSdrahn sec->lma = sec->vma;
1626d2201f2fSdrahn }
1627d2201f2fSdrahn
1628d2201f2fSdrahn /* Read the mmo file and turn it into sections. */
1629d2201f2fSdrahn
1630d2201f2fSdrahn static bfd_boolean
mmo_scan(abfd)1631d2201f2fSdrahn mmo_scan (abfd)
1632d2201f2fSdrahn bfd *abfd;
1633d2201f2fSdrahn {
1634d2201f2fSdrahn unsigned int i;
1635d2201f2fSdrahn unsigned int lineno = 1;
1636d2201f2fSdrahn bfd_boolean error = FALSE;
1637d2201f2fSdrahn bfd_vma vma = 0;
1638d2201f2fSdrahn asection *sec = bfd_make_section_old_way (abfd, MMO_TEXT_SECTION_NAME);
1639d2201f2fSdrahn asection *non_spec_sec = NULL;
1640d2201f2fSdrahn bfd_vma non_spec_vma = 0;
1641d2201f2fSdrahn char *current_filename = NULL;
1642d2201f2fSdrahn bfd_size_type nbytes_read = 0;
1643d2201f2fSdrahn /* Buffer with room to read a 64-bit value. */
1644d2201f2fSdrahn bfd_byte buf[8];
1645d2201f2fSdrahn long stab_loc = -1;
1646d2201f2fSdrahn char *file_names[256];
1647d2201f2fSdrahn
1648d2201f2fSdrahn memset (file_names, 0, sizeof (file_names));
1649d2201f2fSdrahn
1650d2201f2fSdrahn if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
1651d2201f2fSdrahn goto error_return;
1652d2201f2fSdrahn
1653d2201f2fSdrahn while ((nbytes_read = bfd_bread (buf, 4, abfd)) == 4)
1654d2201f2fSdrahn {
1655d2201f2fSdrahn if (buf[0] == LOP)
1656d2201f2fSdrahn {
1657d2201f2fSdrahn unsigned int y = bfd_get_8 (abfd, buf + 2);
1658d2201f2fSdrahn unsigned int z = bfd_get_8 (abfd, buf + 3);
1659d2201f2fSdrahn
1660d2201f2fSdrahn /* Change back to the original section for lopcodes other
1661d2201f2fSdrahn than LOP_QUOTE that comes after a LOP_SPEC. */
1662d2201f2fSdrahn if ((buf[1] != LOP_QUOTE || y != 0 || z != 1)
1663d2201f2fSdrahn && non_spec_sec != NULL)
1664d2201f2fSdrahn {
1665d2201f2fSdrahn sec = non_spec_sec;
1666d2201f2fSdrahn vma = non_spec_vma;
1667d2201f2fSdrahn non_spec_sec = NULL;
1668d2201f2fSdrahn }
1669d2201f2fSdrahn
1670d2201f2fSdrahn switch (buf[1])
1671d2201f2fSdrahn {
1672d2201f2fSdrahn default:
1673d2201f2fSdrahn (*_bfd_error_handler)
1674d2201f2fSdrahn (_("%s: invalid mmo file: unsupported lopcode `%d'\n"),
1675d2201f2fSdrahn bfd_get_filename (abfd), buf[1]);
1676d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1677d2201f2fSdrahn goto error_return;
1678d2201f2fSdrahn
1679d2201f2fSdrahn case LOP_QUOTE:
1680d2201f2fSdrahn /* Quote the next 32-bit word. */
1681d2201f2fSdrahn if (y != 0 || z != 1)
1682d2201f2fSdrahn {
1683d2201f2fSdrahn (*_bfd_error_handler)
1684d2201f2fSdrahn (_("%s: invalid mmo file: expected YZ = 1 got YZ = %d for lop_quote\n"),
1685d2201f2fSdrahn bfd_get_filename (abfd), y*256+z);
1686d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1687d2201f2fSdrahn goto error_return;
1688d2201f2fSdrahn }
1689d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1690d2201f2fSdrahn goto error_return;
1691d2201f2fSdrahn
1692d2201f2fSdrahn mmo_xore_32 (sec, vma, bfd_get_32 (abfd, buf));
1693d2201f2fSdrahn vma += 4;
1694d2201f2fSdrahn vma &= ~3;
1695d2201f2fSdrahn lineno++;
1696d2201f2fSdrahn break;
1697d2201f2fSdrahn
1698d2201f2fSdrahn case LOP_LOC:
1699d2201f2fSdrahn /* Set vma (and section). */
1700d2201f2fSdrahn vma = (bfd_vma) y << 56;
1701d2201f2fSdrahn if (z == 1)
1702d2201f2fSdrahn {
1703d2201f2fSdrahn /* Get a 32-bit value. */
1704d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1705d2201f2fSdrahn goto error_return;
1706d2201f2fSdrahn
1707d2201f2fSdrahn vma += bfd_get_32 (abfd, buf);
1708d2201f2fSdrahn }
1709d2201f2fSdrahn else if (z == 2)
1710d2201f2fSdrahn {
1711d2201f2fSdrahn /* Get a 64-bit value. */
1712d2201f2fSdrahn if (bfd_bread (buf, 8, abfd) != 8)
1713d2201f2fSdrahn goto error_return;
1714d2201f2fSdrahn
1715d2201f2fSdrahn vma += bfd_get_64 (abfd, buf);
1716d2201f2fSdrahn }
1717d2201f2fSdrahn else
1718d2201f2fSdrahn {
1719d2201f2fSdrahn (*_bfd_error_handler)
1720d2201f2fSdrahn (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_loc\n"),
1721d2201f2fSdrahn bfd_get_filename (abfd), z);
1722d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1723d2201f2fSdrahn goto error_return;
1724d2201f2fSdrahn }
1725d2201f2fSdrahn
1726d2201f2fSdrahn sec = mmo_decide_section (abfd, vma);
1727d2201f2fSdrahn if (sec == NULL)
1728d2201f2fSdrahn goto error_return;
1729d2201f2fSdrahn break;
1730d2201f2fSdrahn
1731d2201f2fSdrahn case LOP_SKIP:
1732d2201f2fSdrahn /* Move forward within the same section. */
1733d2201f2fSdrahn vma += y * 256 + z;
1734d2201f2fSdrahn
1735d2201f2fSdrahn sec = mmo_decide_section (abfd, vma);
1736d2201f2fSdrahn if (sec == NULL)
1737d2201f2fSdrahn goto error_return;
1738d2201f2fSdrahn break;
1739d2201f2fSdrahn
1740d2201f2fSdrahn case LOP_FIXO:
1741d2201f2fSdrahn /* A fixup: Store the current vma somewhere. Position using
1742d2201f2fSdrahn same format as LOP_LOC. */
1743d2201f2fSdrahn {
1744d2201f2fSdrahn bfd_vma p = (bfd_vma) y << 56;
1745d2201f2fSdrahn asection *fixosec;
1746d2201f2fSdrahn
1747d2201f2fSdrahn if (z == 1)
1748d2201f2fSdrahn {
1749d2201f2fSdrahn /* Get a 32-bit value. */
1750d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1751d2201f2fSdrahn goto error_return;
1752d2201f2fSdrahn
1753d2201f2fSdrahn p += bfd_get_32 (abfd, buf);
1754d2201f2fSdrahn }
1755d2201f2fSdrahn else if (z == 2)
1756d2201f2fSdrahn {
1757d2201f2fSdrahn /* Get a 64-bit value. */
1758d2201f2fSdrahn if (bfd_bread (buf, 8, abfd) != 8)
1759d2201f2fSdrahn goto error_return;
1760d2201f2fSdrahn
1761d2201f2fSdrahn p += bfd_get_64 (abfd, buf);
1762d2201f2fSdrahn }
1763d2201f2fSdrahn else
1764d2201f2fSdrahn {
1765d2201f2fSdrahn (*_bfd_error_handler)
1766d2201f2fSdrahn (_("%s: invalid mmo file: expected z = 1 or z = 2, got z = %d for lop_fixo\n"),
1767d2201f2fSdrahn bfd_get_filename (abfd), z);
1768d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1769d2201f2fSdrahn goto error_return;
1770d2201f2fSdrahn }
1771d2201f2fSdrahn
1772d2201f2fSdrahn /* The section where we store this address might be a
1773d2201f2fSdrahn different one than the current section. */
1774d2201f2fSdrahn fixosec = mmo_decide_section (abfd, p);
1775d2201f2fSdrahn if (fixosec == NULL)
1776d2201f2fSdrahn goto error_return;
1777d2201f2fSdrahn mmo_xore_64 (fixosec, p, vma);
1778d2201f2fSdrahn }
1779d2201f2fSdrahn break;
1780d2201f2fSdrahn
1781d2201f2fSdrahn case LOP_FIXR:
1782d2201f2fSdrahn /* A fixup: Store YZ of this lopcode into YZ at vma - 4 * yz. */
1783d2201f2fSdrahn {
1784d2201f2fSdrahn unsigned int yz = (y * 256 + z);
1785d2201f2fSdrahn bfd_vma p = vma + 2 - 4 * yz;
1786d2201f2fSdrahn asection *fixrsec = mmo_decide_section (abfd, p);
1787d2201f2fSdrahn if (fixrsec == NULL)
1788d2201f2fSdrahn goto error_return;
1789d2201f2fSdrahn mmo_xore_16 (fixrsec, p, yz);
1790d2201f2fSdrahn }
1791d2201f2fSdrahn break;
1792d2201f2fSdrahn
1793d2201f2fSdrahn case LOP_FIXRX:
1794d2201f2fSdrahn /* A fixup, similar to lop_fixr, but taking larger numbers
1795d2201f2fSdrahn and can change branches into the opposite direction
1796d2201f2fSdrahn (gasp!). */
1797d2201f2fSdrahn {
1798d2201f2fSdrahn bfd_vma delta;
1799d2201f2fSdrahn bfd_vma p;
1800d2201f2fSdrahn asection *fixrsec;
1801d2201f2fSdrahn
1802d2201f2fSdrahn if (y != 0)
1803d2201f2fSdrahn {
1804d2201f2fSdrahn (*_bfd_error_handler)
1805d2201f2fSdrahn (_("%s: invalid mmo file: expected y = 0, got y = %d for lop_fixrx\n"),
1806d2201f2fSdrahn bfd_get_filename (abfd), y);
1807d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1808d2201f2fSdrahn goto error_return;
1809d2201f2fSdrahn }
1810d2201f2fSdrahn
1811d2201f2fSdrahn if (z != 16 && z != 24)
1812d2201f2fSdrahn {
1813d2201f2fSdrahn (*_bfd_error_handler)
1814d2201f2fSdrahn (_("%s: invalid mmo file: expected z = 16 or z = 24, got z = %d for lop_fixrx\n"),
1815d2201f2fSdrahn bfd_get_filename (abfd), z);
1816d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1817d2201f2fSdrahn goto error_return;
1818d2201f2fSdrahn }
1819d2201f2fSdrahn
1820d2201f2fSdrahn /* Get the next 32-bit value. */
1821d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1822d2201f2fSdrahn goto error_return;
1823d2201f2fSdrahn
1824d2201f2fSdrahn delta = bfd_get_32 (abfd, buf);
1825d2201f2fSdrahn
1826d2201f2fSdrahn /* Do an, ehm, involved calculation for the location of
1827d2201f2fSdrahn the fixup. See mmixal documentation for a verbose
1828d2201f2fSdrahn explanation. We follow it verbosely here for the
1829d2201f2fSdrahn readers delight. */
1830d2201f2fSdrahn if (buf[0] == 0)
1831d2201f2fSdrahn p = vma - 4 * delta;
1832d2201f2fSdrahn else if (buf[0] == 1)
1833d2201f2fSdrahn p = vma - 4 * ((delta & 0xffffff) - (1 << z));
1834d2201f2fSdrahn else
1835d2201f2fSdrahn {
1836d2201f2fSdrahn (*_bfd_error_handler)
1837d2201f2fSdrahn (_("%s: invalid mmo file: leading byte of operand word must be 0 or 1, got %d for lop_fixrx\n"),
1838d2201f2fSdrahn bfd_get_filename (abfd), buf[0]);
1839d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1840d2201f2fSdrahn goto error_return;
1841d2201f2fSdrahn }
1842d2201f2fSdrahn
1843d2201f2fSdrahn fixrsec = mmo_decide_section (abfd, vma);
1844d2201f2fSdrahn if (fixrsec == NULL)
1845d2201f2fSdrahn goto error_return;
1846d2201f2fSdrahn mmo_xore_32 (fixrsec, p, delta);
1847d2201f2fSdrahn }
1848d2201f2fSdrahn break;
1849d2201f2fSdrahn
1850d2201f2fSdrahn case LOP_FILE:
1851d2201f2fSdrahn /* Set current file and perhaps the file name. Reset line
1852d2201f2fSdrahn number. */
1853d2201f2fSdrahn if (z != 0)
1854d2201f2fSdrahn {
1855d2201f2fSdrahn char *fname = bfd_malloc (z * 4 + 1);
1856d2201f2fSdrahn
1857d2201f2fSdrahn if (fname == NULL)
1858d2201f2fSdrahn {
1859d2201f2fSdrahn (*_bfd_error_handler)
1860d2201f2fSdrahn (_("%s: cannot allocate file name for file number %d, %d bytes\n"),
1861d2201f2fSdrahn bfd_get_filename (abfd), y, z * 4 + 1);
1862d2201f2fSdrahn bfd_set_error (bfd_error_system_call);
1863d2201f2fSdrahn goto error_return;
1864d2201f2fSdrahn }
1865d2201f2fSdrahn
1866d2201f2fSdrahn fname[z * 4] = 0;
1867d2201f2fSdrahn
1868d2201f2fSdrahn for (i = 0; i < z; i++)
1869d2201f2fSdrahn {
1870d2201f2fSdrahn if (bfd_bread (fname + i * 4, 4, abfd) != 4)
1871d2201f2fSdrahn {
1872d2201f2fSdrahn free (fname);
1873d2201f2fSdrahn goto error_return;
1874d2201f2fSdrahn }
1875d2201f2fSdrahn }
1876d2201f2fSdrahn
1877d2201f2fSdrahn if (file_names[y] != NULL)
1878d2201f2fSdrahn {
1879d2201f2fSdrahn (*_bfd_error_handler)
1880d2201f2fSdrahn (_("%s: invalid mmo file: file number %d `%s',\
1881d2201f2fSdrahn was already entered as `%s'\n"),
1882d2201f2fSdrahn bfd_get_filename (abfd), y, fname, file_names[y]);
1883d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1884d2201f2fSdrahn goto error_return;
1885d2201f2fSdrahn }
1886d2201f2fSdrahn
1887d2201f2fSdrahn file_names[y] = fname;
1888d2201f2fSdrahn }
1889d2201f2fSdrahn
1890d2201f2fSdrahn if (file_names[y] == NULL)
1891d2201f2fSdrahn {
1892d2201f2fSdrahn (*_bfd_error_handler)
1893d2201f2fSdrahn (_("%s: invalid mmo file: file name for number %d\
1894d2201f2fSdrahn was not specified before use\n"),
1895d2201f2fSdrahn bfd_get_filename (abfd), y);
1896d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1897d2201f2fSdrahn goto error_return;
1898d2201f2fSdrahn }
1899d2201f2fSdrahn
1900d2201f2fSdrahn current_filename = file_names[y];
1901d2201f2fSdrahn lineno = 0;
1902d2201f2fSdrahn break;
1903d2201f2fSdrahn
1904d2201f2fSdrahn case LOP_LINE:
1905d2201f2fSdrahn /* Set line number. */
1906d2201f2fSdrahn lineno = y * 256 + z;
1907d2201f2fSdrahn /* FIXME: Create a sequence of mmo-specific line number
1908d2201f2fSdrahn entries for each section, then translate into canonical
1909d2201f2fSdrahn format. */
1910d2201f2fSdrahn break;
1911d2201f2fSdrahn
1912d2201f2fSdrahn case LOP_SPEC:
1913d2201f2fSdrahn /* Special data follows until the next non-lop_quote
1914d2201f2fSdrahn lopcode. */
1915d2201f2fSdrahn non_spec_sec = sec;
1916d2201f2fSdrahn non_spec_vma = vma;
1917d2201f2fSdrahn sec = mmo_get_spec_section (abfd, y * 256 + z);
1918d2201f2fSdrahn if (sec == NULL)
1919d2201f2fSdrahn goto error_return;
1920d2201f2fSdrahn
1921d2201f2fSdrahn vma = sec->vma;
1922d2201f2fSdrahn break;
1923d2201f2fSdrahn
1924d2201f2fSdrahn case LOP_PRE:
1925d2201f2fSdrahn {
1926d2201f2fSdrahn /* We ignore header information, except we read in the
1927d2201f2fSdrahn creation time from the first 32-bit word with the time
1928d2201f2fSdrahn in seconds since era. */
1929d2201f2fSdrahn if (z >= 1
1930d2201f2fSdrahn && bfd_bread (abfd->tdata.mmo_data->created, 4,
1931d2201f2fSdrahn abfd) != 4)
1932d2201f2fSdrahn goto error_return;
1933d2201f2fSdrahn
1934d2201f2fSdrahn for (i = 1; i < z; i++)
1935d2201f2fSdrahn if (bfd_bread (buf, 4, abfd) != 4)
1936d2201f2fSdrahn goto error_return;
1937d2201f2fSdrahn }
1938d2201f2fSdrahn break;
1939d2201f2fSdrahn
1940d2201f2fSdrahn case LOP_POST:
1941d2201f2fSdrahn /* This tells of the contents of registers $Z..$255 at
1942d2201f2fSdrahn startup. We make a section out of it, with VMA = Z * 8,
1943d2201f2fSdrahn but only if Z != 255 or the contents is non-zero. */
1944d2201f2fSdrahn {
1945d2201f2fSdrahn asection *rsec;
1946d2201f2fSdrahn bfd_byte *loc;
1947d2201f2fSdrahn bfd_vma first_octa;
1948d2201f2fSdrahn bfd_vma startaddr_octa;
1949d2201f2fSdrahn
1950d2201f2fSdrahn /* Read first octaword outside loop to simplify logic when
1951d2201f2fSdrahn excluding the Z == 255, octa == 0 case. */
1952d2201f2fSdrahn if (bfd_bread (buf, 8, abfd) != 8)
1953d2201f2fSdrahn goto error_return;
1954d2201f2fSdrahn
1955d2201f2fSdrahn first_octa = bfd_get_64 (abfd, buf);
1956d2201f2fSdrahn
1957d2201f2fSdrahn /* Don't emit contents for the trivial case which is
1958d2201f2fSdrahn always present; $255 pointing to Main. */
1959d2201f2fSdrahn if (z != 255)
1960d2201f2fSdrahn {
1961d2201f2fSdrahn rsec
1962d2201f2fSdrahn = bfd_make_section_old_way (abfd,
1963d2201f2fSdrahn MMIX_REG_CONTENTS_SECTION_NAME);
1964d2201f2fSdrahn rsec->vma = z * 8;
1965d2201f2fSdrahn loc = mmo_get_loc (rsec, z * 8, (255 - z) * 8);
1966d2201f2fSdrahn bfd_put_64 (abfd, first_octa, loc);
1967d2201f2fSdrahn
1968d2201f2fSdrahn for (i = z + 1; i < 255; i++)
1969d2201f2fSdrahn {
1970d2201f2fSdrahn if (bfd_bread (loc + (i - z) * 8, 8, abfd) != 8)
1971d2201f2fSdrahn goto error_return;
1972d2201f2fSdrahn }
1973d2201f2fSdrahn
1974d2201f2fSdrahn /* Read out the last octabyte, and use it to set the
1975d2201f2fSdrahn start address. */
1976d2201f2fSdrahn if (bfd_bread (buf, 8, abfd) != 8)
1977d2201f2fSdrahn goto error_return;
1978d2201f2fSdrahn
1979d2201f2fSdrahn startaddr_octa = bfd_get_64 (abfd, buf);
1980d2201f2fSdrahn }
1981d2201f2fSdrahn else
1982d2201f2fSdrahn startaddr_octa = first_octa;
1983d2201f2fSdrahn
1984d2201f2fSdrahn if (! bfd_set_start_address (abfd, startaddr_octa))
1985d2201f2fSdrahn {
1986d2201f2fSdrahn /* Currently this can't fail, but this should handle
1987d2201f2fSdrahn future failures. */
1988d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
1989d2201f2fSdrahn goto error_return;
1990d2201f2fSdrahn }
1991d2201f2fSdrahn }
1992d2201f2fSdrahn break;
1993d2201f2fSdrahn
1994d2201f2fSdrahn case LOP_STAB:
1995d2201f2fSdrahn /* We read in the symbols now, not later. */
1996d2201f2fSdrahn if (y != 0 || z != 0)
1997d2201f2fSdrahn {
1998d2201f2fSdrahn (*_bfd_error_handler)
1999d2201f2fSdrahn (_("%s: invalid mmo file: fields y and z of lop_stab\
2000d2201f2fSdrahn non-zero, y: %d, z: %d\n"),
2001d2201f2fSdrahn bfd_get_filename (abfd), y, z);
2002d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2003d2201f2fSdrahn goto error_return;
2004d2201f2fSdrahn }
2005d2201f2fSdrahn
2006d2201f2fSdrahn /* Save the location, so we can check that YZ in the LOP_END
2007d2201f2fSdrahn is correct. */
2008d2201f2fSdrahn stab_loc = bfd_tell (abfd);
2009d2201f2fSdrahn
2010d2201f2fSdrahn /* It's not said that an MMO can be without symbols (though
2011d2201f2fSdrahn mmixal will refuse to assemble files without Main), but
2012d2201f2fSdrahn it seems it would still be a valid mmo-file, so allow it.
2013d2201f2fSdrahn We detect the absence of a symbol area in that the upper
2014d2201f2fSdrahn limit is computed (from the lop_end YZ field) as 0.
2015d2201f2fSdrahn Don't call mmo_get_symbols; it can only detect the end of
2016d2201f2fSdrahn a valid symbol trie, not the absence of one. */
2017d2201f2fSdrahn if (abfd->tdata.mmo_data->max_symbol_length != 0
2018d2201f2fSdrahn && ! mmo_get_symbols (abfd))
2019d2201f2fSdrahn goto error_return;
2020d2201f2fSdrahn break;
2021d2201f2fSdrahn
2022d2201f2fSdrahn case LOP_END:
2023d2201f2fSdrahn {
2024d2201f2fSdrahn /* This must be the last 32-bit word in an mmo file.
2025d2201f2fSdrahn Let's find out. */
2026d2201f2fSdrahn struct stat statbuf;
2027d2201f2fSdrahn long curpos = bfd_tell (abfd);
2028d2201f2fSdrahn
2029d2201f2fSdrahn if (bfd_stat (abfd, &statbuf) < 0)
2030d2201f2fSdrahn goto error_return;
2031d2201f2fSdrahn
2032d2201f2fSdrahn if (statbuf.st_size != curpos)
2033d2201f2fSdrahn {
2034d2201f2fSdrahn (*_bfd_error_handler)
2035d2201f2fSdrahn (_("%s: invalid mmo file: lop_end not last item in\
2036d2201f2fSdrahn file\n"),
2037d2201f2fSdrahn bfd_get_filename (abfd));
2038d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2039d2201f2fSdrahn goto error_return;
2040d2201f2fSdrahn }
2041d2201f2fSdrahn
2042d2201f2fSdrahn /* Check that the YZ field is right. Subtract the size of
2043d2201f2fSdrahn this LOP_END in the calculation; YZ does not include
2044d2201f2fSdrahn it. */
2045d2201f2fSdrahn if ((long) (y * 256 + z) * 4 != (curpos - stab_loc) - 4)
2046d2201f2fSdrahn {
2047d2201f2fSdrahn (*_bfd_error_handler)
2048d2201f2fSdrahn (_("%s: invalid mmo file: YZ of lop_end (%ld)\
2049d2201f2fSdrahn not equal to the number of tetras to the preceding lop_stab (%ld)\n"),
2050d2201f2fSdrahn bfd_get_filename (abfd), (long) (y * 256 + z),
2051d2201f2fSdrahn (curpos - stab_loc - 4)/4);
2052d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2053d2201f2fSdrahn goto error_return;
2054d2201f2fSdrahn }
2055d2201f2fSdrahn
2056d2201f2fSdrahn bfd_map_over_sections (abfd, mmo_map_set_sizes, NULL);
2057d2201f2fSdrahn goto done;
2058d2201f2fSdrahn }
2059d2201f2fSdrahn }
2060d2201f2fSdrahn }
2061d2201f2fSdrahn else
2062d2201f2fSdrahn {
2063d2201f2fSdrahn /* This wasn't a lopcode, so store it in the current section. */
2064d2201f2fSdrahn mmo_xore_32 (sec, vma & ~3, bfd_get_32 (abfd, buf));
2065d2201f2fSdrahn vma += 4;
2066d2201f2fSdrahn vma &= ~3;
2067d2201f2fSdrahn lineno++;
2068d2201f2fSdrahn }
2069d2201f2fSdrahn }
2070d2201f2fSdrahn
2071d2201f2fSdrahn /* We know this file is a multiple of four bytes (checked in
2072d2201f2fSdrahn mmo_object_p), so if we got something other than 0, this was a bad
2073d2201f2fSdrahn file (although it's more likely we'll get 0 in that case too).
2074d2201f2fSdrahn If we got end-of-file, then there was no lop_stab, so the file has
2075d2201f2fSdrahn invalid format. */
2076d2201f2fSdrahn
2077d2201f2fSdrahn if (nbytes_read != 0)
2078d2201f2fSdrahn bfd_set_error (bfd_error_system_call);
2079d2201f2fSdrahn else
2080d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2081d2201f2fSdrahn
2082d2201f2fSdrahn error_return:
2083d2201f2fSdrahn error = TRUE;
2084d2201f2fSdrahn done:
2085d2201f2fSdrahn /* Mark the .text and .data section with their normal attribute if they
2086d2201f2fSdrahn contain anything. This is not redundant wrt. mmo_decide_section,
2087d2201f2fSdrahn since that code might never execute, and conversely the alloc+code
2088d2201f2fSdrahn section flags must be set then. */
2089d2201f2fSdrahn sec = bfd_get_section_by_name (abfd, MMO_TEXT_SECTION_NAME);
2090d2201f2fSdrahn if (sec != NULL
2091d2201f2fSdrahn && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
2092d2201f2fSdrahn && ! bfd_set_section_flags (abfd, sec,
2093d2201f2fSdrahn bfd_get_section_flags (abfd, sec)
2094d2201f2fSdrahn | SEC_ALLOC | SEC_LOAD | SEC_CODE))
2095d2201f2fSdrahn error = TRUE;
2096d2201f2fSdrahn
2097d2201f2fSdrahn sec = bfd_get_section_by_name (abfd, MMO_DATA_SECTION_NAME);
2098d2201f2fSdrahn if (sec != NULL
2099d2201f2fSdrahn && (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
2100d2201f2fSdrahn && ! bfd_set_section_flags (abfd, sec,
2101d2201f2fSdrahn bfd_get_section_flags (abfd, sec)
2102d2201f2fSdrahn | SEC_ALLOC | SEC_LOAD))
2103d2201f2fSdrahn error = TRUE;
2104d2201f2fSdrahn
2105d2201f2fSdrahn /* Free whatever resources we took. */
2106d2201f2fSdrahn for (i = 0; i < sizeof (file_names) / sizeof (file_names[0]); i++)
2107d2201f2fSdrahn if (file_names[i])
2108d2201f2fSdrahn free (file_names[i]);
2109d2201f2fSdrahn return ! error;
2110d2201f2fSdrahn }
2111d2201f2fSdrahn
2112d2201f2fSdrahn /* A hook to set up object file dependent section information. For mmo,
2113d2201f2fSdrahn we point out the shape of allocated section contents. */
2114d2201f2fSdrahn
2115d2201f2fSdrahn static bfd_boolean
mmo_new_section_hook(abfd,newsect)2116d2201f2fSdrahn mmo_new_section_hook (abfd, newsect)
2117d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
2118d2201f2fSdrahn asection *newsect;
2119d2201f2fSdrahn {
2120d2201f2fSdrahn /* We zero-fill all fields and assume NULL is represented by an all
2121d2201f2fSdrahn zero-bit pattern. */
2122d2201f2fSdrahn newsect->used_by_bfd =
2123d2201f2fSdrahn (PTR) bfd_zalloc (abfd, sizeof (struct mmo_section_data_struct));
2124d2201f2fSdrahn
2125d2201f2fSdrahn if (!newsect->used_by_bfd)
2126d2201f2fSdrahn return FALSE;
2127d2201f2fSdrahn
2128d2201f2fSdrahn /* Always align to at least 32-bit words. */
2129d2201f2fSdrahn newsect->alignment_power = 2;
2130d2201f2fSdrahn return TRUE;
2131d2201f2fSdrahn }
2132d2201f2fSdrahn
2133d2201f2fSdrahn /* We already have section contents loaded for sections that have
2134d2201f2fSdrahn contents. */
2135d2201f2fSdrahn
2136d2201f2fSdrahn static bfd_boolean
mmo_get_section_contents(abfd,sec,location,offset,bytes_to_do)2137d2201f2fSdrahn mmo_get_section_contents (abfd, sec, location, offset, bytes_to_do)
2138d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
2139d2201f2fSdrahn asection *sec ATTRIBUTE_UNUSED;
2140d2201f2fSdrahn PTR location ATTRIBUTE_UNUSED;
2141d2201f2fSdrahn file_ptr offset ATTRIBUTE_UNUSED;
2142d2201f2fSdrahn bfd_size_type bytes_to_do ATTRIBUTE_UNUSED;
2143d2201f2fSdrahn {
2144d2201f2fSdrahn /* Iterate over diminishing chunk sizes, copying contents, like
2145d2201f2fSdrahn mmo_set_section_contents. */
2146d2201f2fSdrahn while (bytes_to_do)
2147d2201f2fSdrahn {
2148d2201f2fSdrahn /* A minor song-and-dance to make sure we're not bitten by the
2149d2201f2fSdrahn distant possibility of the cast from bfd_vma to int making the
2150d2201f2fSdrahn chunk zero-sized. */
2151d2201f2fSdrahn int chunk_size
2152d2201f2fSdrahn = (int) bytes_to_do != 0 ? bytes_to_do : MMO_SEC_CONTENTS_CHUNK_SIZE;
2153d2201f2fSdrahn bfd_byte *loc;
2154d2201f2fSdrahn
2155d2201f2fSdrahn do
2156d2201f2fSdrahn loc = mmo_get_loc (sec, sec->vma + offset, chunk_size);
2157d2201f2fSdrahn while (loc == NULL && (chunk_size /= 2) != 0);
2158d2201f2fSdrahn
2159d2201f2fSdrahn if (chunk_size == 0)
2160d2201f2fSdrahn return FALSE;
2161d2201f2fSdrahn
2162d2201f2fSdrahn memcpy (location, loc, chunk_size);
2163d2201f2fSdrahn
2164d2201f2fSdrahn location += chunk_size;
2165d2201f2fSdrahn bytes_to_do -= chunk_size;
2166d2201f2fSdrahn offset += chunk_size;
2167d2201f2fSdrahn }
2168d2201f2fSdrahn return TRUE;
2169d2201f2fSdrahn }
2170d2201f2fSdrahn
2171d2201f2fSdrahn /* Return the amount of memory needed to read the symbol table. */
2172d2201f2fSdrahn
2173d2201f2fSdrahn static long
mmo_get_symtab_upper_bound(abfd)2174d2201f2fSdrahn mmo_get_symtab_upper_bound (abfd)
2175d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
2176d2201f2fSdrahn {
2177d2201f2fSdrahn return (abfd->symcount + 1) * sizeof (asymbol *);
2178d2201f2fSdrahn }
2179d2201f2fSdrahn
2180d2201f2fSdrahn /* Sort mmo symbols by serial number. */
2181d2201f2fSdrahn
2182d2201f2fSdrahn static int
mmo_sort_mmo_symbols(arg1,arg2)2183d2201f2fSdrahn mmo_sort_mmo_symbols (arg1, arg2)
2184d2201f2fSdrahn const PTR arg1;
2185d2201f2fSdrahn const PTR arg2;
2186d2201f2fSdrahn {
2187d2201f2fSdrahn const struct mmo_symbol *sym1 = *(const struct mmo_symbol **) arg1;
2188d2201f2fSdrahn const struct mmo_symbol *sym2 = *(const struct mmo_symbol **) arg2;
2189d2201f2fSdrahn
2190d2201f2fSdrahn /* Sort by serial number first. */
2191d2201f2fSdrahn if (sym1->serno < sym2->serno)
2192d2201f2fSdrahn return -1;
2193d2201f2fSdrahn else if (sym1->serno > sym2->serno)
2194d2201f2fSdrahn return 1;
2195d2201f2fSdrahn
2196d2201f2fSdrahn /* Then sort by address of the table entries. */
2197d2201f2fSdrahn return ((const char *) arg1 - (const char *) arg2);
2198d2201f2fSdrahn }
2199d2201f2fSdrahn
2200d2201f2fSdrahn /* Translate the symbol table. */
2201d2201f2fSdrahn
2202d2201f2fSdrahn static long
mmo_canonicalize_symtab(abfd,alocation)2203*cf2f2c56Smiod mmo_canonicalize_symtab (abfd, alocation)
2204d2201f2fSdrahn bfd *abfd;
2205d2201f2fSdrahn asymbol **alocation;
2206d2201f2fSdrahn {
2207d2201f2fSdrahn unsigned int symcount = bfd_get_symcount (abfd);
2208d2201f2fSdrahn asymbol *csymbols;
2209d2201f2fSdrahn unsigned int i;
2210d2201f2fSdrahn
2211d2201f2fSdrahn csymbols = abfd->tdata.mmo_data->csymbols;
2212d2201f2fSdrahn if (csymbols == NULL)
2213d2201f2fSdrahn {
2214d2201f2fSdrahn asymbol *c;
2215d2201f2fSdrahn struct mmo_symbol *s;
2216d2201f2fSdrahn struct mmo_symbol **msp;
2217d2201f2fSdrahn
2218d2201f2fSdrahn /* First we store the symbols into the table we'll return, then we
2219d2201f2fSdrahn qsort it on the serial number, with secondary on the address of
2220d2201f2fSdrahn the symbol, to preserve order if there would be non-unique serial
2221d2201f2fSdrahn numbers. */
2222d2201f2fSdrahn for (s = abfd->tdata.mmo_data->symbols,
2223d2201f2fSdrahn msp = (struct mmo_symbol **) alocation;
2224d2201f2fSdrahn s != NULL;
2225d2201f2fSdrahn s = s->next, ++msp)
2226d2201f2fSdrahn *msp = s;
2227d2201f2fSdrahn
2228d2201f2fSdrahn *msp = NULL;
2229d2201f2fSdrahn
2230d2201f2fSdrahn qsort (alocation, symcount, sizeof (struct mmo_symbol *),
2231d2201f2fSdrahn mmo_sort_mmo_symbols);
2232d2201f2fSdrahn
2233d2201f2fSdrahn csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol));
2234d2201f2fSdrahn if (csymbols == NULL && symcount != 0)
2235d2201f2fSdrahn return FALSE;
2236d2201f2fSdrahn abfd->tdata.mmo_data->csymbols = csymbols;
2237d2201f2fSdrahn
2238d2201f2fSdrahn for (msp = (struct mmo_symbol **) alocation, c = csymbols;
2239d2201f2fSdrahn *msp != NULL;
2240d2201f2fSdrahn msp++, ++c)
2241d2201f2fSdrahn {
2242d2201f2fSdrahn s = *msp;
2243d2201f2fSdrahn c->the_bfd = abfd;
2244d2201f2fSdrahn c->name = s->name;
2245d2201f2fSdrahn c->value = s->value;
2246d2201f2fSdrahn c->flags = BSF_GLOBAL;
2247d2201f2fSdrahn
2248d2201f2fSdrahn if (s->sym_type == mmo_data_sym)
2249d2201f2fSdrahn {
2250d2201f2fSdrahn c->section
2251d2201f2fSdrahn = bfd_get_section_by_name (abfd, MMO_DATA_SECTION_NAME);
2252d2201f2fSdrahn
2253d2201f2fSdrahn if (c->section == NULL)
2254d2201f2fSdrahn c->section = bfd_abs_section_ptr;
2255d2201f2fSdrahn else
2256d2201f2fSdrahn c->value -= c->section->vma;
2257d2201f2fSdrahn }
2258d2201f2fSdrahn else if (s->sym_type == mmo_undef_sym)
2259d2201f2fSdrahn c->section = bfd_und_section_ptr;
2260d2201f2fSdrahn else if (s->sym_type == mmo_reg_sym)
2261d2201f2fSdrahn {
2262d2201f2fSdrahn c->section
2263d2201f2fSdrahn = bfd_make_section_old_way (abfd, MMIX_REG_SECTION_NAME);
2264d2201f2fSdrahn }
2265d2201f2fSdrahn else
2266d2201f2fSdrahn {
2267d2201f2fSdrahn asection *textsec
2268d2201f2fSdrahn = bfd_get_section_by_name (abfd, MMO_TEXT_SECTION_NAME);
2269d2201f2fSdrahn
2270d2201f2fSdrahn if (textsec != NULL
2271d2201f2fSdrahn && c->value >= textsec->vma
2272d2201f2fSdrahn && c->value <= textsec->vma + textsec->_cooked_size)
2273d2201f2fSdrahn {
2274d2201f2fSdrahn c->section = textsec;
2275d2201f2fSdrahn c->value -= c->section->vma;
2276d2201f2fSdrahn }
2277d2201f2fSdrahn else
2278d2201f2fSdrahn c->section = bfd_abs_section_ptr;
2279d2201f2fSdrahn }
2280d2201f2fSdrahn
2281d2201f2fSdrahn c->udata.p = NULL;
2282d2201f2fSdrahn }
2283d2201f2fSdrahn }
2284d2201f2fSdrahn
2285d2201f2fSdrahn /* Last, overwrite the incoming table with the right-type entries. */
2286d2201f2fSdrahn for (i = 0; i < symcount; i++)
2287d2201f2fSdrahn *alocation++ = csymbols++;
2288d2201f2fSdrahn *alocation = NULL;
2289d2201f2fSdrahn
2290d2201f2fSdrahn return symcount;
2291d2201f2fSdrahn }
2292d2201f2fSdrahn
2293d2201f2fSdrahn /* Get information about a symbol. */
2294d2201f2fSdrahn
2295d2201f2fSdrahn static void
mmo_get_symbol_info(ignore_abfd,symbol,ret)2296d2201f2fSdrahn mmo_get_symbol_info (ignore_abfd, symbol, ret)
2297d2201f2fSdrahn bfd *ignore_abfd ATTRIBUTE_UNUSED;
2298d2201f2fSdrahn asymbol *symbol;
2299d2201f2fSdrahn symbol_info *ret;
2300d2201f2fSdrahn {
2301d2201f2fSdrahn bfd_symbol_info (symbol, ret);
2302d2201f2fSdrahn }
2303d2201f2fSdrahn
2304d2201f2fSdrahn static void
mmo_print_symbol(abfd,afile,symbol,how)2305d2201f2fSdrahn mmo_print_symbol (abfd, afile, symbol, how)
2306d2201f2fSdrahn bfd *abfd;
2307d2201f2fSdrahn PTR afile;
2308d2201f2fSdrahn asymbol *symbol;
2309d2201f2fSdrahn bfd_print_symbol_type how;
2310d2201f2fSdrahn {
2311d2201f2fSdrahn FILE *file = (FILE *) afile;
2312d2201f2fSdrahn
2313d2201f2fSdrahn switch (how)
2314d2201f2fSdrahn {
2315d2201f2fSdrahn case bfd_print_symbol_name:
2316d2201f2fSdrahn fprintf (file, "%s", symbol->name);
2317d2201f2fSdrahn break;
2318d2201f2fSdrahn default:
2319d2201f2fSdrahn bfd_print_symbol_vandf (abfd, (PTR) file, symbol);
2320d2201f2fSdrahn
2321d2201f2fSdrahn fprintf (file, " %-5s %s",
2322d2201f2fSdrahn symbol->section->name,
2323d2201f2fSdrahn symbol->name);
2324d2201f2fSdrahn }
2325d2201f2fSdrahn }
2326d2201f2fSdrahn
2327d2201f2fSdrahn /* We can't map a file directly into executable code, so the
2328d2201f2fSdrahn size of header information is irrelevant. */
2329d2201f2fSdrahn
2330d2201f2fSdrahn static int
mmo_sizeof_headers(abfd,exec)2331d2201f2fSdrahn mmo_sizeof_headers (abfd, exec)
2332d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
2333d2201f2fSdrahn bfd_boolean exec ATTRIBUTE_UNUSED;
2334d2201f2fSdrahn {
2335d2201f2fSdrahn return 0;
2336d2201f2fSdrahn }
2337d2201f2fSdrahn
2338d2201f2fSdrahn /* Write the (section-neutral) file preamble. */
2339d2201f2fSdrahn
2340d2201f2fSdrahn static bfd_boolean
mmo_internal_write_header(abfd)2341d2201f2fSdrahn mmo_internal_write_header (abfd)
2342d2201f2fSdrahn bfd *abfd;
2343d2201f2fSdrahn {
2344d2201f2fSdrahn const char lop_pre_bfd[] = { LOP, LOP_PRE, 1, 1};
2345d2201f2fSdrahn
2346d2201f2fSdrahn if (bfd_bwrite (lop_pre_bfd, 4, abfd) != 4)
2347d2201f2fSdrahn return FALSE;
2348d2201f2fSdrahn
2349d2201f2fSdrahn /* Copy creation time of original file. */
2350d2201f2fSdrahn if (bfd_bwrite (abfd->tdata.mmo_data->created, 4, abfd) != 4)
2351d2201f2fSdrahn return FALSE;
2352d2201f2fSdrahn
2353d2201f2fSdrahn return TRUE;
2354d2201f2fSdrahn }
2355d2201f2fSdrahn
2356d2201f2fSdrahn /* Write the LOP_POST record, with global register initializations.
2357d2201f2fSdrahn Z is the Z field of the LOP_POST, corresponding to 255 - number of
2358d2201f2fSdrahn registers at DATA. The Z = 255 field is filled in with the
2359d2201f2fSdrahn start-address. */
2360d2201f2fSdrahn
2361d2201f2fSdrahn static bfd_boolean
mmo_internal_write_post(abfd,z,sec)2362d2201f2fSdrahn mmo_internal_write_post (abfd, z, sec)
2363d2201f2fSdrahn bfd *abfd;
2364d2201f2fSdrahn int z;
2365d2201f2fSdrahn asection *sec;
2366d2201f2fSdrahn {
2367d2201f2fSdrahn int i;
2368d2201f2fSdrahn bfd_byte buf[8];
2369d2201f2fSdrahn mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_POST << 16) | z);
2370d2201f2fSdrahn
2371d2201f2fSdrahn for (i = z; i < 255; i++)
2372d2201f2fSdrahn {
2373d2201f2fSdrahn bfd_byte *data = mmo_get_loc (sec, i * 8, 8);
2374d2201f2fSdrahn
2375d2201f2fSdrahn if (bfd_bwrite (data, 8, abfd) != 8)
2376d2201f2fSdrahn return FALSE;
2377d2201f2fSdrahn }
2378d2201f2fSdrahn
2379d2201f2fSdrahn /* For Z == $255, we always emit the start location; supposedly Main,
2380d2201f2fSdrahn but we have it handy at bfd_get_start_address. If we're called with
2381d2201f2fSdrahn Z == 255, don't assume DATA is valid. */
2382d2201f2fSdrahn bfd_put_64 (abfd, bfd_get_start_address (abfd), buf);
2383d2201f2fSdrahn
2384d2201f2fSdrahn return ! abfd->tdata.mmo_data->have_error && bfd_bwrite (buf, 8, abfd) == 8;
2385d2201f2fSdrahn }
2386d2201f2fSdrahn
2387d2201f2fSdrahn /* Translate to and from BFD flags. This is to make sure that we don't
2388d2201f2fSdrahn get bitten by BFD flag number changes. */
2389d2201f2fSdrahn
2390d2201f2fSdrahn static flagword
mmo_sec_flags_from_bfd_flags(flags)2391d2201f2fSdrahn mmo_sec_flags_from_bfd_flags (flags)
2392d2201f2fSdrahn flagword flags;
2393d2201f2fSdrahn {
2394d2201f2fSdrahn flagword oflags = 0;
2395d2201f2fSdrahn
2396d2201f2fSdrahn if (flags & SEC_ALLOC)
2397d2201f2fSdrahn oflags |= MMO_SEC_ALLOC;
2398d2201f2fSdrahn if (flags & SEC_LOAD)
2399d2201f2fSdrahn oflags |= MMO_SEC_LOAD;
2400d2201f2fSdrahn if (flags & SEC_RELOC)
2401d2201f2fSdrahn oflags |= MMO_SEC_RELOC;
2402d2201f2fSdrahn if (flags & SEC_READONLY)
2403d2201f2fSdrahn oflags |= MMO_SEC_READONLY;
2404d2201f2fSdrahn if (flags & SEC_CODE)
2405d2201f2fSdrahn oflags |= MMO_SEC_CODE;
2406d2201f2fSdrahn if (flags & SEC_DATA)
2407d2201f2fSdrahn oflags |= MMO_SEC_DATA;
2408d2201f2fSdrahn if (flags & SEC_NEVER_LOAD)
2409d2201f2fSdrahn oflags |= MMO_SEC_NEVER_LOAD;
2410d2201f2fSdrahn if (flags & SEC_IS_COMMON)
2411d2201f2fSdrahn oflags |= MMO_SEC_IS_COMMON;
2412d2201f2fSdrahn if (flags & SEC_DEBUGGING)
2413d2201f2fSdrahn oflags |= MMO_SEC_DEBUGGING;
2414d2201f2fSdrahn
2415d2201f2fSdrahn return oflags;
2416d2201f2fSdrahn }
2417d2201f2fSdrahn
2418d2201f2fSdrahn static flagword
bfd_sec_flags_from_mmo_flags(flags)2419d2201f2fSdrahn bfd_sec_flags_from_mmo_flags (flags)
2420d2201f2fSdrahn flagword flags;
2421d2201f2fSdrahn {
2422d2201f2fSdrahn flagword oflags = 0;
2423d2201f2fSdrahn
2424d2201f2fSdrahn if (flags & MMO_SEC_ALLOC)
2425d2201f2fSdrahn oflags |= SEC_ALLOC;
2426d2201f2fSdrahn if (flags & MMO_SEC_LOAD)
2427d2201f2fSdrahn oflags |= SEC_LOAD;
2428d2201f2fSdrahn if (flags & MMO_SEC_RELOC)
2429d2201f2fSdrahn oflags |= SEC_RELOC;
2430d2201f2fSdrahn if (flags & MMO_SEC_READONLY)
2431d2201f2fSdrahn oflags |= SEC_READONLY;
2432d2201f2fSdrahn if (flags & MMO_SEC_CODE)
2433d2201f2fSdrahn oflags |= SEC_CODE;
2434d2201f2fSdrahn if (flags & MMO_SEC_DATA)
2435d2201f2fSdrahn oflags |= SEC_DATA;
2436d2201f2fSdrahn if (flags & MMO_SEC_NEVER_LOAD)
2437d2201f2fSdrahn oflags |= SEC_NEVER_LOAD;
2438d2201f2fSdrahn if (flags & MMO_SEC_IS_COMMON)
2439d2201f2fSdrahn oflags |= SEC_IS_COMMON;
2440d2201f2fSdrahn if (flags & MMO_SEC_DEBUGGING)
2441d2201f2fSdrahn oflags |= SEC_DEBUGGING;
2442d2201f2fSdrahn
2443d2201f2fSdrahn return oflags;
2444d2201f2fSdrahn }
2445d2201f2fSdrahn
2446d2201f2fSdrahn /* Write a section. */
2447d2201f2fSdrahn
2448d2201f2fSdrahn static bfd_boolean
mmo_internal_write_section(abfd,sec)2449d2201f2fSdrahn mmo_internal_write_section (abfd, sec)
2450d2201f2fSdrahn bfd *abfd;
2451d2201f2fSdrahn asection *sec;
2452d2201f2fSdrahn {
2453d2201f2fSdrahn /* We do it differently depending on what section this is:
2454d2201f2fSdrahn
2455d2201f2fSdrahn ".text": Output, prepended by information about the first source file
2456d2201f2fSdrahn (not yet implemented.)
2457d2201f2fSdrahn
2458d2201f2fSdrahn ".data": Output.
2459d2201f2fSdrahn
2460d2201f2fSdrahn (".MMIX.reg_contents": Not handled here.)
2461d2201f2fSdrahn
2462d2201f2fSdrahn Anything else: Output inside a lop_spec 80, in the format described
2463d2201f2fSdrahn above. */
2464d2201f2fSdrahn
2465d2201f2fSdrahn if (strcmp (sec->name, MMO_TEXT_SECTION_NAME) == 0)
2466d2201f2fSdrahn /* FIXME: Output source file name and line number. */
2467d2201f2fSdrahn return mmo_write_loc_chunk_list (abfd, mmo_section_data (sec)->head);
2468d2201f2fSdrahn else if (strcmp (sec->name, MMO_DATA_SECTION_NAME) == 0)
2469d2201f2fSdrahn return mmo_write_loc_chunk_list (abfd, mmo_section_data (sec)->head);
2470d2201f2fSdrahn else if (strcmp (sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
2471d2201f2fSdrahn /* Not handled here. */
2472d2201f2fSdrahn {
2473d2201f2fSdrahn /* This would normally be an abort call since this can't happen, but
2474d2201f2fSdrahn we don't do that. */
2475d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2476d2201f2fSdrahn return FALSE;
2477d2201f2fSdrahn }
2478d2201f2fSdrahn else if (strncmp (sec->name, MMIX_OTHER_SPEC_SECTION_PREFIX,
2479d2201f2fSdrahn strlen (MMIX_OTHER_SPEC_SECTION_PREFIX)) == 0)
2480d2201f2fSdrahn {
2481d2201f2fSdrahn int n = atoi (sec->name + strlen (MMIX_OTHER_SPEC_SECTION_PREFIX));
2482d2201f2fSdrahn mmo_write_tetra_raw (abfd, (LOP << 24) | (LOP_SPEC << 16) | n);
2483d2201f2fSdrahn return (! abfd->tdata.mmo_data->have_error
2484d2201f2fSdrahn && mmo_write_chunk_list (abfd, mmo_section_data (sec)->head));
2485d2201f2fSdrahn }
2486d2201f2fSdrahn /* Ignore sections that are just allocated or empty; we write out
2487d2201f2fSdrahn _contents_ here. */
2488d2201f2fSdrahn else if ((bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS) != 0
2489d2201f2fSdrahn && sec->_raw_size != 0)
2490d2201f2fSdrahn {
2491d2201f2fSdrahn /* Keep the document-comment formatted the way it is. */
2492d2201f2fSdrahn /*
2493d2201f2fSdrahn INODE
2494d2201f2fSdrahn mmo section mapping, , Symbol-table, mmo
2495d2201f2fSdrahn SUBSECTION
2496d2201f2fSdrahn mmo section mapping
2497d2201f2fSdrahn
2498d2201f2fSdrahn The implementation in BFD uses special data type 80 (decimal) to
2499d2201f2fSdrahn encapsulate and describe named sections, containing e.g.@: debug
2500d2201f2fSdrahn information. If needed, any datum in the encapsulation will be
2501d2201f2fSdrahn quoted using lop_quote. First comes a 32-bit word holding the
2502d2201f2fSdrahn number of 32-bit words containing the zero-terminated zero-padded
2503d2201f2fSdrahn segment name. After the name there's a 32-bit word holding flags
2504d2201f2fSdrahn describing the section type. Then comes a 64-bit big-endian word
2505d2201f2fSdrahn with the section length (in bytes), then another with the section
2506d2201f2fSdrahn start address. Depending on the type of section, the contents
2507d2201f2fSdrahn might follow, zero-padded to 32-bit boundary. For a loadable
2508d2201f2fSdrahn section (such as data or code), the contents might follow at some
2509d2201f2fSdrahn later point, not necessarily immediately, as a lop_loc with the
2510d2201f2fSdrahn same start address as in the section description, followed by the
2511d2201f2fSdrahn contents. This in effect forms a descriptor that must be emitted
2512d2201f2fSdrahn before the actual contents. Sections described this way must not
2513d2201f2fSdrahn overlap.
2514d2201f2fSdrahn
2515d2201f2fSdrahn For areas that don't have such descriptors, synthetic sections are
2516d2201f2fSdrahn formed by BFD. Consecutive contents in the two memory areas
2517d2201f2fSdrahn @samp{0x0000@dots{}00} to @samp{0x01ff@dots{}ff} and
2518d2201f2fSdrahn @samp{0x2000@dots{}00} to @samp{0x20ff@dots{}ff} are entered in
2519d2201f2fSdrahn sections named <<.text>> and <<.data>> respectively. If an area
2520d2201f2fSdrahn is not otherwise described, but would together with a neighboring
2521d2201f2fSdrahn lower area be less than @samp{0x40000000} bytes long, it is joined
2522d2201f2fSdrahn with the lower area and the gap is zero-filled. For other cases,
2523d2201f2fSdrahn a new section is formed, named <<.MMIX.sec.@var{n}>>. Here,
2524d2201f2fSdrahn @var{n} is a number, a running count through the mmo file,
2525d2201f2fSdrahn starting at 0.
2526d2201f2fSdrahn
2527d2201f2fSdrahn EXAMPLE
2528d2201f2fSdrahn A loadable section specified as:
2529d2201f2fSdrahn
2530d2201f2fSdrahn | .section secname,"ax"
2531d2201f2fSdrahn | TETRA 1,2,3,4,-1,-2009
2532d2201f2fSdrahn | BYTE 80
2533d2201f2fSdrahn
2534d2201f2fSdrahn and linked to address @samp{0x4}, is represented by the sequence:
2535d2201f2fSdrahn
2536d2201f2fSdrahn | 0x98080050 - lop_spec 80
2537d2201f2fSdrahn | 0x00000002 - two 32-bit words for the section name
2538d2201f2fSdrahn | 0x7365636e - "secn"
2539d2201f2fSdrahn | 0x616d6500 - "ame\0"
2540d2201f2fSdrahn | 0x00000033 - flags CODE, READONLY, LOAD, ALLOC
2541d2201f2fSdrahn | 0x00000000 - high 32 bits of section length
2542d2201f2fSdrahn | 0x0000001c - section length is 28 bytes; 6 * 4 + 1 + alignment to 32 bits
2543d2201f2fSdrahn | 0x00000000 - high 32 bits of section address
2544d2201f2fSdrahn | 0x00000004 - section address is 4
2545d2201f2fSdrahn | 0x98010002 - 64 bits with address of following data
2546d2201f2fSdrahn | 0x00000000 - high 32 bits of address
2547d2201f2fSdrahn | 0x00000004 - low 32 bits: data starts at address 4
2548d2201f2fSdrahn | 0x00000001 - 1
2549d2201f2fSdrahn | 0x00000002 - 2
2550d2201f2fSdrahn | 0x00000003 - 3
2551d2201f2fSdrahn | 0x00000004 - 4
2552d2201f2fSdrahn | 0xffffffff - -1
2553d2201f2fSdrahn | 0xfffff827 - -2009
2554d2201f2fSdrahn | 0x50000000 - 80 as a byte, padded with zeros.
2555d2201f2fSdrahn
2556d2201f2fSdrahn Note that the lop_spec wrapping does not include the section
2557d2201f2fSdrahn contents. Compare this to a non-loaded section specified as:
2558d2201f2fSdrahn
2559d2201f2fSdrahn | .section thirdsec
2560d2201f2fSdrahn | TETRA 200001,100002
2561d2201f2fSdrahn | BYTE 38,40
2562d2201f2fSdrahn
2563d2201f2fSdrahn This, when linked to address @samp{0x200000000000001c}, is
2564d2201f2fSdrahn represented by:
2565d2201f2fSdrahn
2566d2201f2fSdrahn | 0x98080050 - lop_spec 80
2567d2201f2fSdrahn | 0x00000002 - two 32-bit words for the section name
2568d2201f2fSdrahn | 0x7365636e - "thir"
2569d2201f2fSdrahn | 0x616d6500 - "dsec"
2570d2201f2fSdrahn | 0x00000010 - flag READONLY
2571d2201f2fSdrahn | 0x00000000 - high 32 bits of section length
2572d2201f2fSdrahn | 0x0000000c - section length is 12 bytes; 2 * 4 + 2 + alignment to 32 bits
2573d2201f2fSdrahn | 0x20000000 - high 32 bits of address
2574d2201f2fSdrahn | 0x0000001c - low 32 bits of address 0x200000000000001c
2575d2201f2fSdrahn | 0x00030d41 - 200001
2576d2201f2fSdrahn | 0x000186a2 - 100002
2577d2201f2fSdrahn | 0x26280000 - 38, 40 as bytes, padded with zeros
2578d2201f2fSdrahn
2579d2201f2fSdrahn For the latter example, the section contents must not be
2580d2201f2fSdrahn loaded in memory, and is therefore specified as part of the
2581d2201f2fSdrahn special data. The address is usually unimportant but might
2582d2201f2fSdrahn provide information for e.g.@: the DWARF 2 debugging format. */
2583d2201f2fSdrahn
2584d2201f2fSdrahn mmo_write_tetra_raw (abfd, LOP_SPEC_SECTION);
2585d2201f2fSdrahn mmo_write_tetra (abfd, (strlen (sec->name) + 3) / 4);
2586d2201f2fSdrahn mmo_write_chunk (abfd, sec->name, strlen (sec->name));
2587d2201f2fSdrahn mmo_flush_chunk (abfd);
2588d2201f2fSdrahn /* FIXME: We can get debug sections (.debug_line & Co.) with a
2589d2201f2fSdrahn section flag still having SEC_RELOC set. Investigate. This
2590d2201f2fSdrahn might be true for all alien sections; perhaps mmo.em should clear
2591d2201f2fSdrahn that flag. Might be related to weak references. */
2592d2201f2fSdrahn mmo_write_tetra (abfd,
2593d2201f2fSdrahn mmo_sec_flags_from_bfd_flags
2594d2201f2fSdrahn (bfd_get_section_flags (abfd, sec)));
2595d2201f2fSdrahn mmo_write_octa (abfd, sec->_raw_size);
2596d2201f2fSdrahn mmo_write_octa (abfd, bfd_get_section_vma (abfd, sec));
2597d2201f2fSdrahn
2598d2201f2fSdrahn /* Writing a LOP_LOC ends the LOP_SPEC data, and makes data actually
2599d2201f2fSdrahn loaded. */
2600d2201f2fSdrahn if (bfd_get_section_flags (abfd, sec) & SEC_LOAD)
2601d2201f2fSdrahn return (! abfd->tdata.mmo_data->have_error
2602d2201f2fSdrahn && mmo_write_loc_chunk_list (abfd,
2603d2201f2fSdrahn mmo_section_data (sec)->head));
2604d2201f2fSdrahn return (! abfd->tdata.mmo_data->have_error
2605d2201f2fSdrahn && mmo_write_chunk_list (abfd, mmo_section_data (sec)->head));
2606d2201f2fSdrahn }
2607d2201f2fSdrahn return TRUE;
2608d2201f2fSdrahn }
2609d2201f2fSdrahn
2610d2201f2fSdrahn /* We save up all data before output. */
2611d2201f2fSdrahn
2612d2201f2fSdrahn static bfd_boolean
mmo_set_section_contents(abfd,sec,location,offset,bytes_to_do)2613d2201f2fSdrahn mmo_set_section_contents (abfd, sec, location, offset, bytes_to_do)
2614d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
2615d2201f2fSdrahn sec_ptr sec;
2616*cf2f2c56Smiod const PTR location;
2617d2201f2fSdrahn file_ptr offset;
2618d2201f2fSdrahn bfd_size_type bytes_to_do;
2619d2201f2fSdrahn {
2620d2201f2fSdrahn /* Iterate over diminishing chunk sizes, copying contents. */
2621d2201f2fSdrahn while (bytes_to_do)
2622d2201f2fSdrahn {
2623d2201f2fSdrahn /* A minor song-and-dance to make sure we're not bitten by the
2624d2201f2fSdrahn distant possibility of the cast from bfd_vma to int making the
2625d2201f2fSdrahn chunk zero-sized. */
2626d2201f2fSdrahn int chunk_size
2627d2201f2fSdrahn = (int) bytes_to_do != 0 ? bytes_to_do : MMO_SEC_CONTENTS_CHUNK_SIZE;
2628d2201f2fSdrahn bfd_byte *loc;
2629d2201f2fSdrahn
2630d2201f2fSdrahn do
2631d2201f2fSdrahn loc = mmo_get_loc (sec, sec->vma + offset, chunk_size);
2632d2201f2fSdrahn while (loc == NULL && (chunk_size /= 2) != 0);
2633d2201f2fSdrahn
2634d2201f2fSdrahn if (chunk_size == 0)
2635d2201f2fSdrahn return FALSE;
2636d2201f2fSdrahn
2637d2201f2fSdrahn memcpy (loc, location, chunk_size);
2638d2201f2fSdrahn
2639d2201f2fSdrahn location += chunk_size;
2640d2201f2fSdrahn bytes_to_do -= chunk_size;
2641d2201f2fSdrahn offset += chunk_size;
2642d2201f2fSdrahn }
2643d2201f2fSdrahn return TRUE;
2644d2201f2fSdrahn }
2645d2201f2fSdrahn
2646d2201f2fSdrahn /* Add a symbol to a trie-tree. */
2647d2201f2fSdrahn
2648d2201f2fSdrahn static bfd_boolean
mmo_internal_add_3_sym(abfd,rootp,symp)2649d2201f2fSdrahn mmo_internal_add_3_sym (abfd, rootp, symp)
2650d2201f2fSdrahn bfd *abfd;
2651d2201f2fSdrahn struct mmo_symbol_trie *rootp;
2652d2201f2fSdrahn const struct mmo_symbol *symp;
2653d2201f2fSdrahn {
2654d2201f2fSdrahn const char *name = symp->name;
2655d2201f2fSdrahn struct mmo_symbol_trie *trie = rootp;
2656d2201f2fSdrahn struct mmo_symbol_trie **triep = NULL;
2657d2201f2fSdrahn
2658d2201f2fSdrahn while (*name && trie != NULL)
2659d2201f2fSdrahn {
2660d2201f2fSdrahn if (*name < trie->symchar)
2661d2201f2fSdrahn {
2662d2201f2fSdrahn triep = &trie->left;
2663d2201f2fSdrahn trie = trie->left;
2664d2201f2fSdrahn }
2665d2201f2fSdrahn else if (*name > trie->symchar)
2666d2201f2fSdrahn {
2667d2201f2fSdrahn triep = &trie->right;
2668d2201f2fSdrahn trie = trie->right;
2669d2201f2fSdrahn }
2670d2201f2fSdrahn else if (*name == trie->symchar)
2671d2201f2fSdrahn {
2672d2201f2fSdrahn triep = &trie->middle;
2673d2201f2fSdrahn name++;
2674d2201f2fSdrahn
2675d2201f2fSdrahn /* Make sure "trie" points to where we should fill in the
2676d2201f2fSdrahn current symbol whenever we've iterated through "name". We
2677d2201f2fSdrahn would lose the right position if we encounter "foobar" then
2678d2201f2fSdrahn "foo". */
2679d2201f2fSdrahn if (*name)
2680d2201f2fSdrahn trie = trie->middle;
2681d2201f2fSdrahn }
2682d2201f2fSdrahn }
2683d2201f2fSdrahn
2684d2201f2fSdrahn while (*name != 0)
2685d2201f2fSdrahn {
2686d2201f2fSdrahn /* Create middle branches for the rest of the characters. */
2687d2201f2fSdrahn trie = bfd_zalloc (abfd, sizeof (struct mmo_symbol_trie));
2688d2201f2fSdrahn *triep = trie;
2689d2201f2fSdrahn trie->symchar = *name++;
2690d2201f2fSdrahn triep = &trie->middle;
2691d2201f2fSdrahn }
2692d2201f2fSdrahn
2693d2201f2fSdrahn /* We discover a duplicate symbol rather late in the process, but still;
2694d2201f2fSdrahn we discover it and bail out. */
2695d2201f2fSdrahn if (trie->sym.name != NULL)
2696d2201f2fSdrahn {
2697d2201f2fSdrahn (*_bfd_error_handler)
2698d2201f2fSdrahn (_("%s: invalid symbol table: duplicate symbol `%s'\n"),
2699d2201f2fSdrahn bfd_get_filename (abfd), trie->sym.name);
2700d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2701d2201f2fSdrahn return FALSE;
2702d2201f2fSdrahn }
2703d2201f2fSdrahn
2704d2201f2fSdrahn memcpy (&trie->sym, symp, sizeof *symp);
2705d2201f2fSdrahn return TRUE;
2706d2201f2fSdrahn }
2707d2201f2fSdrahn
2708d2201f2fSdrahn /* Find out the length of the serialized version of a trie in bytes. */
2709d2201f2fSdrahn
2710d2201f2fSdrahn static unsigned int
mmo_internal_3_length(abfd,trie)2711d2201f2fSdrahn mmo_internal_3_length (abfd, trie)
2712d2201f2fSdrahn bfd *abfd;
2713d2201f2fSdrahn struct mmo_symbol_trie *trie;
2714d2201f2fSdrahn {
2715d2201f2fSdrahn /* First, one for the control byte. */
2716d2201f2fSdrahn unsigned int length = 1;
2717d2201f2fSdrahn
2718d2201f2fSdrahn if (trie == NULL)
2719d2201f2fSdrahn return 0;
2720d2201f2fSdrahn
2721d2201f2fSdrahn /* Add in the recursion to the left. */
2722d2201f2fSdrahn length += mmo_internal_3_length (abfd, trie->left);
2723d2201f2fSdrahn
2724d2201f2fSdrahn /* Add in the middle trie and the character. */
2725d2201f2fSdrahn length += 1 + mmo_internal_3_length (abfd, trie->middle);
2726d2201f2fSdrahn
2727d2201f2fSdrahn /* Add in the recursion to the right. */
2728d2201f2fSdrahn length += mmo_internal_3_length (abfd, trie->right);
2729d2201f2fSdrahn
2730d2201f2fSdrahn /* Add in bytes for the symbol (if this is an endnode). */
2731d2201f2fSdrahn if (trie->sym.name != NULL)
2732d2201f2fSdrahn {
2733d2201f2fSdrahn unsigned int serno = trie->sym.serno;
2734d2201f2fSdrahn
2735d2201f2fSdrahn /* First what it takes to encode the value. */
2736d2201f2fSdrahn if (trie->sym.sym_type == mmo_reg_sym)
2737d2201f2fSdrahn length++;
2738d2201f2fSdrahn else if (trie->sym.sym_type == mmo_undef_sym)
2739d2201f2fSdrahn length += 2;
2740d2201f2fSdrahn else
2741d2201f2fSdrahn {
2742d2201f2fSdrahn bfd_vma value = trie->sym.value;
2743d2201f2fSdrahn
2744d2201f2fSdrahn /* Coded in one to eight following bytes. */
2745d2201f2fSdrahn if (trie->sym.sym_type == mmo_data_sym)
2746d2201f2fSdrahn value -= (bfd_vma) 0x20 << 56;
2747d2201f2fSdrahn
2748d2201f2fSdrahn do
2749d2201f2fSdrahn {
2750d2201f2fSdrahn value >>= 8;
2751d2201f2fSdrahn length++;
2752d2201f2fSdrahn }
2753d2201f2fSdrahn while (value != 0);
2754d2201f2fSdrahn }
2755d2201f2fSdrahn
2756d2201f2fSdrahn /* Find out what it takes to encode the serial number. */
2757d2201f2fSdrahn do
2758d2201f2fSdrahn {
2759d2201f2fSdrahn serno >>= 7;
2760d2201f2fSdrahn length++;
2761d2201f2fSdrahn }
2762d2201f2fSdrahn while (serno != 0);
2763d2201f2fSdrahn }
2764d2201f2fSdrahn
2765d2201f2fSdrahn return length;
2766d2201f2fSdrahn }
2767d2201f2fSdrahn
2768d2201f2fSdrahn /* Helper function for outputting the serial number of a symbol, output as
2769d2201f2fSdrahn a variant of leb128 (see dwarf2 documentation) which could be called
2770d2201f2fSdrahn beb128. Using a helper function and recursion simplifies debugging. */
2771d2201f2fSdrahn
2772d2201f2fSdrahn static void
mmo_beb128_out(abfd,serno,marker)2773d2201f2fSdrahn mmo_beb128_out (abfd, serno, marker)
2774d2201f2fSdrahn bfd *abfd;
2775d2201f2fSdrahn int serno;
2776d2201f2fSdrahn int marker;
2777d2201f2fSdrahn {
2778d2201f2fSdrahn if (serno & ~0x7f)
2779d2201f2fSdrahn mmo_beb128_out (abfd, serno >> 7, 0);
2780d2201f2fSdrahn mmo_write_byte (abfd, marker | (serno & 0x7f));
2781d2201f2fSdrahn }
2782d2201f2fSdrahn
2783d2201f2fSdrahn /* Serialize a trie. */
2784d2201f2fSdrahn
2785d2201f2fSdrahn static void
mmo_internal_3_dump(abfd,trie)2786d2201f2fSdrahn mmo_internal_3_dump (abfd, trie)
2787d2201f2fSdrahn bfd *abfd;
2788d2201f2fSdrahn struct mmo_symbol_trie *trie;
2789d2201f2fSdrahn {
2790d2201f2fSdrahn bfd_byte control = 0;
2791d2201f2fSdrahn
2792d2201f2fSdrahn if (trie == NULL)
2793d2201f2fSdrahn return;
2794d2201f2fSdrahn
2795d2201f2fSdrahn if (trie->left)
2796d2201f2fSdrahn control |= MMO3_LEFT;
2797d2201f2fSdrahn
2798d2201f2fSdrahn if (trie->middle)
2799d2201f2fSdrahn control |= MMO3_MIDDLE;
2800d2201f2fSdrahn
2801d2201f2fSdrahn if (trie->right)
2802d2201f2fSdrahn control |= MMO3_RIGHT;
2803d2201f2fSdrahn
2804d2201f2fSdrahn if (trie->sym.name != NULL)
2805d2201f2fSdrahn {
2806d2201f2fSdrahn /* Encode the symbol type and length of value bytes. */
2807d2201f2fSdrahn if (trie->sym.sym_type == mmo_reg_sym)
2808d2201f2fSdrahn control |= MMO3_REGQUAL_BITS;
2809d2201f2fSdrahn else if (trie->sym.sym_type == mmo_undef_sym)
2810d2201f2fSdrahn control |= MMO3_UNDEF;
2811d2201f2fSdrahn else
2812d2201f2fSdrahn {
2813d2201f2fSdrahn bfd_vma value = trie->sym.value;
2814d2201f2fSdrahn
2815d2201f2fSdrahn /* Coded in 1..8 following bytes. */
2816d2201f2fSdrahn if (trie->sym.sym_type == mmo_data_sym)
2817d2201f2fSdrahn {
2818d2201f2fSdrahn control |= MMO3_DATA;
2819d2201f2fSdrahn value -= (bfd_vma) 0x20 << 56;
2820d2201f2fSdrahn }
2821d2201f2fSdrahn
2822d2201f2fSdrahn do
2823d2201f2fSdrahn {
2824d2201f2fSdrahn value >>= 8;
2825d2201f2fSdrahn control++;
2826d2201f2fSdrahn }
2827d2201f2fSdrahn while (value != 0);
2828d2201f2fSdrahn }
2829d2201f2fSdrahn }
2830d2201f2fSdrahn
2831d2201f2fSdrahn /* The control byte is output before recursing. */
2832d2201f2fSdrahn mmo_write_byte (abfd, control);
2833d2201f2fSdrahn
2834d2201f2fSdrahn mmo_internal_3_dump (abfd, trie->left);
2835d2201f2fSdrahn
2836d2201f2fSdrahn if (control & MMO3_SYMBITS)
2837d2201f2fSdrahn {
2838d2201f2fSdrahn mmo_write_byte (abfd, trie->symchar);
2839d2201f2fSdrahn
2840d2201f2fSdrahn if (trie->sym.name != NULL)
2841d2201f2fSdrahn {
2842d2201f2fSdrahn if (trie->sym.sym_type == mmo_reg_sym)
2843d2201f2fSdrahn mmo_write_byte (abfd, trie->sym.value);
2844d2201f2fSdrahn else if (trie->sym.sym_type == mmo_undef_sym)
2845d2201f2fSdrahn {
2846d2201f2fSdrahn mmo_write_byte (abfd, 0);
2847d2201f2fSdrahn mmo_write_byte (abfd, 0);
2848d2201f2fSdrahn }
2849d2201f2fSdrahn else
2850d2201f2fSdrahn {
2851d2201f2fSdrahn bfd_vma value = trie->sym.value;
2852d2201f2fSdrahn
2853d2201f2fSdrahn bfd_byte byte_n = control & 15;
2854d2201f2fSdrahn
2855d2201f2fSdrahn /* Coded in 1..8 following bytes. Note that the value is
2856d2201f2fSdrahn shifted out big-endian. */
2857d2201f2fSdrahn if (trie->sym.sym_type == mmo_data_sym)
2858d2201f2fSdrahn {
2859d2201f2fSdrahn value -= (bfd_vma) 0x20 << 56;
2860d2201f2fSdrahn byte_n -= 8;
2861d2201f2fSdrahn }
2862d2201f2fSdrahn
2863d2201f2fSdrahn do
2864d2201f2fSdrahn {
2865d2201f2fSdrahn mmo_write_byte (abfd, (value >> ((byte_n - 1) * 8)) & 0xff);
2866d2201f2fSdrahn byte_n--;
2867d2201f2fSdrahn }
2868d2201f2fSdrahn while (byte_n != 0);
2869d2201f2fSdrahn }
2870d2201f2fSdrahn
2871d2201f2fSdrahn mmo_beb128_out (abfd, trie->sym.serno, 128);
2872d2201f2fSdrahn }
2873d2201f2fSdrahn mmo_internal_3_dump (abfd, trie->middle);
2874d2201f2fSdrahn }
2875d2201f2fSdrahn mmo_internal_3_dump (abfd, trie->right);
2876d2201f2fSdrahn }
2877d2201f2fSdrahn
2878d2201f2fSdrahn /* Write symbols in mmo format. Also write the lop_end terminator. */
2879d2201f2fSdrahn
2880d2201f2fSdrahn static bfd_boolean
mmo_write_symbols_and_terminator(abfd)2881d2201f2fSdrahn mmo_write_symbols_and_terminator (abfd)
2882d2201f2fSdrahn bfd *abfd;
2883d2201f2fSdrahn {
2884d2201f2fSdrahn int count = bfd_get_symcount (abfd);
2885d2201f2fSdrahn asymbol *maintable[2];
2886d2201f2fSdrahn asymbol **table;
2887d2201f2fSdrahn asymbol **orig_table = bfd_get_outsymbols (abfd);
2888d2201f2fSdrahn int serno;
2889d2201f2fSdrahn struct mmo_symbol_trie root;
2890d2201f2fSdrahn int trie_len;
2891d2201f2fSdrahn int i;
2892d2201f2fSdrahn bfd_byte buf[4];
2893d2201f2fSdrahn
2894d2201f2fSdrahn /* Create a symbol for "Main". */
2895d2201f2fSdrahn asymbol *fakemain = bfd_make_empty_symbol (abfd);
2896d2201f2fSdrahn
2897d2201f2fSdrahn fakemain->flags = BSF_GLOBAL;
2898d2201f2fSdrahn fakemain->value = bfd_get_start_address (abfd);
2899d2201f2fSdrahn fakemain->name = MMIX_START_SYMBOL_NAME;
2900d2201f2fSdrahn fakemain->section = bfd_abs_section_ptr;
2901d2201f2fSdrahn maintable[0] = fakemain;
2902d2201f2fSdrahn maintable[1] = NULL;
2903d2201f2fSdrahn
2904d2201f2fSdrahn memset (&root, 0, sizeof (root));
2905d2201f2fSdrahn
2906d2201f2fSdrahn /* Make all symbols take a left turn. */
2907d2201f2fSdrahn root.symchar = 0xff;
2908d2201f2fSdrahn
2909d2201f2fSdrahn /* There must always be a ":Main", so we'll add one if there are no
2910d2201f2fSdrahn symbols. Make sure we have room for it. */
2911d2201f2fSdrahn table = bfd_alloc (abfd, (count + 1) * sizeof (asymbol *));
2912d2201f2fSdrahn if (table == NULL)
2913d2201f2fSdrahn return FALSE;
2914d2201f2fSdrahn
2915d2201f2fSdrahn memcpy (table, orig_table, count * sizeof (asymbol *));
2916d2201f2fSdrahn
2917d2201f2fSdrahn /* Move :Main (if there is one) to the first position. This is
2918d2201f2fSdrahn necessary to get the same layout of the trie-tree when linking as
2919d2201f2fSdrahn when objcopying the result as in the objcopy.exp test "simple objcopy
2920d2201f2fSdrahn of executable". It also automatically takes care of assigning serial
2921d2201f2fSdrahn number 1 to :Main (as is mandatory). */
2922d2201f2fSdrahn for (i = 0; i < count; i++)
2923d2201f2fSdrahn if (table[i] != NULL
2924d2201f2fSdrahn && strcmp (table[i]->name, MMIX_START_SYMBOL_NAME) == 0
2925d2201f2fSdrahn && (table[i]->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL)
2926d2201f2fSdrahn {
2927d2201f2fSdrahn asymbol *mainsym = table[i];
2928d2201f2fSdrahn memcpy (table + 1, orig_table, i * sizeof (asymbol *));
2929d2201f2fSdrahn table[0] = mainsym;
2930d2201f2fSdrahn
2931d2201f2fSdrahn /* Check that the value assigned to :Main is the same as the entry
2932d2201f2fSdrahn address. The default linker script asserts this. This is as
2933d2201f2fSdrahn good a place as any to check this consistency. */
2934d2201f2fSdrahn if ((mainsym->value
2935d2201f2fSdrahn + mainsym->section->output_section->vma
2936d2201f2fSdrahn + mainsym->section->output_offset)
2937d2201f2fSdrahn != bfd_get_start_address (abfd))
2938d2201f2fSdrahn {
2939d2201f2fSdrahn /* Arbitrary buffer to hold the printable representation of a
2940d2201f2fSdrahn vma. */
2941d2201f2fSdrahn char vmas_main[40];
2942d2201f2fSdrahn char vmas_start[40];
2943d2201f2fSdrahn bfd_vma vma_start = bfd_get_start_address (abfd);
2944d2201f2fSdrahn
2945d2201f2fSdrahn sprintf_vma (vmas_main, mainsym->value);
2946d2201f2fSdrahn sprintf_vma (vmas_start, vma_start);
2947d2201f2fSdrahn
2948d2201f2fSdrahn (*_bfd_error_handler)
2949d2201f2fSdrahn (_("%s: Bad symbol definition: `Main' set to %s rather\
2950d2201f2fSdrahn than the start address %s\n"),
2951d2201f2fSdrahn bfd_get_filename (abfd), vmas_main, vmas_start);
2952d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
2953d2201f2fSdrahn return FALSE;
2954d2201f2fSdrahn }
2955d2201f2fSdrahn break;
2956d2201f2fSdrahn }
2957d2201f2fSdrahn if (i == count && count != 0)
2958d2201f2fSdrahn {
2959d2201f2fSdrahn /* When there are symbols, there must be a :Main. There was no
2960d2201f2fSdrahn :Main, so we need to add it manually. */
2961d2201f2fSdrahn memcpy (table + 1, orig_table, count * sizeof (asymbol *));
2962d2201f2fSdrahn table[0] = fakemain;
2963d2201f2fSdrahn count++;
2964d2201f2fSdrahn }
2965d2201f2fSdrahn
2966d2201f2fSdrahn for (i = 0, serno = 1; i < count && table[i] != NULL; i++)
2967d2201f2fSdrahn {
2968d2201f2fSdrahn asymbol *s = table[i];
2969d2201f2fSdrahn
2970d2201f2fSdrahn /* It's not enough to consult bfd_is_local_label, since it does not
2971d2201f2fSdrahn mean "local" in the sense of linkable-and-observable-after-link.
2972d2201f2fSdrahn Let's just check the BSF_GLOBAL flag.
2973d2201f2fSdrahn
2974d2201f2fSdrahn Also, don't export symbols with characters not in the allowed set. */
2975d2201f2fSdrahn if ((s->flags & (BSF_DEBUGGING|BSF_GLOBAL)) == BSF_GLOBAL
2976d2201f2fSdrahn && strspn (s->name,
2977d2201f2fSdrahn valid_mmo_symbol_character_set) == strlen (s->name))
2978d2201f2fSdrahn {
2979d2201f2fSdrahn struct mmo_symbol sym;
2980d2201f2fSdrahn memset (&sym, 0, sizeof (sym));
2981d2201f2fSdrahn
2982d2201f2fSdrahn sym.name = s->name;
2983d2201f2fSdrahn sym.value =
2984d2201f2fSdrahn s->value
2985d2201f2fSdrahn + s->section->output_section->vma
2986d2201f2fSdrahn + s->section->output_offset;
2987d2201f2fSdrahn
2988d2201f2fSdrahn if (bfd_is_und_section (s->section))
2989d2201f2fSdrahn sym.sym_type = mmo_undef_sym;
2990d2201f2fSdrahn else if (strcmp (s->section->name, MMO_DATA_SECTION_NAME) == 0
2991d2201f2fSdrahn /* The encoding of data symbols require that the "rest"
2992d2201f2fSdrahn of the value fits in 6 bytes, so the upper two bytes
2993d2201f2fSdrahn must be 0x2000. All other symbols get to be the
2994d2201f2fSdrahn absolute type. */
2995d2201f2fSdrahn && (sym.value >> 48) == 0x2000)
2996d2201f2fSdrahn sym.sym_type = mmo_data_sym;
2997d2201f2fSdrahn else if (strcmp (s->section->name, MMIX_REG_SECTION_NAME) == 0)
2998d2201f2fSdrahn sym.sym_type = mmo_reg_sym;
2999d2201f2fSdrahn else if (strcmp (s->section->name,
3000d2201f2fSdrahn MMIX_REG_CONTENTS_SECTION_NAME) == 0)
3001d2201f2fSdrahn {
3002d2201f2fSdrahn sym.sym_type = mmo_reg_sym;
3003d2201f2fSdrahn sym.value /= 8;
3004d2201f2fSdrahn }
3005d2201f2fSdrahn else
3006d2201f2fSdrahn sym.sym_type = mmo_abs_sym;
3007d2201f2fSdrahn
3008d2201f2fSdrahn /* FIXME: We assume the order of the received symbols is an
3009d2201f2fSdrahn ordered mapping of the serial numbers. This is not
3010d2201f2fSdrahn necessarily true if we e.g. objcopy a mmo file to another and
3011d2201f2fSdrahn there are gaps in the numbering. Not sure if this can
3012d2201f2fSdrahn happen. Not sure what to do. */
3013d2201f2fSdrahn sym.serno = serno++;
3014d2201f2fSdrahn
3015d2201f2fSdrahn if (! mmo_internal_add_3_sym (abfd, &root, &sym))
3016d2201f2fSdrahn return FALSE;
3017d2201f2fSdrahn }
3018d2201f2fSdrahn }
3019d2201f2fSdrahn
3020d2201f2fSdrahn /* Change the root node to be a ":"-prefix. */
3021d2201f2fSdrahn root.symchar = ':';
3022d2201f2fSdrahn root.middle = root.left;
3023d2201f2fSdrahn root.right = NULL;
3024d2201f2fSdrahn root.left = NULL;
3025d2201f2fSdrahn
3026d2201f2fSdrahn /* We have to find out if we can fit the whole symbol table in the mmo
3027d2201f2fSdrahn symtab. It would be bad to assume we can always fit it in 262144
3028d2201f2fSdrahn bytes. If we can't, just leave the Main symbol. */
3029d2201f2fSdrahn trie_len = (mmo_internal_3_length (abfd, &root) + 3)/4;
3030d2201f2fSdrahn
3031d2201f2fSdrahn if (trie_len > 0xffff)
3032d2201f2fSdrahn {
3033d2201f2fSdrahn /* Test this code by using a lower limit in the test above and check
3034d2201f2fSdrahn that the single "Main" symbol is emitted and handled properly.
3035d2201f2fSdrahn There's no specific test-case. */
3036d2201f2fSdrahn struct mmo_symbol sym;
3037d2201f2fSdrahn
3038d2201f2fSdrahn (*_bfd_error_handler)
3039d2201f2fSdrahn (_("%s: warning: symbol table too large for mmo, larger than 65535\
3040d2201f2fSdrahn 32-bit words: %d. Only `Main' will be emitted.\n"),
3041d2201f2fSdrahn bfd_get_filename (abfd), trie_len);
3042d2201f2fSdrahn
3043d2201f2fSdrahn memset (&sym, 0, sizeof (sym));
3044d2201f2fSdrahn sym.sym_type = mmo_abs_sym;
3045d2201f2fSdrahn sym.name = MMIX_START_SYMBOL_NAME;
3046d2201f2fSdrahn sym.serno = 1;
3047d2201f2fSdrahn sym.value = bfd_get_start_address (abfd);
3048d2201f2fSdrahn
3049d2201f2fSdrahn /* Then patch up a symbol table to be just the ":Main" symbol. */
3050d2201f2fSdrahn memset (&root, 0, sizeof (root));
3051d2201f2fSdrahn root.left = root.middle;
3052d2201f2fSdrahn root.symchar = 0xff;
3053d2201f2fSdrahn root.middle = NULL;
3054d2201f2fSdrahn root.right = NULL;
3055d2201f2fSdrahn
3056d2201f2fSdrahn if (! mmo_internal_add_3_sym (abfd, &root, &sym))
3057d2201f2fSdrahn return FALSE;
3058d2201f2fSdrahn
3059d2201f2fSdrahn root.symchar = ':';
3060d2201f2fSdrahn root.middle = root.left;
3061d2201f2fSdrahn root.right = NULL;
3062d2201f2fSdrahn root.left = NULL;
3063d2201f2fSdrahn
3064d2201f2fSdrahn trie_len = (mmo_internal_3_length (abfd, &root) + 3)/4;
3065d2201f2fSdrahn }
3066d2201f2fSdrahn
3067d2201f2fSdrahn /* Reset the written-bytes counter. */
3068d2201f2fSdrahn abfd->tdata.mmo_data->byte_no = 0;
3069d2201f2fSdrahn
3070d2201f2fSdrahn /* Put out the lop_stab mark. */
3071d2201f2fSdrahn bfd_put_32 (abfd, (LOP << 24) | (LOP_STAB << 16), buf);
3072d2201f2fSdrahn if (bfd_bwrite (buf, 4, abfd) != 4)
3073d2201f2fSdrahn return FALSE;
3074d2201f2fSdrahn
3075d2201f2fSdrahn /* Dump out symbols. */
3076d2201f2fSdrahn mmo_internal_3_dump (abfd, &root);
3077d2201f2fSdrahn
3078d2201f2fSdrahn if (trie_len != (abfd->tdata.mmo_data->byte_no + 3)/4)
3079d2201f2fSdrahn {
3080d2201f2fSdrahn /* I haven't seen this trig. It seems no use claiming this case
3081d2201f2fSdrahn isn't debugged and abort if we get here. Instead emit a
3082d2201f2fSdrahn diagnostic and fail "normally". */
3083d2201f2fSdrahn (*_bfd_error_handler)
3084d2201f2fSdrahn (_("%s: internal error, symbol table changed size from %d to %d\
3085d2201f2fSdrahn words\n"),
3086d2201f2fSdrahn bfd_get_filename (abfd), trie_len,
3087d2201f2fSdrahn (abfd->tdata.mmo_data->byte_no + 3)/4);
3088d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
3089d2201f2fSdrahn return FALSE;
3090d2201f2fSdrahn }
3091d2201f2fSdrahn
3092d2201f2fSdrahn /* Dump out remaining bytes in the buffer and handle I/O errors by
3093d2201f2fSdrahn propagating errors. */
3094d2201f2fSdrahn if ((abfd->tdata.mmo_data->byte_no % 4) != 0
3095d2201f2fSdrahn || abfd->tdata.mmo_data->have_error)
3096d2201f2fSdrahn {
3097d2201f2fSdrahn memset (abfd->tdata.mmo_data->buf + (abfd->tdata.mmo_data->byte_no % 4),
3098d2201f2fSdrahn 0, 4 - (abfd->tdata.mmo_data->byte_no % 4));
3099d2201f2fSdrahn
3100d2201f2fSdrahn if (abfd->tdata.mmo_data->have_error
3101d2201f2fSdrahn || bfd_bwrite (abfd->tdata.mmo_data->buf, 4, abfd) != 4)
3102d2201f2fSdrahn return FALSE;
3103d2201f2fSdrahn }
3104d2201f2fSdrahn
3105d2201f2fSdrahn bfd_put_32 (abfd, (LOP << 24) | (LOP_END << 16) | trie_len, buf);
3106d2201f2fSdrahn return bfd_bwrite (buf, 4, abfd) == 4;
3107d2201f2fSdrahn }
3108d2201f2fSdrahn
3109d2201f2fSdrahn /* Write section unless it is the register contents section. For that, we
3110d2201f2fSdrahn instead store the section in the supplied pointer. This function is
3111d2201f2fSdrahn used through bfd_map_over_sections. */
3112d2201f2fSdrahn
3113d2201f2fSdrahn static void
mmo_write_section_unless_reg_contents(abfd,sec,p)3114d2201f2fSdrahn mmo_write_section_unless_reg_contents (abfd, sec, p)
3115d2201f2fSdrahn bfd *abfd;
3116d2201f2fSdrahn asection *sec;
3117d2201f2fSdrahn PTR p;
3118d2201f2fSdrahn {
3119d2201f2fSdrahn struct mmo_write_sec_info *infop = (struct mmo_write_sec_info *) p;
3120d2201f2fSdrahn
3121d2201f2fSdrahn if (! infop->retval)
3122d2201f2fSdrahn return;
3123d2201f2fSdrahn
3124d2201f2fSdrahn if (strcmp (sec->name, MMIX_REG_CONTENTS_SECTION_NAME) == 0)
3125d2201f2fSdrahn {
3126d2201f2fSdrahn infop->reg_section = sec;
3127d2201f2fSdrahn return;
3128d2201f2fSdrahn }
3129d2201f2fSdrahn
3130d2201f2fSdrahn /* Exclude the convenience register section. */
3131d2201f2fSdrahn if (strcmp (sec->name, MMIX_REG_SECTION_NAME) == 0)
3132d2201f2fSdrahn {
3133d2201f2fSdrahn if (bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)
3134d2201f2fSdrahn {
3135d2201f2fSdrahn /* Make sure it hasn't got contents. It seems impossible to
3136d2201f2fSdrahn make it carry contents, so we don't have a test-case for
3137d2201f2fSdrahn this. */
3138d2201f2fSdrahn (*_bfd_error_handler)
3139d2201f2fSdrahn (_("%s: internal error, internal register section %s had\
3140d2201f2fSdrahn contents\n"),
3141d2201f2fSdrahn bfd_get_filename (abfd), sec->name);
3142d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
3143d2201f2fSdrahn infop->retval = FALSE;
3144d2201f2fSdrahn return;
3145d2201f2fSdrahn }
3146d2201f2fSdrahn
3147d2201f2fSdrahn return;
3148d2201f2fSdrahn }
3149d2201f2fSdrahn
3150d2201f2fSdrahn infop->retval = mmo_internal_write_section (abfd, sec);
3151d2201f2fSdrahn }
3152d2201f2fSdrahn
3153d2201f2fSdrahn /* Do the actual output of a file. Assumes mmo_set_section_contents is
3154d2201f2fSdrahn already called. */
3155d2201f2fSdrahn
3156d2201f2fSdrahn static bfd_boolean
mmo_write_object_contents(abfd)3157d2201f2fSdrahn mmo_write_object_contents (abfd)
3158d2201f2fSdrahn bfd *abfd;
3159d2201f2fSdrahn {
3160d2201f2fSdrahn struct mmo_write_sec_info wsecinfo;
3161d2201f2fSdrahn
3162d2201f2fSdrahn /* First, there are a few words of preamble. */
3163d2201f2fSdrahn if (! mmo_internal_write_header (abfd))
3164d2201f2fSdrahn return FALSE;
3165d2201f2fSdrahn
3166d2201f2fSdrahn wsecinfo.reg_section = NULL;
3167d2201f2fSdrahn wsecinfo.retval = TRUE;
3168d2201f2fSdrahn
3169d2201f2fSdrahn bfd_map_over_sections (abfd, mmo_write_section_unless_reg_contents,
3170d2201f2fSdrahn (PTR) &wsecinfo);
3171d2201f2fSdrahn
3172d2201f2fSdrahn if (! wsecinfo.retval)
3173d2201f2fSdrahn return FALSE;
3174d2201f2fSdrahn
3175d2201f2fSdrahn if (wsecinfo.reg_section != NULL)
3176d2201f2fSdrahn {
3177d2201f2fSdrahn asection *sec = wsecinfo.reg_section;
3178d2201f2fSdrahn unsigned int z = (unsigned int) (sec->vma / 8);
3179d2201f2fSdrahn
3180d2201f2fSdrahn /* Registers 0..31 must not be global. Do sanity check on the "vma"
3181d2201f2fSdrahn of the register contents section and check that it corresponds to
3182d2201f2fSdrahn the length of the section. */
3183d2201f2fSdrahn if (z < 32 || z >= 255 || (sec->vma & 7) != 0
3184d2201f2fSdrahn || sec->vma != 256 * 8 - sec->_raw_size - 8)
3185d2201f2fSdrahn {
3186d2201f2fSdrahn bfd_set_error (bfd_error_bad_value);
3187d2201f2fSdrahn
3188d2201f2fSdrahn if (sec->_raw_size == 0)
3189d2201f2fSdrahn /* There must always be at least one such register. */
3190d2201f2fSdrahn (*_bfd_error_handler)
3191d2201f2fSdrahn (_("%s: no initialized registers; section length 0\n"),
3192d2201f2fSdrahn bfd_get_filename (abfd));
3193d2201f2fSdrahn else if (sec->vma > (256 - 32) * 8)
3194d2201f2fSdrahn /* Provide better error message for the case of too many
3195d2201f2fSdrahn global registers. */
3196d2201f2fSdrahn (*_bfd_error_handler)
3197d2201f2fSdrahn (_("%s: too many initialized registers; section length %ld\n"),
3198d2201f2fSdrahn bfd_get_filename (abfd),
3199d2201f2fSdrahn (long) sec->_raw_size);
3200d2201f2fSdrahn else
3201d2201f2fSdrahn (*_bfd_error_handler)
3202d2201f2fSdrahn (_("%s: invalid start address for initialized registers of\
3203d2201f2fSdrahn length %ld: 0x%lx%08lx\n"),
3204d2201f2fSdrahn bfd_get_filename (abfd),
3205d2201f2fSdrahn (long) sec->_raw_size,
3206d2201f2fSdrahn (unsigned long) (sec->vma >> 32), (unsigned long) (sec->vma));
3207d2201f2fSdrahn
3208d2201f2fSdrahn return FALSE;
3209d2201f2fSdrahn }
3210d2201f2fSdrahn
3211d2201f2fSdrahn if (! mmo_internal_write_post (abfd, z, sec))
3212d2201f2fSdrahn return FALSE;
3213d2201f2fSdrahn }
3214d2201f2fSdrahn else
3215d2201f2fSdrahn if (! mmo_internal_write_post (abfd, 255, NULL))
3216d2201f2fSdrahn return FALSE;
3217d2201f2fSdrahn
3218d2201f2fSdrahn return mmo_write_symbols_and_terminator (abfd);
3219d2201f2fSdrahn }
3220d2201f2fSdrahn
3221d2201f2fSdrahn /* Return the size of a NULL pointer, so we support linking in an mmo
3222d2201f2fSdrahn object. */
3223d2201f2fSdrahn
3224d2201f2fSdrahn static long
mmo_get_reloc_upper_bound(abfd,sec)3225d2201f2fSdrahn mmo_get_reloc_upper_bound (abfd, sec)
3226d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
3227d2201f2fSdrahn asection *sec ATTRIBUTE_UNUSED;
3228d2201f2fSdrahn {
3229d2201f2fSdrahn return sizeof (PTR);
3230d2201f2fSdrahn }
3231d2201f2fSdrahn
3232d2201f2fSdrahn /* Similarly canonicalize relocs to empty, filling in the terminating NULL
3233d2201f2fSdrahn pointer. */
3234d2201f2fSdrahn
3235d2201f2fSdrahn long
mmo_canonicalize_reloc(abfd,section,relptr,symbols)3236d2201f2fSdrahn mmo_canonicalize_reloc (abfd, section, relptr, symbols)
3237d2201f2fSdrahn bfd *abfd ATTRIBUTE_UNUSED;
3238d2201f2fSdrahn sec_ptr section ATTRIBUTE_UNUSED;
3239d2201f2fSdrahn arelent **relptr;
3240d2201f2fSdrahn asymbol **symbols ATTRIBUTE_UNUSED;
3241d2201f2fSdrahn {
3242d2201f2fSdrahn *relptr = NULL;
3243d2201f2fSdrahn return 0;
3244d2201f2fSdrahn }
3245d2201f2fSdrahn
3246d2201f2fSdrahn /* If there's anything in particular in a mmo bfd that we want to free,
3247d2201f2fSdrahn make this a real function. Only do this if you see major memory
3248d2201f2fSdrahn thrashing; zealous free:ing will cause unwanted behavior, especially if
3249d2201f2fSdrahn you "free" memory allocated with "bfd_alloc", or even "bfd_release" a
3250d2201f2fSdrahn block allocated with "bfd_alloc"; they're really allocated from an
3251d2201f2fSdrahn obstack, and we don't know what was allocated there since this
3252d2201f2fSdrahn particular allocation. */
3253d2201f2fSdrahn
3254d2201f2fSdrahn #define mmo_close_and_cleanup _bfd_generic_close_and_cleanup
3255d2201f2fSdrahn #define mmo_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
3256d2201f2fSdrahn
3257d2201f2fSdrahn /* Perhaps we need to adjust this one; mmo labels (originally) without a
3258d2201f2fSdrahn leading ':' might more appropriately be called local. */
3259d2201f2fSdrahn #define mmo_bfd_is_local_label_name bfd_generic_is_local_label_name
3260d2201f2fSdrahn
3261d2201f2fSdrahn /* Is this one really used or defined by anyone? */
3262d2201f2fSdrahn #define mmo_get_lineno _bfd_nosymbols_get_lineno
3263d2201f2fSdrahn
3264d2201f2fSdrahn /* FIXME: We can do better on this one, if we have a dwarf2 .debug_line
3265d2201f2fSdrahn section or if MMO line numbers are implemented. */
3266d2201f2fSdrahn #define mmo_find_nearest_line _bfd_nosymbols_find_nearest_line
3267d2201f2fSdrahn #define mmo_make_empty_symbol _bfd_generic_make_empty_symbol
3268d2201f2fSdrahn #define mmo_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
3269d2201f2fSdrahn #define mmo_read_minisymbols _bfd_generic_read_minisymbols
3270d2201f2fSdrahn #define mmo_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
3271d2201f2fSdrahn
3272d2201f2fSdrahn #define mmo_get_section_contents_in_window \
3273d2201f2fSdrahn _bfd_generic_get_section_contents_in_window
3274d2201f2fSdrahn #define mmo_bfd_get_relocated_section_contents \
3275d2201f2fSdrahn bfd_generic_get_relocated_section_contents
3276d2201f2fSdrahn #define mmo_bfd_gc_sections bfd_generic_gc_sections
3277d2201f2fSdrahn #define mmo_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
3278d2201f2fSdrahn #define mmo_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
3279d2201f2fSdrahn #define mmo_bfd_link_add_symbols _bfd_generic_link_add_symbols
3280d2201f2fSdrahn #define mmo_bfd_link_just_syms _bfd_generic_link_just_syms
3281d2201f2fSdrahn #define mmo_bfd_final_link _bfd_generic_final_link
3282d2201f2fSdrahn #define mmo_bfd_link_split_section _bfd_generic_link_split_section
3283d2201f2fSdrahn
3284d2201f2fSdrahn /* Strictly speaking, only MMIX uses this restricted format, but let's not
3285d2201f2fSdrahn stop anybody from shooting themselves in the foot. */
3286d2201f2fSdrahn #define mmo_set_arch_mach bfd_default_set_arch_mach
3287d2201f2fSdrahn #define mmo_bfd_relax_section bfd_generic_relax_section
3288d2201f2fSdrahn #define mmo_bfd_merge_sections bfd_generic_merge_sections
3289d2201f2fSdrahn #define mmo_bfd_discard_group bfd_generic_discard_group
3290d2201f2fSdrahn
3291d2201f2fSdrahn /* objcopy will be upset if we return -1 from bfd_get_reloc_upper_bound by
3292d2201f2fSdrahn using BFD_JUMP_TABLE_RELOCS (_bfd_norelocs) rather than 0. FIXME: Most
3293d2201f2fSdrahn likely a bug in the _bfd_norelocs definition.
3294d2201f2fSdrahn
3295d2201f2fSdrahn On the other hand, we smuggle in an mmo object (because setting up ELF
3296d2201f2fSdrahn is too cumbersome) when linking (from other formats, presumably ELF) to
3297d2201f2fSdrahn represent the g255 entry. We need to link that object, so need to say
3298d2201f2fSdrahn it has no relocs. Upper bound for the size of the relocation table is
3299d2201f2fSdrahn the size of a NULL pointer, and we support "canonicalization" for that
3300d2201f2fSdrahn pointer. */
3301d2201f2fSdrahn #define mmo_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup
3302d2201f2fSdrahn
3303d2201f2fSdrahn /* We want to copy time of creation, otherwise we'd use
3304d2201f2fSdrahn BFD_JUMP_TABLE_COPY (_bfd_generic). */
3305d2201f2fSdrahn #define mmo_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
3306d2201f2fSdrahn #define mmo_bfd_copy_private_section_data _bfd_generic_bfd_copy_private_section_data
3307d2201f2fSdrahn #define mmo_bfd_copy_private_symbol_data _bfd_generic_bfd_copy_private_symbol_data
3308d2201f2fSdrahn #define mmo_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
3309d2201f2fSdrahn #define mmo_bfd_print_private_bfd_data _bfd_generic_bfd_print_private_bfd_data
3310d2201f2fSdrahn
3311d2201f2fSdrahn const bfd_target bfd_mmo_vec =
3312d2201f2fSdrahn {
3313d2201f2fSdrahn "mmo", /* name */
3314d2201f2fSdrahn bfd_target_mmo_flavour,
3315d2201f2fSdrahn BFD_ENDIAN_BIG, /* target byte order */
3316d2201f2fSdrahn BFD_ENDIAN_BIG, /* target headers byte order */
3317d2201f2fSdrahn
3318d2201f2fSdrahn /* FIXME: Might need adjustments. */
3319d2201f2fSdrahn (HAS_RELOC | EXEC_P | /* object flags */
3320d2201f2fSdrahn HAS_LINENO | HAS_DEBUG |
3321d2201f2fSdrahn HAS_SYMS | HAS_LOCALS | WP_TEXT),
3322d2201f2fSdrahn
3323d2201f2fSdrahn /* FIXME: Might need adjustments. */
3324d2201f2fSdrahn (SEC_CODE | SEC_DATA | SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
3325d2201f2fSdrahn | SEC_READONLY | SEC_EXCLUDE | SEC_DEBUGGING | SEC_IN_MEMORY),
3326d2201f2fSdrahn /* section flags */
3327d2201f2fSdrahn 0, /* leading underscore */
3328d2201f2fSdrahn ' ', /* ar_pad_char */
3329d2201f2fSdrahn 16, /* ar_max_namelen */
3330d2201f2fSdrahn bfd_getb64, bfd_getb_signed_64, bfd_putb64,
3331d2201f2fSdrahn bfd_getb32, bfd_getb_signed_32, bfd_putb32,
3332d2201f2fSdrahn bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */
3333d2201f2fSdrahn bfd_getb64, bfd_getb_signed_64, bfd_putb64,
3334d2201f2fSdrahn bfd_getb32, bfd_getb_signed_32, bfd_putb32,
3335d2201f2fSdrahn bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */
3336d2201f2fSdrahn
3337d2201f2fSdrahn {
3338d2201f2fSdrahn _bfd_dummy_target,
3339d2201f2fSdrahn mmo_object_p, /* bfd_check_format */
3340d2201f2fSdrahn _bfd_dummy_target,
3341d2201f2fSdrahn _bfd_dummy_target,
3342d2201f2fSdrahn },
3343d2201f2fSdrahn {
3344d2201f2fSdrahn bfd_false,
3345d2201f2fSdrahn mmo_mkobject,
3346d2201f2fSdrahn bfd_false,
3347d2201f2fSdrahn bfd_false,
3348d2201f2fSdrahn },
3349d2201f2fSdrahn { /* bfd_write_contents */
3350d2201f2fSdrahn bfd_false,
3351d2201f2fSdrahn mmo_write_object_contents,
3352d2201f2fSdrahn bfd_false,
3353d2201f2fSdrahn bfd_false,
3354d2201f2fSdrahn },
3355d2201f2fSdrahn
3356d2201f2fSdrahn BFD_JUMP_TABLE_GENERIC (mmo),
3357d2201f2fSdrahn BFD_JUMP_TABLE_COPY (mmo),
3358d2201f2fSdrahn BFD_JUMP_TABLE_CORE (_bfd_nocore),
3359d2201f2fSdrahn BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
3360d2201f2fSdrahn BFD_JUMP_TABLE_SYMBOLS (mmo),
3361d2201f2fSdrahn /* We have to provide a valid method for getting relocs, returning zero,
3362d2201f2fSdrahn so we can't say BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */
3363d2201f2fSdrahn BFD_JUMP_TABLE_RELOCS (mmo),
3364d2201f2fSdrahn BFD_JUMP_TABLE_WRITE (mmo),
3365d2201f2fSdrahn BFD_JUMP_TABLE_LINK (mmo),
3366d2201f2fSdrahn BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
3367d2201f2fSdrahn
3368d2201f2fSdrahn NULL,
3369d2201f2fSdrahn
3370d2201f2fSdrahn NULL
3371d2201f2fSdrahn };
3372