Added missing file.
[tinycc/k1w1.git] / tccld.c
blob4563cdd9eea8352d08e12178fa9a8efeee466334
1 /*
2 * Linkder script handling for TCC
3 *
4 * Copyright (c) 2001-2004 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "tcc.h"
22 #ifndef TCC_TARGET_PE
23 /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
24 is referenced by the user (so it should be added as DT_NEEDED in
25 the generated ELF file) */
26 int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
28 ElfW(Ehdr) ehdr;
29 ElfW(Shdr) *shdr, *sh, *sh1;
30 int i, j, nb_syms, nb_dts, sym_bind, ret;
31 ElfW(Sym) *sym, *dynsym;
32 ElfW(Dyn) *dt, *dynamic;
33 unsigned char *dynstr;
34 const char *name, *soname;
35 DLLReference *dllref;
37 read(fd, &ehdr, sizeof(ehdr));
39 /* test CPU specific stuff */
40 if (ehdr.e_ident[5] != ELFDATA2LSB ||
41 ehdr.e_machine != EM_TCC_TARGET) {
42 error_noabort("bad architecture");
43 return -1;
46 /* read sections */
47 shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum);
49 /* load dynamic section and dynamic symbols */
50 nb_syms = 0;
51 nb_dts = 0;
52 dynamic = NULL;
53 dynsym = NULL; /* avoid warning */
54 dynstr = NULL; /* avoid warning */
55 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
56 switch(sh->sh_type) {
57 case SHT_DYNAMIC:
58 nb_dts = sh->sh_size / sizeof(ElfW(Dyn));
59 dynamic = load_data(fd, sh->sh_offset, sh->sh_size);
60 break;
61 case SHT_DYNSYM:
62 nb_syms = sh->sh_size / sizeof(ElfW(Sym));
63 dynsym = load_data(fd, sh->sh_offset, sh->sh_size);
64 sh1 = &shdr[sh->sh_link];
65 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
66 break;
67 default:
68 break;
72 /* compute the real library name */
73 soname = tcc_basename(filename);
75 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
76 if (dt->d_tag == DT_SONAME) {
77 soname = dynstr + dt->d_un.d_val;
81 /* if the dll is already loaded, do not load it */
82 for(i = 0; i < s1->nb_loaded_dlls; i++) {
83 dllref = s1->loaded_dlls[i];
84 if (!strcmp(soname, dllref->name)) {
85 /* but update level if needed */
86 if (level < dllref->level)
87 dllref->level = level;
88 ret = 0;
89 goto the_end;
93 // printf("loading dll '%s'\n", soname);
95 /* add the dll and its level */
96 dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
97 dllref->level = level;
98 strcpy(dllref->name, soname);
99 dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
101 /* add dynamic symbols in dynsym_section */
102 for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
103 sym_bind = ELFW(ST_BIND)(sym->st_info);
104 if (sym_bind == STB_LOCAL)
105 continue;
106 name = dynstr + sym->st_name;
107 add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
108 sym->st_info, sym->st_other, sym->st_shndx, name);
111 /* load all referenced DLLs */
112 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
113 switch(dt->d_tag) {
114 case DT_NEEDED:
115 name = dynstr + dt->d_un.d_val;
116 for(j = 0; j < s1->nb_loaded_dlls; j++) {
117 dllref = s1->loaded_dlls[j];
118 if (!strcmp(name, dllref->name))
119 goto already_loaded;
121 if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) {
122 error_noabort("referenced dll '%s' not found", name);
123 ret = -1;
124 goto the_end;
126 already_loaded:
127 break;
130 ret = 0;
131 the_end:
132 tcc_free(dynstr);
133 tcc_free(dynsym);
134 tcc_free(dynamic);
135 tcc_free(shdr);
136 return ret;
139 #define LD_TOK_NAME 256
140 #define LD_TOK_EOF (-1)
142 /* return next ld script token */
143 static int ld_next(TCCState *s1, char *name, int name_size)
145 int c;
146 char *q;
148 redo:
149 switch(ch) {
150 case ' ':
151 case '\t':
152 case '\f':
153 case '\v':
154 case '\r':
155 case '\n':
156 inp();
157 goto redo;
158 case '/':
159 minp();
160 if (ch == '*') {
161 file->buf_ptr = parse_comment(file->buf_ptr);
162 ch = file->buf_ptr[0];
163 goto redo;
164 } else {
165 q = name;
166 *q++ = '/';
167 goto parse_name;
169 break;
170 /* case 'a' ... 'z': */
171 case 'a':
172 case 'b':
173 case 'c':
174 case 'd':
175 case 'e':
176 case 'f':
177 case 'g':
178 case 'h':
179 case 'i':
180 case 'j':
181 case 'k':
182 case 'l':
183 case 'm':
184 case 'n':
185 case 'o':
186 case 'p':
187 case 'q':
188 case 'r':
189 case 's':
190 case 't':
191 case 'u':
192 case 'v':
193 case 'w':
194 case 'x':
195 case 'y':
196 case 'z':
197 /* case 'A' ... 'z': */
198 case 'A':
199 case 'B':
200 case 'C':
201 case 'D':
202 case 'E':
203 case 'F':
204 case 'G':
205 case 'H':
206 case 'I':
207 case 'J':
208 case 'K':
209 case 'L':
210 case 'M':
211 case 'N':
212 case 'O':
213 case 'P':
214 case 'Q':
215 case 'R':
216 case 'S':
217 case 'T':
218 case 'U':
219 case 'V':
220 case 'W':
221 case 'X':
222 case 'Y':
223 case 'Z':
224 case '_':
225 case '\\':
226 case '.':
227 case '$':
228 case '~':
229 q = name;
230 parse_name:
231 for(;;) {
232 if (!((ch >= 'a' && ch <= 'z') ||
233 (ch >= 'A' && ch <= 'Z') ||
234 (ch >= '0' && ch <= '9') ||
235 strchr("/.-_+=$:\\,~", ch)))
236 break;
237 if ((q - name) < name_size - 1) {
238 *q++ = ch;
240 minp();
242 *q = '\0';
243 c = LD_TOK_NAME;
244 break;
245 case CH_EOF:
246 c = LD_TOK_EOF;
247 break;
248 default:
249 c = ch;
250 inp();
251 break;
253 #if 0
254 printf("tok=%c %d\n", c, c);
255 if (c == LD_TOK_NAME)
256 printf(" name=%s\n", name);
257 #endif
258 return c;
261 static int ld_add_file_list(TCCState *s1, int as_needed)
263 char filename[1024];
264 int t, ret;
266 t = ld_next(s1, filename, sizeof(filename));
267 if (t != '(')
268 expect("(");
269 t = ld_next(s1, filename, sizeof(filename));
270 for(;;) {
271 if (t == LD_TOK_EOF) {
272 error_noabort("unexpected end of file");
273 return -1;
274 } else if (t == ')') {
275 break;
276 } else if (t != LD_TOK_NAME) {
277 error_noabort("filename expected");
278 return -1;
280 if (!strcmp(filename, "AS_NEEDED")) {
281 ret = ld_add_file_list(s1, 1);
282 if (ret)
283 return ret;
284 } else {
285 /* TODO: Implement AS_NEEDED support. Ignore it for now */
286 if (!as_needed)
287 tcc_add_file(s1, filename);
289 t = ld_next(s1, filename, sizeof(filename));
290 if (t == ',') {
291 t = ld_next(s1, filename, sizeof(filename));
294 return 0;
297 /* interpret a subset of GNU ldscripts to handle the dummy libc.so
298 files */
299 int tcc_load_ldscript(TCCState *s1)
301 char cmd[64];
302 char filename[1024];
303 int t, ret;
305 ch = file->buf_ptr[0];
306 ch = handle_eob();
307 for(;;) {
308 t = ld_next(s1, cmd, sizeof(cmd));
309 if (t == LD_TOK_EOF)
310 return 0;
311 else if (t != LD_TOK_NAME)
312 return -1;
313 if (!strcmp(cmd, "INPUT") ||
314 !strcmp(cmd, "GROUP")) {
315 ret = ld_add_file_list(s1, 0);
316 if (ret)
317 return ret;
318 } else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
319 !strcmp(cmd, "TARGET")) {
320 /* ignore some commands */
321 t = ld_next(s1, cmd, sizeof(cmd));
322 if (t != '(')
323 expect("(");
324 for(;;) {
325 t = ld_next(s1, filename, sizeof(filename));
326 if (t == LD_TOK_EOF) {
327 error_noabort("unexpected end of file");
328 return -1;
329 } else if (t == ')') {
330 break;
333 } else {
334 return -1;
337 return 0;
339 #endif