aboutsummaryrefslogtreecommitdiff
path: root/gcc/lto/lto-coff.h
blob: 5792f3dc5965624b4ccf81179f4117dbcfd52d3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/* LTO routines for COFF object files.
   Copyright 2009 Free Software Foundation, Inc.
   Contributed by Dave Korn.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#ifndef LTO_COFF_H
#define LTO_COFF_H

/* Rather than implementing a libcoff to match libelf, or attempting to
   integrate libbfd into GCC, this file is a self-contained (and very
   minimal) COFF format object file reader/writer.  The generated files
   will contain a COFF header, a number of COFF section headers, the 
   section data itself, and a trailing string table for section names.  */

/* Alignment of sections in a COFF object file.

   The LTO writer uses zlib compression on the data that it streams into
   LTO sections in the output object file.  Because these streams don't
   have any embedded size information, the section in the object file must
   be exactly sized to the data emitted; any trailing padding bytes will
   be interpreted as partial and/or corrupt compressed data.

   This is easy enough to do on COFF targets (with binutils 2.20.1 or
   above) because we can specify 1-byte alignment for the LTO sections.
   They are then emitted precisely-sized and byte-packed into the object
   and the reader is happy when it parses them later.  This is currently
   implemented in the x86/windows backed in i386_pe_asm_named_section()
   in config/i386/winnt.c by detecting the LTO section name prefix, 

   That would be sufficient, but for one thing.  At the start of the LTO
   data is a header struct with (currently) a couple of version numbers and
   some type info; see struct lto_header in lto-streamer.h.  If the sections
   are byte-packed, this header will not necessarily be correctly-aligned
   when it is read back into memory.

   On x86 targets, which are currently the only LTO-COFF targets, misaligned
   memory accesses aren't problematic (okay, inefficient, but not worth
   worrying about two half-word memory reads per section in the context of
   everything else the compiler has to do at the time!), but RISC targets may
   fail on trying to access the header struct.  In this case, it will be
   necessary to enable (preferably in a target-dependent fashion, but a few
   bytes of padding are hardly an important issue if it comes down to it) the
   COFF_ALIGNMENT macros below.

   As currently implemented, this will emit padding to the necessary number
   of bytes after each LTO section.  These bytes will constitute 'gaps' in
   the object file structure, as they won't be covered by any section header.
   This hasn't yet been tested, because no such RISC LTO-COFF target yet
   exists.  If it causes problems further down the toolchain, it will be
   necessary to adapt the code to emit additional section headers for these
   padding bytes, but the odds are that it will "just work".

  */

#if 0
#define COFF_ALIGNMENT	 (4)
#define COFF_ALIGNMENTM1 (COFF_ALIGNMENT - 1)
#define COFF_ALIGN(x)	 (((x) + COFF_ALIGNMENTM1) & ~COFF_ALIGNMENTM1)
#else
#define COFF_ALIGNMENT	 (1)
#define COFF_ALIGN(x)	 (x)
#endif

/* COFF header machine codes.  */

#define IMAGE_FILE_MACHINE_I386	(0x014c)
#define IMAGE_FILE_MACHINE_ADM64 (0x8664)

/* Known header magics for validation, as an array initialiser.  */

#define COFF_KNOWN_MACHINES \
  { IMAGE_FILE_MACHINE_I386, \
    IMAGE_FILE_MACHINE_ADM64/*, ... add more here when working.  */ }

/* COFF object file header, section and symbol flags and types.  These are
   currently specific to PE-COFF, which is the only LTO-COFF format at the
   time of writing.  Maintainers adding support for new COFF formats will
   need to make these into target macros of some kind.  */

/* COFF header characteristics.  */

#define IMAGE_FILE_EXECUTABLE_IMAGE	(1 << 1)
#define IMAGE_FILE_32BIT_MACHINE	(1 << 8)
#define IMAGE_FILE_SYSTEM		(1 << 12)
#define IMAGE_FILE_DLL			(1 << 13)

/* Desired characteristics (for validation).  */

#define COFF_CHARACTERISTICS \
  (IMAGE_FILE_32BIT_MACHINE)

/* Unwanted characteristics (for validation).  */

#define COFF_NOT_CHARACTERISTICS \
  (IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL)

