xref: /netbsd-src/external/gpl3/gcc/dist/gcc/lto/lto-object.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* LTO routines to use object files.
2    Copyright (C) 2010-2022 Free Software Foundation, Inc.
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"
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 
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
lto_file_init(lto_file * file,const char * filename,off_t offset)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 *
lto_obj_file_open(const char * filename,bool writable)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     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 (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 	{
125 	  errmsg = simple_object_attributes_merge (saved_attributes, attrs,
126 						   &err);
127 	  if (errmsg != NULL)
128 	    {
129 	      free (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 (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 
146 fail_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 ((lto_file *) lo);
154   free (lo);
155   return NULL;
156 }
157 
158 
159 /* Close FILE.  If FILE was opened for writing, it is written out
160    now.  */
161 
162 void
lto_obj_file_close(lto_file * file)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)
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 (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 
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;
203   /* List in linker order */
204   struct lto_section_list *list;
205 };
206 
207 /* This is called for each section in the file.  */
208 
209 static int
lto_obj_add_section(void * data,const char * name,off_t offset,off_t length)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;
219   struct lto_section_list *list = loasd->list;
220 
221   if (strncmp (name, section_name_prefix, strlen (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 
257 htab_t
lto_obj_build_section_table(lto_file * lto_file,struct lto_section_list * list)258 lto_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 (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 *
lto_set_current_out_file(lto_file * 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 *
lto_get_current_out_file(void)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
lto_obj_begin_section(const char * name)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 
328   align = ceil_log2 (POINTER_SIZE_UNITS);
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)
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 
343 void
lto_obj_append_data(const void * data,size_t len,void *)344 lto_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 (lo->sobj_w, lo->section, data, len,
354 					 1, &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 
366 void
lto_obj_end_section(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 }
375