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