]>
Commit | Line | Data |
---|---|---|
6b3456d1 | 1 | /* LTO routines to use object files. |
83ffe9cd | 2 | Copyright (C) 2010-2023 Free Software Foundation, Inc. |
6b3456d1 ILT |
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" | |
60393bbc | 24 | #include "tm.h" |
2adfab87 | 25 | #include "diagnostic-core.h" |
6b3456d1 | 26 | #include "lto.h" |
4000360e | 27 | #include "lto-section-names.h" |
6b3456d1 ILT |
28 | #include "simple-object.h" |
29 | ||
6b3456d1 ILT |
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) | |
9a92e46c | 106 | fatal_error (input_location, "open %s failed: %s", fname, xstrerror (errno)); |
6b3456d1 ILT |
107 | |
108 | if (!writable) | |
109 | { | |
110 | simple_object_attributes *attrs; | |
111 | ||
112 | lo->sobj_r = simple_object_start_read (lo->fd, offset, LTO_SEGMENT_NAME, | |
113 | &errmsg, &err); | |
114 | if (lo->sobj_r == NULL) | |
115 | goto fail_errmsg; | |
116 | ||
117 | attrs = simple_object_fetch_attributes (lo->sobj_r, &errmsg, &err); | |
118 | if (attrs == NULL) | |
119 | goto fail_errmsg; | |
120 | ||
121 | if (saved_attributes == NULL) | |
122 | saved_attributes = attrs; | |
123 | else | |
124 | { | |
d82f74d3 ILT |
125 | errmsg = simple_object_attributes_merge (saved_attributes, attrs, |
126 | &err); | |
6b3456d1 | 127 | if (errmsg != NULL) |
0b8c30f9 TB |
128 | { |
129 | free (attrs); | |
130 | goto fail_errmsg; | |
131 | } | |
6b3456d1 ILT |
132 | } |
133 | } | |
134 | else | |
135 | { | |
136 | gcc_assert (saved_attributes != NULL); | |
137 | lo->sobj_w = simple_object_start_write (saved_attributes, | |
138 | LTO_SEGMENT_NAME, | |
139 | &errmsg, &err); | |
140 | if (lo->sobj_w == NULL) | |
141 | goto fail_errmsg; | |
142 | } | |
143 | ||
144 | return &lo->base; | |
145 | ||
9a92e46c | 146 | fail_errmsg: |
6b3456d1 ILT |
147 | if (err == 0) |
148 | error ("%s: %s", fname, errmsg); | |
149 | else | |
150 | error ("%s: %s: %s", fname, errmsg, xstrerror (err)); | |
151 | ||
0b8c30f9 | 152 | if (lo->fd != -1) |
6b3456d1 | 153 | lto_obj_file_close ((lto_file *) lo); |
0b8c30f9 | 154 | free (lo); |
6b3456d1 ILT |
155 | return NULL; |
156 | } | |
157 | ||
0b8c30f9 | 158 | |
6b3456d1 ILT |
159 | /* Close FILE. If FILE was opened for writing, it is written out |
160 | now. */ | |
161 | ||
162 | void | |
163 | lto_obj_file_close (lto_file *file) | |
164 | { | |
165 | struct lto_simple_object *lo = (struct lto_simple_object *) file; | |
166 | ||
167 | if (lo->sobj_r != NULL) | |
168 | simple_object_release_read (lo->sobj_r); | |
169 | else if (lo->sobj_w != NULL) | |
170 | { | |
171 | const char *errmsg; | |
172 | int err; | |
173 | ||
174 | gcc_assert (lo->base.offset == 0); | |
175 | ||
176 | errmsg = simple_object_write_to_file (lo->sobj_w, lo->fd, &err); | |
177 | if (errmsg != NULL) | |
178 | { | |
179 | if (err == 0) | |
40fecdd6 | 180 | fatal_error (input_location, "%s", errmsg); |
6b3456d1 | 181 | else |
40fecdd6 | 182 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (err)); |
6b3456d1 ILT |
183 | } |
184 | ||
185 | simple_object_release_write (lo->sobj_w); | |
186 | } | |
187 | ||
188 | if (lo->fd != -1) | |
189 | { | |
190 | if (close (lo->fd) < 0) | |
40fecdd6 | 191 | fatal_error (input_location, "close: %s", xstrerror (errno)); |
6b3456d1 ILT |
192 | } |
193 | } | |
194 | ||
195 | /* This is passed to lto_obj_add_section. */ | |
196 | ||
197 | struct lto_obj_add_section_data | |
198 | { | |
199 | /* The hash table of sections. */ | |
200 | htab_t section_hash_table; | |
201 | /* The offset of this file. */ | |
202 | off_t base_offset; | |
c17d253c AK |
203 | /* List in linker order */ |
204 | struct lto_section_list *list; | |
6b3456d1 ILT |
205 | }; |
206 | ||
207 | /* This is called for each section in the file. */ | |
208 | ||
209 | static int | |
210 | lto_obj_add_section (void *data, const char *name, off_t offset, | |
211 | off_t length) | |
212 | { | |
213 | struct lto_obj_add_section_data *loasd = | |
214 | (struct lto_obj_add_section_data *) data; | |
215 | htab_t section_hash_table = (htab_t) loasd->section_hash_table; | |
216 | char *new_name; | |
217 | struct lto_section_slot s_slot; | |
218 | void **slot; | |
c17d253c | 219 | struct lto_section_list *list = loasd->list; |
6b3456d1 | 220 | |
1f6be682 | 221 | if (strncmp (name, section_name_prefix, strlen (section_name_prefix))) |
6b3456d1 ILT |
222 | return 1; |
223 | ||
224 | new_name = xstrdup (name); | |
225 | s_slot.name = new_name; | |
226 | slot = htab_find_slot (section_hash_table, &s_slot, INSERT); | |
227 | if (*slot == NULL) | |
228 | { | |
c17d253c | 229 | struct lto_section_slot *new_slot = XCNEW (struct lto_section_slot); |
6b3456d1 ILT |
230 | |
231 | new_slot->name = new_name; | |
232 | new_slot->start = loasd->base_offset + offset; | |
233 | new_slot->len = length; | |
234 | *slot = new_slot; | |
c17d253c AK |
235 | |
236 | if (list != NULL) | |
237 | { | |
238 | if (!list->first) | |
239 | list->first = new_slot; | |
240 | if (list->last) | |
241 | list->last->next = new_slot; | |
242 | list->last = new_slot; | |
243 | } | |
6b3456d1 ILT |
244 | } |
245 | else | |
246 | { | |
247 | error ("two or more sections for %s", new_name); | |
248 | return 0; | |
249 | } | |
250 | ||
251 | return 1; | |
252 | } | |
253 | ||
254 | /* Build a hash table whose key is the section name and whose data is | |
255 | the start and size of each section in the .o file. */ | |
256 | ||
257 | htab_t | |
c17d253c | 258 | lto_obj_build_section_table (lto_file *lto_file, struct lto_section_list *list) |
6b3456d1 ILT |
259 | { |
260 | struct lto_simple_object *lo = (struct lto_simple_object *) lto_file; | |
261 | htab_t section_hash_table; | |
262 | struct lto_obj_add_section_data loasd; | |
263 | const char *errmsg; | |
264 | int err; | |
265 | ||
266 | section_hash_table = lto_obj_create_section_hash_table (); | |
267 | ||
268 | gcc_assert (lo->sobj_r != NULL && lo->sobj_w == NULL); | |
269 | loasd.section_hash_table = section_hash_table; | |
270 | loasd.base_offset = lo->base.offset; | |
c17d253c | 271 | loasd.list = list; |
6b3456d1 ILT |
272 | errmsg = simple_object_find_sections (lo->sobj_r, lto_obj_add_section, |
273 | &loasd, &err); | |
274 | if (errmsg != NULL) | |
275 | { | |
276 | if (err == 0) | |
277 | error ("%s", errmsg); | |
278 | else | |
279 | error ("%s: %s", errmsg, xstrerror (err)); | |
280 | htab_delete (section_hash_table); | |
281 | return NULL; | |
282 | } | |
283 | ||
284 | return section_hash_table; | |
285 | } | |
286 | ||
287 | /* The current output file. */ | |
288 | ||
289 | static lto_file *current_out_file; | |
290 | ||
291 | /* Set the current output file. Return the old one. */ | |
292 | ||
293 | lto_file * | |
294 | lto_set_current_out_file (lto_file *file) | |
295 | { | |
296 | lto_file *old_file; | |
297 | ||
298 | old_file = current_out_file; | |
299 | current_out_file = file; | |
300 | return old_file; | |
301 | } | |
302 | ||
303 | /* Return the current output file. */ | |
304 | ||
305 | lto_file * | |
306 | lto_get_current_out_file (void) | |
307 | { | |
308 | return current_out_file; | |
309 | } | |
310 | ||
311 | /* Begin writing a new section named NAME in the current output | |
312 | file. */ | |
313 | ||
314 | void | |
315 | lto_obj_begin_section (const char *name) | |
316 | { | |
317 | struct lto_simple_object *lo; | |
318 | int align; | |
319 | const char *errmsg; | |
320 | int err; | |
321 | ||
322 | lo = (struct lto_simple_object *) current_out_file; | |
323 | gcc_assert (lo != NULL | |
324 | && lo->sobj_r == NULL | |
325 | && lo->sobj_w != NULL | |
326 | && lo->section == NULL); | |
327 | ||
957f47e6 | 328 | align = ceil_log2 (POINTER_SIZE_UNITS); |
6b3456d1 ILT |
329 | lo->section = simple_object_write_create_section (lo->sobj_w, name, align, |
330 | &errmsg, &err); | |
331 | if (lo->section == NULL) | |
332 | { | |
333 | if (err == 0) | |
40fecdd6 | 334 | fatal_error (input_location, "%s", errmsg); |
6b3456d1 | 335 | else |
40fecdd6 | 336 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno)); |
6b3456d1 ILT |
337 | } |
338 | } | |
339 | ||
340 | /* Add data to a section. BLOCK is a pointer to memory containing | |
341 | DATA. */ | |
342 | ||
343 | void | |
f6bcdb5e | 344 | lto_obj_append_data (const void *data, size_t len, void *) |
6b3456d1 ILT |
345 | { |
346 | struct lto_simple_object *lo; | |
347 | const char *errmsg; | |
348 | int err; | |
349 | ||
350 | lo = (struct lto_simple_object *) current_out_file; | |
351 | gcc_assert (lo != NULL && lo->section != NULL); | |
352 | ||
353 | errmsg = simple_object_write_add_data (lo->sobj_w, lo->section, data, len, | |
354 | 1, &err); | |
355 | if (errmsg != NULL) | |
356 | { | |
357 | if (err == 0) | |
40fecdd6 | 358 | fatal_error (input_location, "%s", errmsg); |
6b3456d1 | 359 | else |
40fecdd6 | 360 | fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno)); |
6b3456d1 | 361 | } |
6b3456d1 ILT |
362 | } |
363 | ||
364 | /* Stop writing to the current output section. */ | |
365 | ||
366 | void | |
367 | lto_obj_end_section (void) | |
368 | { | |
369 | struct lto_simple_object *lo; | |
370 | ||
371 | lo = (struct lto_simple_object *) current_out_file; | |
372 | gcc_assert (lo != NULL && lo->section != NULL); | |
373 | lo->section = NULL; | |
374 | } |