]>
Commit | Line | Data |
---|---|---|
e09108e1 | 1 | /* LTO routines to use object files. |
fbd26352 | 2 | Copyright (C) 2010-2019 Free Software Foundation, Inc. |
e09108e1 | 3 | Written by Ian Lance Taylor, Google. |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 3, or (at your option) any later | |
10 | version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | #include "config.h" | |
22 | #include "system.h" | |
23 | #include "coretypes.h" | |
94ea8568 | 24 | #include "tm.h" |
4cba6f60 | 25 | #include "diagnostic-core.h" |
e09108e1 | 26 | #include "lto.h" |
47131315 | 27 | #include "lto-section-names.h" |
e09108e1 | 28 | #include "simple-object.h" |
29 | ||
e09108e1 | 30 | /* An LTO file wrapped around an simple_object. */ |
31 | ||
32 | struct lto_simple_object | |
33 | { | |
34 | /* The base information. */ | |
35 | lto_file base; | |
36 | ||
37 | /* The system file descriptor. */ | |
38 | int fd; | |
39 | ||
40 | /* The simple_object if we are reading the file. */ | |
41 | simple_object_read *sobj_r; | |
42 | ||
43 | /* The simple_object if we are writing the file. */ | |
44 | simple_object_write *sobj_w; | |
45 | ||
46 | /* The currently active section. */ | |
47 | simple_object_write_section *section; | |
48 | }; | |
49 | ||
50 | /* Saved simple_object attributes. FIXME: Once set, this is never | |
51 | cleared. */ | |
52 | ||
53 | static simple_object_attributes *saved_attributes; | |
54 | ||
55 | /* Initialize FILE, an LTO file object for FILENAME. */ | |
56 | ||
57 | static void | |
58 | lto_file_init (lto_file *file, const char *filename, off_t offset) | |
59 | { | |
60 | file->filename = filename; | |
61 | file->offset = offset; | |
62 | } | |
63 | ||
64 | /* Open the file FILENAME. It WRITABLE is true, the file is opened | |
65 | for write and, if necessary, created. Otherwise, the file is | |
66 | opened for reading. Returns the opened file. */ | |
67 | ||
68 | lto_file * | |
69 | lto_obj_file_open (const char *filename, bool writable) | |
70 | { | |
71 | const char *offset_p; | |
72 | long loffset; | |
73 | int consumed; | |
74 | char *fname; | |
75 | off_t offset; | |
76 | struct lto_simple_object *lo; | |
77 | const char *errmsg; | |
78 | int err; | |
79 | ||
80 | offset_p = strrchr (filename, '@'); | |
81 | if (offset_p != NULL | |
82 | && offset_p != filename | |
83 | && sscanf (offset_p, "@%li%n", &loffset, &consumed) >= 1 | |
84 | && strlen (offset_p) == (unsigned int) consumed) | |
85 | { | |
86 | fname = XNEWVEC (char, offset_p - filename + 1); | |
87 | memcpy (fname, filename, offset_p - filename); | |
88 | fname[offset_p - filename] = '\0'; | |
89 | offset = (off_t) loffset; | |
90 | } | |
91 | else | |
92 | { | |
93 | fname = xstrdup (filename); | |
94 | offset = 0; | |
95 | } | |
96 | ||
97 | lo = XCNEW (struct lto_simple_object); | |
98 | lto_file_init ((lto_file *) lo, fname, offset); | |
99 | ||
100 | lo->fd = open (fname, | |
101 | (writable | |
102 | ? O_WRONLY | O_CREAT | O_BINARY | |
103 | : O_RDONLY | O_BINARY), | |
104 | 0666); | |
105 | if (lo->fd == -1) | |
106 | { | |
107 | error ("open %s failed: %s", fname, xstrerror (errno)); | |
108 | goto fail; | |
109 | } | |
110 | ||
111 | if (!writable) | |
112 | { | |
113 | simple_object_attributes *attrs; | |
114 | ||
115 | lo->sobj_r = simple_object_start_read (lo->fd, offset, LTO_SEGMENT_NAME, | |
116 | &errmsg, &err); | |
117 | if (lo->sobj_r == NULL) | |
118 | goto fail_errmsg; | |
119 | ||
120 | attrs = simple_object_fetch_attributes (lo->sobj_r, &errmsg, &err); | |
121 | if (attrs == NULL) | |
122 | goto fail_errmsg; | |
123 | ||
124 | if (saved_attributes == NULL) | |
125 | saved_attributes = attrs; | |
126 | else | |
127 | { | |
2e521e13 | 128 | errmsg = simple_object_attributes_merge (saved_attributes, attrs, |
129 | &err); | |
e09108e1 | 130 | if (errmsg != NULL) |
883554eb | 131 | { |
132 | free (attrs); | |
133 | goto fail_errmsg; | |
134 | } | |
e09108e1 | 135 | } |
136 | } | |
137 | else | |
138 | { | |
139 | gcc_assert (saved_attributes != NULL); | |
140 | lo->sobj_w = simple_object_start_write (saved_attributes, | |
141 | LTO_SEGMENT_NAME, | |
142 | &errmsg, &err); | |
143 | if (lo->sobj_w == NULL) | |
144 | goto fail_errmsg; | |
145 | } | |
146 | ||
147 | return &lo->base; | |
148 | ||
149 | fail_errmsg: | |
150 | if (err == 0) | |
151 | error ("%s: %s", fname, errmsg); | |
152 | else | |
153 | error ("%s: %s: %s", fname, errmsg, xstrerror (err)); | |
154 | ||
155 | fail: | |
883554eb | 156 | if (lo->fd != -1) |
e09108e1 | 157 | lto_obj_file_close ((lto_file *) lo); |
883554eb | 158 | free (lo); |
e09108e1 | 159 | return NULL; |
160 | } | |
161 | ||
883554eb | 162 | |
e09108e1 | 163 | /* Close FILE. If FILE was opened for writing, it is written out |
164 | now. */ | |
165 | ||
166 | void | |
167 | lto_obj_file_close (lto_file *file) | |
168 | { | |
169 | struct lto_simple_object *lo = (struct lto_simple_object *) file; | |
170 | ||
171 | if (lo->sobj_r != NULL) | |
172 | simple_object_release_read (lo->sobj_r); | |
173 | else if (lo->sobj_w != NULL) | |
174 | { | |
175 | const char *errmsg; | |
176 | int err; | |
177 | ||
178 | gcc_assert (lo->base.offset == 0); | |
179 | ||
180 | errmsg = simple_object_write_to_file (lo->sobj_w, lo->fd, &err); | |
181 | if (errmsg != NULL) | |
182 | { | |
183 | if (err == 0) | |
c05be867 | 184 | fatal_error (input_location, "%s", errmsg); |
e09108e1 | 185 | else |
c05be867 | 186 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (err)); |
e09108e1 | 187 | } |
188 | ||
189 | simple_object_release_write (lo->sobj_w); | |
190 | } | |
191 | ||
192 | if (lo->fd != -1) | |
193 | { | |
194 | if (close (lo->fd) < 0) | |
c05be867 | 195 | fatal_error (input_location, "close: %s", xstrerror (errno)); |
e09108e1 | 196 | } |
197 | } | |
198 | ||
199 | /* This is passed to lto_obj_add_section. */ | |
200 | ||
201 | struct lto_obj_add_section_data | |
202 | { | |
203 | /* The hash table of sections. */ | |
204 | htab_t section_hash_table; | |
205 | /* The offset of this file. */ | |
206 | off_t base_offset; | |
805389b2 | 207 | /* List in linker order */ |
208 | struct lto_section_list *list; | |
e09108e1 | 209 | }; |
210 | ||
211 | /* This is called for each section in the file. */ | |
212 | ||
213 | static int | |
214 | lto_obj_add_section (void *data, const char *name, off_t offset, | |
215 | off_t length) | |
216 | { | |
217 | struct lto_obj_add_section_data *loasd = | |
218 | (struct lto_obj_add_section_data *) data; | |
219 | htab_t section_hash_table = (htab_t) loasd->section_hash_table; | |
220 | char *new_name; | |
221 | struct lto_section_slot s_slot; | |
222 | void **slot; | |
805389b2 | 223 | struct lto_section_list *list = loasd->list; |
e09108e1 | 224 | |
b0c5e347 | 225 | if (strncmp (name, section_name_prefix, strlen (section_name_prefix))) |
e09108e1 | 226 | return 1; |
227 | ||
228 | new_name = xstrdup (name); | |
229 | s_slot.name = new_name; | |
230 | slot = htab_find_slot (section_hash_table, &s_slot, INSERT); | |
231 | if (*slot == NULL) | |
232 | { | |
805389b2 | 233 | struct lto_section_slot *new_slot = XCNEW (struct lto_section_slot); |
e09108e1 | 234 | |
235 | new_slot->name = new_name; | |
236 | new_slot->start = loasd->base_offset + offset; | |
237 | new_slot->len = length; | |
238 | *slot = new_slot; | |
805389b2 | 239 | |
240 | if (list != NULL) | |
241 | { | |
242 | if (!list->first) | |
243 | list->first = new_slot; | |
244 | if (list->last) | |
245 | list->last->next = new_slot; | |
246 | list->last = new_slot; | |
247 | } | |
e09108e1 | 248 | } |
249 | else | |
250 | { | |
251 | error ("two or more sections for %s", new_name); | |
252 | return 0; | |
253 | } | |
254 | ||
255 | return 1; | |
256 | } | |
257 | ||
258 | /* Build a hash table whose key is the section name and whose data is | |
259 | the start and size of each section in the .o file. */ | |
260 | ||
261 | htab_t | |
805389b2 | 262 | lto_obj_build_section_table (lto_file *lto_file, struct lto_section_list *list) |
e09108e1 | 263 | { |
264 | struct lto_simple_object *lo = (struct lto_simple_object *) lto_file; | |
265 | htab_t section_hash_table; | |
266 | struct lto_obj_add_section_data loasd; | |
267 | const char *errmsg; | |
268 | int err; | |
269 | ||
270 | section_hash_table = lto_obj_create_section_hash_table (); | |
271 | ||
272 | gcc_assert (lo->sobj_r != NULL && lo->sobj_w == NULL); | |
273 | loasd.section_hash_table = section_hash_table; | |
274 | loasd.base_offset = lo->base.offset; | |
805389b2 | 275 | loasd.list = list; |
e09108e1 | 276 | errmsg = simple_object_find_sections (lo->sobj_r, lto_obj_add_section, |
277 | &loasd, &err); | |
278 | if (errmsg != NULL) | |
279 | { | |
280 | if (err == 0) | |
281 | error ("%s", errmsg); | |
282 | else | |
283 | error ("%s: %s", errmsg, xstrerror (err)); | |
284 | htab_delete (section_hash_table); | |
285 | return NULL; | |
286 | } | |
287 | ||
288 | return section_hash_table; | |
289 | } | |
290 | ||
291 | /* The current output file. */ | |
292 | ||
293 | static lto_file *current_out_file; | |
294 | ||
295 | /* Set the current output file. Return the old one. */ | |
296 | ||
297 | lto_file * | |
298 | lto_set_current_out_file (lto_file *file) | |
299 | { | |
300 | lto_file *old_file; | |
301 | ||
302 | old_file = current_out_file; | |
303 | current_out_file = file; | |
304 | return old_file; | |
305 | } | |
306 | ||
307 | /* Return the current output file. */ | |
308 | ||
309 | lto_file * | |
310 | lto_get_current_out_file (void) | |
311 | { | |
312 | return current_out_file; | |
313 | } | |
314 | ||
315 | /* Begin writing a new section named NAME in the current output | |
316 | file. */ | |
317 | ||
318 | void | |
319 | lto_obj_begin_section (const char *name) | |
320 | { | |
321 | struct lto_simple_object *lo; | |
322 | int align; | |
323 | const char *errmsg; | |
324 | int err; | |
325 | ||
326 | lo = (struct lto_simple_object *) current_out_file; | |
327 | gcc_assert (lo != NULL | |
328 | && lo->sobj_r == NULL | |
329 | && lo->sobj_w != NULL | |
330 | && lo->section == NULL); | |
331 | ||
c219a638 | 332 | align = ceil_log2 (POINTER_SIZE_UNITS); |
e09108e1 | 333 | lo->section = simple_object_write_create_section (lo->sobj_w, name, align, |
334 | &errmsg, &err); | |
335 | if (lo->section == NULL) | |
336 | { | |
337 | if (err == 0) | |
c05be867 | 338 | fatal_error (input_location, "%s", errmsg); |
e09108e1 | 339 | else |
c05be867 | 340 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno)); |
e09108e1 | 341 | } |
342 | } | |
343 | ||
344 | /* Add data to a section. BLOCK is a pointer to memory containing | |
345 | DATA. */ | |
346 | ||
347 | void | |
2d97af95 | 348 | lto_obj_append_data (const void *data, size_t len, void *) |
e09108e1 | 349 | { |
350 | struct lto_simple_object *lo; | |
351 | const char *errmsg; | |
352 | int err; | |
353 | ||
354 | lo = (struct lto_simple_object *) current_out_file; | |
355 | gcc_assert (lo != NULL && lo->section != NULL); | |
356 | ||
357 | errmsg = simple_object_write_add_data (lo->sobj_w, lo->section, data, len, | |
358 | 1, &err); | |
359 | if (errmsg != NULL) | |
360 | { | |
361 | if (err == 0) | |
c05be867 | 362 | fatal_error (input_location, "%s", errmsg); |
e09108e1 | 363 | else |
c05be867 | 364 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno)); |
e09108e1 | 365 | } |
e09108e1 | 366 | } |
367 | ||
368 | /* Stop writing to the current output section. */ | |
369 | ||
370 | void | |
371 | lto_obj_end_section (void) | |
372 | { | |
373 | struct lto_simple_object *lo; | |
374 | ||
375 | lo = (struct lto_simple_object *) current_out_file; | |
376 | gcc_assert (lo != NULL && lo->section != NULL); | |
377 | lo->section = NULL; | |
378 | } |