2 * Copyright (c) 1997 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/kern/link_aout.c,v 1.26 1999/12/24 15:33:36 bde Exp $
27 * $DragonFly: src/sys/kern/link_aout.c,v 1.21 2006/12/23 00:35:04 swildner Exp $
30 #define FREEBSD_AOUT 1
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/types.h>
36 #include <sys/malloc.h>
38 #include <sys/nlookup.h>
39 #include <sys/fcntl.h>
40 #include <sys/vnode.h>
41 #include <sys/linker.h>
43 #include <vm/vm_zone.h>
48 #include <machine/vmparam.h>
51 #include <machine/exec.h>
52 #include <sys/imgact_aout.h>
53 #include <machine/reloc.h>
54 #define _AOUT_INCLUDE_
55 #include <sys/nlist_aout.h>
56 #include <sys/link_aout.h>
58 static int link_aout_load_module(const char*, linker_file_t
*);
60 static int link_aout_load_file(const char*, linker_file_t
*);
62 static int link_aout_lookup_symbol(linker_file_t
, const char*,
64 static int link_aout_symbol_values(linker_file_t file
, c_linker_sym_t sym
,
65 linker_symval_t
* symval
);
66 static int link_aout_search_symbol(linker_file_t lf
, caddr_t value
,
67 c_linker_sym_t
* sym
, long* diffp
);
68 static void link_aout_unload_file(linker_file_t
);
69 static void link_aout_unload_module(linker_file_t
);
70 static int link_aout_lookup_set(linker_file_t lf
, const char *name
,
71 void ***startp
, void ***stopp
, int *countp
);
73 static struct linker_class_ops link_aout_class_ops
= {
74 link_aout_load_module
,
77 static struct linker_file_ops link_aout_file_ops
= {
78 link_aout_lookup_symbol
,
79 link_aout_symbol_values
,
80 link_aout_search_symbol
,
81 link_aout_unload_file
,
84 static struct linker_file_ops link_aout_module_ops
= {
85 link_aout_lookup_symbol
,
86 link_aout_symbol_values
,
87 link_aout_search_symbol
,
88 link_aout_unload_module
,
92 typedef struct aout_file
{
93 char* address
; /* Load address */
94 struct _dynamic
* dynamic
; /* Symbol table etc. */
97 static int load_dependancies(linker_file_t lf
);
98 static int relocate_file(linker_file_t lf
);
101 * The kernel symbol table starts here.
103 extern struct _dynamic _DYNAMIC
;
106 link_aout_init(void* arg
)
109 struct _dynamic
* dp
= &_DYNAMIC
;
112 linker_add_class("a.out", NULL
, &link_aout_class_ops
);
118 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_NOWAIT
);
120 panic("link_aout_init: Can't create linker structures for kernel");
121 bzero(af
, sizeof(*af
));
126 linker_make_file(kernelname
, af
, &link_aout_file_ops
);
127 if (linker_kernel_file
== NULL
)
128 panic("link_aout_init: Can't create linker structures for kernel");
129 linker_kernel_file
->address
= (caddr_t
) KERNBASE
;
130 linker_kernel_file
->size
= -(long)linker_kernel_file
->address
;
131 linker_current_file
= linker_kernel_file
;
132 linker_kernel_file
->flags
|= LINKER_FILE_LINKED
;
137 SYSINIT(link_aout
, SI_SUB_KLD
, SI_ORDER_THIRD
, link_aout_init
, 0);
140 link_aout_load_module(const char* filename
, linker_file_t
* result
)
142 caddr_t modptr
, baseptr
;
149 /* Look to see if we have the module preloaded. */
150 if ((modptr
= preload_search_by_name(filename
)) == NULL
)
151 return(link_aout_load_file(filename
, result
));
153 /* It's preloaded, check we can handle it and collect information. */
154 if (((type
= (char *)preload_search_info(modptr
, MODINFO_TYPE
)) == NULL
) ||
155 strcmp(type
, "a.out module") ||
156 ((baseptr
= preload_search_info(modptr
, MODINFO_ADDR
)) == NULL
) ||
157 ((ehdr
= (struct exec
*)preload_search_info(modptr
, MODINFO_METADATA
| MODINFOMD_AOUTEXEC
)) == NULL
))
158 return(0); /* we can't handle this */
160 /* Looks like we can handle this one */
161 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
);
162 bzero(af
, sizeof(*af
));
163 af
->address
= baseptr
;
165 /* Assume _DYNAMIC is the first data item. */
166 af
->dynamic
= (struct _dynamic
*)(af
->address
+ ehdr
->a_text
);
167 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
169 return(0); /* we can't handle this */
171 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
172 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
174 /* Register with kld */
175 lf
= linker_make_file(filename
, af
, &link_aout_module_ops
);
180 lf
->address
= af
->address
;
181 lf
->size
= ehdr
->a_text
+ ehdr
->a_data
+ ehdr
->a_bss
;
183 /* Try to load dependancies */
184 if (((error
= load_dependancies(lf
)) != 0) ||
185 ((error
= relocate_file(lf
)) != 0)) {
186 linker_file_unload(lf
);
189 lf
->flags
|= LINKER_FILE_LINKED
;
195 link_aout_load_file(const char* filename
, linker_file_t
* result
)
197 struct nlookupdata nd
;
198 struct thread
*td
= curthread
;
199 struct proc
*p
= td
->td_proc
;
210 if (p
->p_ucred
== NULL
) {
211 kprintf("link_aout_load_file: cannot load '%s' from filesystem"
212 " this early\n", filename
);
216 pathname
= linker_search_path(filename
);
217 if (pathname
== NULL
)
219 error
= nlookup_init(&nd
, pathname
, UIO_SYSSPACE
, NLC_FOLLOW
|NLC_LOCKVP
);
221 error
= vn_open(&nd
, NULL
, FREAD
, 0);
222 kfree(pathname
, M_LINKER
);
228 nd
.nl_open_vp
= NULL
;
232 * Read the a.out header from the file.
234 error
= vn_rdwr(UIO_READ
, vp
, (void*) &header
, sizeof header
, 0,
235 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
239 if (N_BADMAG(header
) || !(N_GETFLAG(header
) & EX_DYNAMIC
))
243 * We have an a.out file, so make some space to read it in.
245 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
);
246 bzero(af
, sizeof(*af
));
247 af
->address
= kmalloc(header
.a_text
+ header
.a_data
+ header
.a_bss
,
251 * Read the text and data sections and zero the bss.
253 error
= vn_rdwr(UIO_READ
, vp
, (void*) af
->address
,
254 header
.a_text
+ header
.a_data
, 0,
255 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
258 bzero(af
->address
+ header
.a_text
+ header
.a_data
, header
.a_bss
);
261 * Assume _DYNAMIC is the first data item.
263 af
->dynamic
= (struct _dynamic
*) (af
->address
+ header
.a_text
);
264 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
265 kfree(af
->address
, M_LINKER
);
269 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
270 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
272 lf
= linker_make_file(filename
, af
, &link_aout_file_ops
);
274 kfree(af
->address
, M_LINKER
);
279 lf
->address
= af
->address
;
280 lf
->size
= header
.a_text
+ header
.a_data
+ header
.a_bss
;
282 if ((error
= load_dependancies(lf
)) != 0
283 || (error
= relocate_file(lf
)) != 0) {
284 linker_file_unload(lf
);
288 lf
->flags
|= LINKER_FILE_LINKED
;
299 link_aout_unload_file(linker_file_t file
)
301 aout_file_t af
= file
->priv
;
305 kfree(af
->address
, M_LINKER
);
311 link_aout_unload_module(linker_file_t file
)
313 aout_file_t af
= file
->priv
;
318 preload_delete_name(file
->filename
);
321 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
324 load_dependancies(linker_file_t lf
)
326 aout_file_t af
= lf
->priv
;
335 * All files are dependant on /kernel.
337 if (linker_kernel_file
) {
338 linker_kernel_file
->refs
++;
339 linker_file_add_dependancy(lf
, linker_kernel_file
);
342 off
= LD_NEED(af
->dynamic
);
345 * Load the dependancies.
348 sodp
= AOUT_RELOC(af
, struct sod
, off
);
349 name
= AOUT_RELOC(af
, char, sodp
->sod_name
);
351 error
= linker_load_file(name
, &lfdep
);
354 error
= linker_file_add_dependancy(lf
, lfdep
);
357 off
= sodp
->sod_next
;
362 kfree(filename
, M_TEMP
);
367 * XXX i386 dependant.
370 read_relocation(struct relocation_info
* r
, char* addr
)
372 int length
= r
->r_length
;
374 return *(u_char
*) addr
;
375 else if (length
== 1)
376 return *(u_short
*) addr
;
377 else if (length
== 2)
378 return *(u_int
*) addr
;
380 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
385 write_relocation(struct relocation_info
* r
, char* addr
, long value
)
387 int length
= r
->r_length
;
389 *(u_char
*) addr
= value
;
390 else if (length
== 1)
391 *(u_short
*) addr
= value
;
392 else if (length
== 2)
393 *(u_int
*) addr
= value
;
395 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
399 relocate_file(linker_file_t lf
)
401 aout_file_t af
= lf
->priv
;
402 struct relocation_info
* rel
;
403 struct relocation_info
* erel
;
404 struct relocation_info
* r
;
405 struct nzlist
* symbolbase
;
411 rel
= AOUT_RELOC(af
, struct relocation_info
, LD_REL(af
->dynamic
));
412 erel
= AOUT_RELOC(af
, struct relocation_info
,
413 LD_REL(af
->dynamic
) + LD_RELSZ(af
->dynamic
));
414 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
415 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
417 for (r
= rel
; r
< erel
; r
++) {
420 if (r
->r_address
== 0)
423 addr
= AOUT_RELOC(af
, char, r
->r_address
);
425 np
= &symbolbase
[r
->r_symbolnum
];
426 sym
= &stringbase
[np
->nz_strx
];
429 kprintf("link_aout: bad symbol name %s\n", sym
);
430 kprintf("link_aout: symbol %s not found\n", sym
);
433 if (linker_file_lookup_symbol(lf
, sym
+ 1,
434 (np
->nz_type
!= (N_SETV
+N_EXT
)), (caddr_t
*)&relocation
)) {
435 kprintf("link_aout: symbol %s not found\n", sym
);
440 relocation
+= read_relocation(r
, addr
);
443 kprintf("link_aout: can't cope with jump table relocations\n");
448 relocation
-= (intptr_t) af
->address
;
451 kprintf("link_aout: can't cope with copy relocations\n");
455 write_relocation(r
, addr
, relocation
);
457 write_relocation(r
, addr
,
458 (intptr_t)(read_relocation(r
, addr
) + af
->address
));
467 symbol_hash_value(aout_file_t af
, const char* name
)
472 hashval
= '_'; /* fake a starting '_' for C symbols */
473 for (p
= name
; *p
; p
++)
474 hashval
= (hashval
<< 1) + *p
;
476 return (hashval
& 0x7fffffff) % LD_BUCKETS(af
->dynamic
);
480 link_aout_lookup_symbol(linker_file_t file
, const char* name
,
483 aout_file_t af
= file
->priv
;
485 struct rrs_hash
* hashbase
;
486 struct nzlist
* symbolbase
;
492 if (LD_BUCKETS(af
->dynamic
) == 0)
495 hashbase
= AOUT_RELOC(af
, struct rrs_hash
, LD_HASH(af
->dynamic
));
496 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
497 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
500 hashval
= symbol_hash_value(af
, name
);
501 hp
= &hashbase
[hashval
];
502 if (hp
->rh_symbolnum
== -1)
506 np
= (struct nzlist
*) &symbolbase
[hp
->rh_symbolnum
];
507 cp
= stringbase
+ np
->nz_strx
;
509 * Note: we fake the leading '_' for C symbols.
511 if (cp
[0] == '_' && !strcmp(cp
+ 1, name
))
514 if (hp
->rh_next
== 0)
517 hp
= &hashbase
[hp
->rh_next
];
527 * Check for an aliased symbol, whatever that is.
529 if (np
->nz_type
== N_INDR
+N_EXT
) {
530 name
= stringbase
+ (++np
)->nz_strx
+ 1; /* +1 for '_' */
535 * Check this is an actual definition of the symbol.
537 if (np
->nz_value
== 0)
540 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
541 if (np
->nz_other
== AUX_FUNC
)
546 *sym
= (linker_sym_t
) np
;
553 link_aout_symbol_values(linker_file_t file
, c_linker_sym_t sym
,
554 linker_symval_t
* symval
)
556 aout_file_t af
= file
->priv
;
557 const struct nzlist
* np
= (const struct nzlist
*) sym
;
559 long numsym
= LD_STABSZ(af
->dynamic
) / sizeof(struct nzlist
);
560 struct nzlist
*symbase
;
562 /* Is it one of ours? It could be another module... */
563 symbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
566 if ((np
- symbase
) > numsym
)
569 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
571 symval
->name
= stringbase
+ np
->nz_strx
+ 1; /* +1 for '_' */
572 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
574 symval
->size
= np
->nz_value
;
576 symval
->value
= AOUT_RELOC(af
, char, np
->nz_value
);
577 symval
->size
= np
->nz_size
;
583 link_aout_search_symbol(linker_file_t lf
, caddr_t value
,
584 c_linker_sym_t
* sym
, long* diffp
)
586 aout_file_t af
= lf
->priv
;
587 u_long off
= (uintptr_t) (void *) value
;
592 struct nzlist
* best
= 0;
594 for (sp
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
)),
595 ep
= (struct nzlist
*) ((caddr_t
) sp
+ LD_STABSZ(af
->dynamic
));
597 if (sp
->nz_name
== 0)
599 sp_nz_value
= sp
->nz_value
+ (uintptr_t) (void *) af
->address
;
600 if (off
>= sp_nz_value
) {
601 if (off
- sp_nz_value
< diff
) {
602 diff
= off
- sp_nz_value
;
606 } else if (off
- sp_nz_value
== diff
) {
615 *sym
= (linker_sym_t
) best
;
621 * Look up a linker set on an a.out + gnu LD system.
624 struct generic_linker_set
{
630 link_aout_lookup_set(linker_file_t lf
, const char *name
,
631 void ***startp
, void ***stopp
, int *countp
)
634 linker_symval_t symval
;
635 void **start
, **stop
;
637 struct generic_linker_set
*setp
;
639 error
= link_aout_lookup_symbol(lf
, name
, &sym
);
642 link_aout_symbol_values(lf
, sym
, &symval
);
643 if (symval
.value
== 0)
645 setp
= (struct generic_linker_set
*)symval
.value
;
646 count
= setp
->ls_length
;
647 start
= &setp
->ls_items
[0];
648 stop
= &setp
->ls_items
[count
];