2 * Linkder script handling for TCC
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
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
)
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
;
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");
47 shdr
= load_data(fd
, ehdr
.e_shoff
, sizeof(ElfW(Shdr
)) * ehdr
.e_shnum
);
49 /* load dynamic section and dynamic symbols */
53 dynsym
= NULL
; /* avoid warning */
54 dynstr
= NULL
; /* avoid warning */
55 for(i
= 0, sh
= shdr
; i
< ehdr
.e_shnum
; i
++, sh
++) {
58 nb_dts
= sh
->sh_size
/ sizeof(ElfW(Dyn
));
59 dynamic
= load_data(fd
, sh
->sh_offset
, sh
->sh_size
);
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
);
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
;
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
)
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
++) {
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
))
121 if (tcc_add_dll(s1
, name
, AFF_REFERENCED_DLL
) < 0) {
122 error_noabort("referenced dll '%s' not found", name
);
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
)
161 file
->buf_ptr
= parse_comment(file
->buf_ptr
);
162 ch
= file
->buf_ptr
[0];
170 /* case 'a' ... 'z': */
197 /* case 'A' ... 'z': */
232 if (!((ch
>= 'a' && ch
<= 'z') ||
233 (ch
>= 'A' && ch
<= 'Z') ||
234 (ch
>= '0' && ch
<= '9') ||
235 strchr("/.-_+=$:\\,~", ch
)))
237 if ((q
- name
) < name_size
- 1) {
254 printf("tok=%c %d\n", c
, c
);
255 if (c
== LD_TOK_NAME
)
256 printf(" name=%s\n", name
);
261 static int ld_add_file_list(TCCState
*s1
, int as_needed
)
266 t
= ld_next(s1
, filename
, sizeof(filename
));
269 t
= ld_next(s1
, filename
, sizeof(filename
));
271 if (t
== LD_TOK_EOF
) {
272 error_noabort("unexpected end of file");
274 } else if (t
== ')') {
276 } else if (t
!= LD_TOK_NAME
) {
277 error_noabort("filename expected");
280 if (!strcmp(filename
, "AS_NEEDED")) {
281 ret
= ld_add_file_list(s1
, 1);
285 /* TODO: Implement AS_NEEDED support. Ignore it for now */
287 tcc_add_file(s1
, filename
);
289 t
= ld_next(s1
, filename
, sizeof(filename
));
291 t
= ld_next(s1
, filename
, sizeof(filename
));
297 /* interpret a subset of GNU ldscripts to handle the dummy libc.so
299 int tcc_load_ldscript(TCCState
*s1
)
305 ch
= file
->buf_ptr
[0];
308 t
= ld_next(s1
, cmd
, sizeof(cmd
));
311 else if (t
!= LD_TOK_NAME
)
313 if (!strcmp(cmd
, "INPUT") ||
314 !strcmp(cmd
, "GROUP")) {
315 ret
= ld_add_file_list(s1
, 0);
318 } else if (!strcmp(cmd
, "OUTPUT_FORMAT") ||
319 !strcmp(cmd
, "TARGET")) {
320 /* ignore some commands */
321 t
= ld_next(s1
, cmd
, sizeof(cmd
));
325 t
= ld_next(s1
, filename
, sizeof(filename
));
326 if (t
== LD_TOK_EOF
) {
327 error_noabort("unexpected end of file");
329 } else if (t
== ')') {