LoongArch: Add more relaxation support for call36
[binutils-gdb.git] / ld / libdep_plugin.c
blob9cd3d7780a9a637d3bc20a735d38677752a9787b
1 /* libdeps plugin for the GNU linker.
2 Copyright (C) 2020-2024 Free Software Foundation, Inc.
4 This file is part of the GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 #include "sysdep.h"
22 #include "bfd.h"
23 #if BFD_SUPPORTS_PLUGINS
24 #include "plugin-api.h"
26 #include <ctype.h> /* For isspace. */
28 extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
30 /* Helper for calling plugin api message function. */
31 #define TV_MESSAGE if (tv_message) (*tv_message)
33 /* Function pointers to cache hooks passed at onload time. */
34 static ld_plugin_register_claim_file tv_register_claim_file = 0;
35 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
36 static ld_plugin_register_cleanup tv_register_cleanup = 0;
37 static ld_plugin_message tv_message = 0;
38 static ld_plugin_add_input_library tv_add_input_library = 0;
39 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
41 /* Handle/record information received in a transfer vector entry. */
42 static enum ld_plugin_status
43 parse_tv_tag (struct ld_plugin_tv *tv)
45 #define SETVAR(x) x = tv->tv_u.x
46 switch (tv->tv_tag)
48 case LDPT_REGISTER_CLAIM_FILE_HOOK:
49 SETVAR(tv_register_claim_file);
50 break;
51 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
52 SETVAR(tv_register_all_symbols_read);
53 break;
54 case LDPT_REGISTER_CLEANUP_HOOK:
55 SETVAR(tv_register_cleanup);
56 break;
57 case LDPT_MESSAGE:
58 SETVAR(tv_message);
59 break;
60 case LDPT_ADD_INPUT_LIBRARY:
61 SETVAR(tv_add_input_library);
62 break;
63 case LDPT_SET_EXTRA_LIBRARY_PATH:
64 SETVAR(tv_set_extra_library_path);
65 break;
66 default:
67 break;
69 #undef SETVAR
70 return LDPS_OK;
73 /* Defs for archive parsing. */
74 #define ARMAGSIZE 8
75 typedef struct arhdr
77 char ar_name[16];
78 char ar_date[12];
79 char ar_uid[6];
80 char ar_gid[6];
81 char ar_mode[8];
82 char ar_size[10];
83 char ar_fmag[2];
84 } arhdr;
86 typedef struct linerec
88 struct linerec *next;
89 char line[];
90 } linerec;
92 #define LIBDEPS "__.LIBDEP/ "
94 static linerec *line_head, **line_tail = &line_head;
96 static enum ld_plugin_status
97 get_libdeps (int fd)
99 arhdr ah;
100 int len;
101 unsigned long mlen;
102 size_t amt;
103 linerec *lr;
104 enum ld_plugin_status rc = LDPS_NO_SYMS;
106 lseek (fd, ARMAGSIZE, SEEK_SET);
107 for (;;)
109 len = read (fd, (void *) &ah, sizeof (ah));
110 if (len != sizeof (ah))
111 break;
112 mlen = strtoul (ah.ar_size, NULL, 10);
113 if (!mlen || strncmp (ah.ar_name, LIBDEPS, sizeof (LIBDEPS)-1))
115 lseek (fd, mlen, SEEK_CUR);
116 continue;
118 amt = mlen + sizeof (linerec);
119 if (amt <= mlen)
120 return LDPS_ERR;
121 lr = malloc (amt);
122 if (!lr)
123 return LDPS_ERR;
124 lr->next = NULL;
125 len = read (fd, lr->line, mlen);
126 lr->line[mlen-1] = '\0';
127 *line_tail = lr;
128 line_tail = &lr->next;
129 rc = LDPS_OK;
130 break;
132 return rc;
135 /* Parse arguments in-place as contiguous C-strings
136 and return the number of arguments. */
138 static int
139 parse_libdep (char *str)
141 char *src, *dst;
142 char quote;
143 int narg;
145 src = dst = str;
147 for (; isspace ((unsigned char) *src); ++src)
150 if (*src == '\0')
151 return 0;
153 narg = 1;
154 quote = 0;
156 while (*src)
158 if (*src == '\'' || *src == '\"')
160 if (!quote)
161 quote = *src++;
162 else if (*src == quote)
164 ++src;
165 quote = 0;
167 else
168 *dst++ = *src++;
170 else if (!quote && isspace ((unsigned char) *src))
172 ++narg;
173 ++src;
174 *dst++ = '\0';
175 for (; isspace ((unsigned char) *src); ++src);
177 else
178 *dst++ = *src++;
181 *dst = '\0';
183 if (quote)
185 TV_MESSAGE (LDPL_WARNING,
186 "libdep syntax error: unterminated quoted string");
187 return 0;
190 return narg;
193 static char *prevfile;
195 /* Standard plugin API registerable hook. */
197 static enum ld_plugin_status
198 onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
200 enum ld_plugin_status rv;
202 *claimed = 0;
204 /* If we've already seen this file, ignore it. */
205 if (prevfile && !strcmp (file->name, prevfile))
206 return LDPS_OK;
208 /* If it's not an archive member, ignore it. */
209 if (!file->offset)
210 return LDPS_OK;
212 if (prevfile)
213 free (prevfile);
215 prevfile = strdup (file->name);
216 if (!prevfile)
217 return LDPS_ERR;
219 /* This hook only gets called on actual object files.
220 We have to examine the archive ourselves, to find
221 our LIBDEPS member. */
222 rv = get_libdeps (file->fd);
223 if (rv == LDPS_ERR)
224 return rv;
226 if (rv == LDPS_OK)
228 linerec *lr = (linerec *)line_tail;
229 /* Inform the user/testsuite. */
230 TV_MESSAGE (LDPL_INFO, "got deps for library %s: %s",
231 file->name, lr->line);
232 fflush (NULL);
235 return LDPS_OK;
238 /* Standard plugin API registerable hook. */
240 static enum ld_plugin_status
241 onall_symbols_read (void)
243 linerec *lr;
244 int nargs;
245 char const *arg;
246 enum ld_plugin_status rv = LDPS_OK;
248 while ((lr = line_head))
250 line_head = lr->next;
251 nargs = parse_libdep (lr->line);
252 arg = lr->line;
254 int i;
255 for (i = 0; i < nargs; i++, arg = strchr (arg, '\0') + 1)
257 if (arg[0] != '-')
259 TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);
260 fflush (NULL);
261 continue;
263 if (arg[1] == 'l')
264 rv = tv_add_input_library (arg + 2);
265 else if (arg[1] == 'L')
266 rv = tv_set_extra_library_path (arg + 2);
267 else
269 TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);
270 fflush (NULL);
272 if (rv != LDPS_OK)
273 break;
275 free (lr);
278 line_tail = NULL;
279 return rv;
282 /* Standard plugin API registerable hook. */
284 static enum ld_plugin_status
285 oncleanup (void)
287 if (prevfile)
289 free (prevfile);
290 prevfile = NULL;
293 if (line_head)
295 linerec *lr;
297 while ((lr = line_head))
299 line_head = lr->next;
300 free (lr);
303 line_tail = NULL;
306 return LDPS_OK;
309 /* Standard plugin API entry point. */
311 enum ld_plugin_status
312 onload (struct ld_plugin_tv *tv)
314 enum ld_plugin_status rv;
316 /* This plugin requires a valid tv array. */
317 if (!tv)
318 return LDPS_ERR;
320 /* First entry should always be LDPT_MESSAGE, letting us get
321 hold of it easily so we can send output straight away. */
322 if (tv[0].tv_tag == LDPT_MESSAGE)
323 tv_message = tv[0].tv_u.tv_message;
326 if ((rv = parse_tv_tag (tv)) != LDPS_OK)
327 return rv;
328 while ((tv++)->tv_tag != LDPT_NULL);
330 /* Register hooks. */
331 if (tv_register_claim_file
332 && tv_register_all_symbols_read
333 && tv_register_cleanup)
335 (*tv_register_claim_file) (onclaim_file);
336 (*tv_register_all_symbols_read) (onall_symbols_read);
337 (*tv_register_cleanup) (oncleanup);
340 fflush (NULL);
341 return LDPS_OK;
343 #endif /* BFD_SUPPORTS_PLUGINS */