/* Section flags.  LTO emits byte-aligned read-only loadable data sections.  */

#define IMAGE_SCN_CNT_INITIALIZED_DATA	 (1 << 6)
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA (1 << 7)
#define IMAGE_SCN_ALIGN_1BYTES		 (0x1 << 20)
#define IMAGE_SCN_MEM_DISCARDABLE	 (1 << 25)
#define	IMAGE_SCN_MEM_SHARED		 (1 << 28)
#define IMAGE_SCN_MEM_READ		 (1 << 30)

#define COFF_SECTION_CHARACTERISTICS \
  (IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | \
  IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED | IMAGE_SCN_MEM_READ)

/* Symbol-related constants.  */

#define IMAGE_SYM_DEBUG		(-2)
#define IMAGE_SYM_TYPE_NULL	(0)
#define IMAGE_SYM_DTYPE_NULL	(0)
#define IMAGE_SYM_CLASS_STATIC	(3)
#define IMAGE_SYM_CLASS_FILE	(103)

#define IMAGE_SYM_TYPE \
  ((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL)

/* Size of a COFF symbol in bytes.  */

#define COFF_SYMBOL_SIZE	(18)

/* On-disk file structures.  */

struct Coff_header
{
  unsigned char Machine[2];
  unsigned char NumberOfSections[2];
  unsigned char TimeDateStamp[4];
  unsigned char PointerToSymbolTable[4];
  unsigned char NumberOfSymbols[4];
  unsigned char SizeOfOptionalHeader[2];
  unsigned char Characteristics[2];
};
typedef struct Coff_header Coff_header;

struct Coff_section
{
  unsigned char Name[8];
  unsigned char VirtualSize[4];
  unsigned char VirtualAddress[4];
  unsigned char SizeOfRawData[4];
  unsigned char PointerToRawData[4];
  unsigned char PointerToRelocations[4];
  unsigned char PointerToLinenumbers[4];
  unsigned char NumberOfRelocations[2];
  unsigned char NumberOfLinenumbers[2];
  unsigned char Characteristics[4];
};
typedef struct Coff_section Coff_section;

struct Coff_symbol
{
  unsigned char Name[8];
  unsigned char Value[4];
  unsigned char SectionNumber[2];
  unsigned char Type[2];
  unsigned char StorageClass[1];
  unsigned char NumberOfAuxSymbols[1];
};
typedef struct Coff_symbol Coff_symbol;

struct Coff_aux_sym_file
{
  unsigned char FileName[18];
};
typedef struct Coff_aux_sym_file Coff_aux_sym_file;

struct Coff_aux_sym_section
{
  unsigned char Length[4];
  unsigned char NumberOfRelocations[2];
  unsigned char NumberOfLineNumbers[2];
  unsigned char Checksum[4];
  unsigned char Number[2];
  unsigned char Selection[1];
  unsigned char Unused[3];
};
typedef struct Coff_aux_sym_section Coff_aux_sym_section;

/* Accessor macros for the above structures.  */

#define COFF_GET(struc,memb) \
  ((COFFENDIAN ? get_be : get_le) (&(struc)->memb[0], sizeof ((struc)->memb)))

#define COFF_PUT(struc,memb,val) \
  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[0], sizeof ((struc)->memb), val))

#define COFF_PUT_NDXSZ(struc,memb,val,ndx,sz) \
  ((COFFENDIAN ? put_be : put_le) (&(struc)->memb[ndx], sz, val))

/* In-memory file structures.  */

/* Forward declared structs.  */

struct lto_coff_data;
struct lto_coff_section;
struct lto_coff_file;

/* Section data in output files is made of these.  */

struct lto_coff_data
{
  /* Pointer to data block.  */
  void *d_buf;

  /* Size of data block.  */
  ssize_t d_size;

  /* Next data block for this section.  */
  struct lto_coff_data *next;
};
typedef struct lto_coff_data lto_coff_data;

/* This struct tracks the data for a section.  */

struct lto_coff_section
{
  /* Singly-linked list of section's data blocks.  */
  lto_coff_data *data_chain;

  /* Offset in string table of name.  */
  size_t strtab_offs;

  /* Section type: 0 = real, 1 = dummy.  */
  size_t type;

