1/* LTO routines to use object files.
2 Copyright (C) 2010-2023 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Google.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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"
24#include "tm.h"
25#include "diagnostic-core.h"
26#include "lto.h"
27#include "lto-section-names.h"
28#include "simple-object.h"
29
30/* An LTO file wrapped around an simple_object. */
31
32struct 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
53static simple_object_attributes *saved_attributes;
54
55/* Initialize FILE, an LTO file object for FILENAME. */
56
57static void
58lto_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
68lto_file *
69lto_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 (s: filename, c: '@');
81 if (offset_p != NULL
82 && offset_p != filename
83 && sscanf (s: offset_p, format: "@%li%n", &loffset, &consumed) >= 1
84 && strlen (s: offset_p) == (unsigned int) consumed)
85 {
86 fname = XNEWVEC (char, offset_p - filename + 1);
87 memcpy (dest: fname, src: filename, n: 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 (file: (lto_file *) lo, filename: fname, offset);
99
100 lo->fd = open (file: fname,
101 oflag: (writable
102 ? O_WRONLY | O_CREAT | O_BINARY
103 : O_RDONLY | O_BINARY),
104 0666);
105 if (lo->fd == -1)
106 fatal_error (input_location, "open %s failed: %s", fname, xstrerror (errno));
107
108 if (!writable)
109 {
110 simple_object_attributes *attrs;
111
112 lo->sobj_r = simple_object_start_read (descriptor: lo->fd, offset, LTO_SEGMENT_NAME,
113 errmsg: &errmsg, err: &err);
114 if (lo->sobj_r == NULL)
115 goto fail_errmsg;
116
117 attrs = simple_object_fetch_attributes (simple_object: lo->sobj_r, errmsg: &errmsg, err: &err);
118 if (attrs == NULL)
119 goto fail_errmsg;
120
121 if (saved_attributes == NULL)
122 saved_attributes = attrs;
123 else
124 {
125 errmsg = simple_object_attributes_merge (to: saved_attributes, from: attrs,
126 err: &err);
127 if (errmsg != NULL)
128 {
129 free (ptr: attrs);
130 goto fail_errmsg;
131 }
132 }
133 }
134 else
135 {
136 gcc_assert (saved_attributes != NULL);
137 lo->sobj_w = simple_object_start_write (attrs: saved_attributes,
138 LTO_SEGMENT_NAME,
139 errmsg: &errmsg, err: &err);
140 if (lo->sobj_w == NULL)
141 goto fail_errmsg;
142 }
143
144 return &lo->base;
145
146fail_errmsg:
147 if (err == 0)
148 error ("%s: %s", fname, errmsg);
149 else
150 error ("%s: %s: %s", fname, errmsg, xstrerror (err));
151
152 if (lo->fd != -1)
153 lto_obj_file_close (file: (lto_file *) lo);
154 free (ptr: lo);
155 return NULL;
156}
157
158
159/* Close FILE. If FILE was opened for writing, it is written out
160 now. */
161
162void
163lto_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 (simple_object: lo->sobj_w, descriptor: lo->fd, err: &err);
177 if (errmsg != NULL)
178 {
179 if (err == 0)
180 fatal_error (input_location, "%s", errmsg);
181 else
182 fatal_error (input_location, "%s: %s", errmsg, xstrerror (err));
183 }
184
185 simple_object_release_write (lo->sobj_w);
186 }
187
188 if (lo->fd != -1)
189 {
190 if (close (fd: lo->fd) < 0)
191 fatal_error (input_location, "close: %s", xstrerror (errno));
192 }
193}
194
195/* This is passed to lto_obj_add_section. */
196
197struct 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;
203 /* List in linker order */
204 struct lto_section_list *list;
205};
206
207/* This is called for each section in the file. */
208
209static int
210lto_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;
219 struct lto_section_list *list = loasd->list;
220
221 if (strncmp (s1: name, s2: section_name_prefix, n: strlen (s: section_name_prefix)))
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 {
229 struct lto_section_slot *new_slot = XCNEW (struct lto_section_slot);
230
231 new_slot->name = new_name;
232 new_slot->start = loasd->base_offset + offset;
233 new_slot->len = length;
234 *slot = new_slot;
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 }
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
257htab_t
258lto_obj_build_section_table (lto_file *lto_file, struct lto_section_list *list)
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;
271 loasd.list = list;
272 errmsg = simple_object_find_sections (simple_object: lo->sobj_r, pfn: lto_obj_add_section,
273 data: &loasd, err: &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
289static lto_file *current_out_file;
290
291/* Set the current output file. Return the old one. */
292
293lto_file *
294lto_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
305lto_file *
306lto_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
314void
315lto_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
328 align = ceil_log2 (POINTER_SIZE_UNITS);
329 lo->section = simple_object_write_create_section (simple_object: lo->sobj_w, name, align,
330 errmsg: &errmsg, err: &err);
331 if (lo->section == NULL)
332 {
333 if (err == 0)
334 fatal_error (input_location, "%s", errmsg);
335 else
336 fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno));
337 }
338}
339
340/* Add data to a section. BLOCK is a pointer to memory containing
341 DATA. */
342
343void
344lto_obj_append_data (const void *data, size_t len, void *)
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 (simple_object: lo->sobj_w, section: lo->section, buffer: data, size: len,
354 copy: 1, err: &err);
355 if (errmsg != NULL)
356 {
357 if (err == 0)
358 fatal_error (input_location, "%s", errmsg);
359 else
360 fatal_error (input_location, "%s: %s", errmsg, xstrerror (errno));
361 }
362}
363
364/* Stop writing to the current output section. */
365
366void
367lto_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}
375

source code of gcc/lto/lto-object.cc