  /* Section name.  */
  const char *name;

#if COFF_ALIGNMENT > 1
  /* Number of trailing padding bytes needed.  */
  ssize_t pad_needed;
#endif

  /* Raw section header data.  */
  Coff_section coffsec;

  /* Next section for this file.  */
  struct lto_coff_section *next;
};
typedef struct lto_coff_section lto_coff_section;

/* A COFF file.  */

struct lto_coff_file 
{
  /* The base information.  */
  lto_file base;

  /* Common file members:  */

  /* The system file descriptor for the file.  */
  int fd;

  /* The file's overall header.  */
  Coff_header coffhdr;

  /* All sections in a singly-linked list.  */
  lto_coff_section *section_chain;

  /* Readable file members:  */

  /* File total size.  */
  off_t file_size;

  /* String table file offset, relative to base.offset.  */
  off_t strtab_offs;

  /* Writable file members:  */

  /* The currently active section.  */
  lto_coff_section *scn;

  /* The output stream for section header names.  */
  struct lto_output_stream *shstrtab_stream;

  /* Linked list of data which must be freed *after* the file has been
     closed.  This is an annoying limitation of libelf.  Which has been
     faithfully reproduced here.  */
  struct lto_char_ptr_base *data;
};
typedef struct lto_coff_file lto_coff_file;

/* Data hunk iterator.  */

#define COFF_FOR_ALL_DATA(sec,var) \
  for (var = sec->data_chain; var; var = var->next)

/* Section list iterator.  */

#define COFF_FOR_ALL_SECTIONS(file,var) \
  for (var = file->section_chain; var; var = var->next)

/* Very simple endian-ness layer.  */

#ifndef COFFENDIAN
#define COFFENDIAN (BYTES_BIG_ENDIAN)
#endif

static inline unsigned int
get_2_le (const unsigned char *ptr)
{
  return ptr[0] | (ptr[1] << 8);
}

static inline unsigned int
get_4_le (const unsigned char *ptr)
{
  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
}

static inline unsigned int
get_2_be (const unsigned char *ptr)
{
  return ptr[1] | (ptr[0] << 8);
}

static inline unsigned int
get_4_be (const unsigned char *ptr)
{
  return ptr[3] | (ptr[2] << 8) | (ptr[1] << 16) | (ptr[0] << 24);
}

static inline unsigned int
get_be (const unsigned char *ptr, size_t size)
{
  gcc_assert (size == 4 || size == 2);
  return (size == 2) ? get_2_be (ptr) : get_4_be (ptr);
}

static inline unsigned int
get_le (const unsigned char *ptr, size_t size)
{
  gcc_assert (size == 4 || size == 2);
  return (size == 2) ? get_2_le (ptr) : get_4_le (ptr);
}

static inline void
put_2_le (unsigned char *ptr, unsigned int data)
{
  ptr[0] = data & 0xff;
  ptr[1] = (data >> 8) & 0xff;
}

static inline void
put_4_le (unsigned char *ptr, unsigned int data)
{
  ptr[0] = data & 0xff;
  ptr[1] = (data >> 8) & 0xff;
  ptr[2] = (data >> 16) & 0xff;
  ptr[3] = (data >> 24) & 0xff;
}

static inline void
put_2_be (unsigned char *ptr, unsigned int data)
{
  ptr[1] = data & 0xff;
  ptr[0] = (data >> 8) & 0xff;
}

static inline void
put_4_be (unsigned char *ptr, unsigned int data)
{
  ptr[3] = data & 0xff;
  ptr[2] = (data >> 8) & 0xff;
  ptr[1] = (data >> 16) & 0xff;
  ptr[0] = (data >> 24) & 0xff;
}

static inline void
put_le (unsigned char *ptr, size_t size, unsigned int data)
{
  gcc_assert (size == 4 || size == 2);
  (void) (size == 2 ? put_2_le : put_4_le) (ptr, data);
}

static inline void
put_be (unsigned char *ptr, size_t size, unsigned int data)
{
  gcc_assert (size == 4 || size == 2);
  (void) (size == 2 ? put_2_be : put_4_be) (ptr, data);
}

/* We use this for putting the string table size.  */

#define COFF_PUT4(ptr, data) \
  ((COFFENDIAN ? put_4_be : put_4_le) (ptr, data))


#endif /* LTO_COFF_H */