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.24 2008/02/06 22:37:46 nth 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
| M_ZERO
);
120 panic("link_aout_init: Can't create linker structures for kernel");
125 linker_make_file(kernelname
, af
, &link_aout_file_ops
);
126 if (linker_kernel_file
== NULL
)
127 panic("link_aout_init: Can't create linker structures for kernel");
128 linker_kernel_file
->address
= (caddr_t
) KERNBASE
;
129 linker_kernel_file
->size
= -(long)linker_kernel_file
->address
;
130 linker_current_file
= linker_kernel_file
;
131 linker_kernel_file
->flags
|= LINKER_FILE_LINKED
;
136 SYSINIT(link_aout
, SI_BOOT2_KLD
, SI_ORDER_THIRD
, link_aout_init
, 0);
139 link_aout_load_module(const char* filename
, linker_file_t
* result
)
141 caddr_t modptr
, baseptr
;
148 /* Look to see if we have the module preloaded. */
149 if ((modptr
= preload_search_by_name(filename
)) == NULL
)
150 return(link_aout_load_file(filename
, result
));
152 /* It's preloaded, check we can handle it and collect information. */
153 if (((type
= (char *)preload_search_info(modptr
, MODINFO_TYPE
)) == NULL
) ||
154 strcmp(type
, "a.out module") ||
155 ((baseptr
= preload_search_info(modptr
, MODINFO_ADDR
)) == NULL
) ||
156 ((ehdr
= (struct exec
*)preload_search_info(modptr
, MODINFO_METADATA
| MODINFOMD_AOUTEXEC
)) == NULL
))
157 return(0); /* we can't handle this */
159 /* Looks like we can handle this one */
160 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
| M_ZERO
);
161 af
->address
= baseptr
;
163 /* Assume _DYNAMIC is the first data item. */
164 af
->dynamic
= (struct _dynamic
*)(af
->address
+ ehdr
->a_text
);
165 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
167 return(0); /* we can't handle this */
169 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
170 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
172 /* Register with kld */
173 lf
= linker_make_file(filename
, af
, &link_aout_module_ops
);
178 lf
->address
= af
->address
;
179 lf
->size
= ehdr
->a_text
+ ehdr
->a_data
+ ehdr
->a_bss
;
181 /* Try to load dependancies */
182 if (((error
= load_dependancies(lf
)) != 0) ||
183 ((error
= relocate_file(lf
)) != 0)) {
184 linker_file_unload(lf
);
187 lf
->flags
|= LINKER_FILE_LINKED
;
193 link_aout_load_file(const char* filename
, linker_file_t
* result
)
195 struct nlookupdata nd
;
196 struct thread
*td
= curthread
;
197 struct proc
*p
= td
->td_proc
;
208 if (p
->p_ucred
== NULL
) {
209 kprintf("link_aout_load_file: cannot load '%s' from filesystem"
210 " this early\n", filename
);
214 pathname
= linker_search_path(filename
);
215 if (pathname
== NULL
)
217 error
= nlookup_init(&nd
, pathname
, UIO_SYSSPACE
, NLC_FOLLOW
|NLC_LOCKVP
);
219 error
= vn_open(&nd
, NULL
, FREAD
, 0);
220 kfree(pathname
, M_LINKER
);
226 nd
.nl_open_vp
= NULL
;
230 * Read the a.out header from the file.
232 error
= vn_rdwr(UIO_READ
, vp
, (void*) &header
, sizeof header
, 0,
233 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
237 if (N_BADMAG(header
) || !(N_GETFLAG(header
) & EX_DYNAMIC
))
241 * We have an a.out file, so make some space to read it in.
243 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
| M_ZERO
);
244 af
->address
= kmalloc(header
.a_text
+ header
.a_data
+ header
.a_bss
,
248 * Read the text and data sections and zero the bss.
250 error
= vn_rdwr(UIO_READ
, vp
, (void*) af
->address
,
251 header
.a_text
+ header
.a_data
, 0,
252 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
255 bzero(af
->address
+ header
.a_text
+ header
.a_data
, header
.a_bss
);
258 * Assume _DYNAMIC is the first data item.
260 af
->dynamic
= (struct _dynamic
*) (af
->address
+ header
.a_text
);
261 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
262 kfree(af
->address
, M_LINKER
);
266 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
267 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
269 lf
= linker_make_file(filename
, af
, &link_aout_file_ops
);
271 kfree(af
->address
, M_LINKER
);
276 lf
->address
= af
->address
;
277 lf
->size
= header
.a_text
+ header
.a_data
+ header
.a_bss
;
279 if ((error
= load_dependancies(lf
)) != 0
280 || (error
= relocate_file(lf
)) != 0) {
281 linker_file_unload(lf
);
285 lf
->flags
|= LINKER_FILE_LINKED
;
296 link_aout_unload_file(linker_file_t file
)
298 aout_file_t af
= file
->priv
;
302 kfree(af
->address
, M_LINKER
);
308 link_aout_unload_module(linker_file_t file
)
310 aout_file_t af
= file
->priv
;
315 preload_delete_name(file
->filename
);
318 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
321 load_dependancies(linker_file_t lf
)
323 aout_file_t af
= lf
->priv
;
332 * All files are dependant on /kernel.
334 if (linker_kernel_file
) {
335 linker_kernel_file
->refs
++;
336 linker_file_add_dependancy(lf
, linker_kernel_file
);
339 off
= LD_NEED(af
->dynamic
);
342 * Load the dependancies.
345 sodp
= AOUT_RELOC(af
, struct sod
, off
);
346 name
= AOUT_RELOC(af
, char, sodp
->sod_name
);
348 error
= linker_load_file(name
, &lfdep
);
351 linker_file_add_dependancy(lf
, lfdep
);
352 off
= sodp
->sod_next
;
357 kfree(filename
, M_TEMP
);
362 * XXX i386 dependant.
365 read_relocation(struct relocation_info
* r
, char* addr
)
367 int length
= r
->r_length
;
369 return *(u_char
*) addr
;
370 else if (length
== 1)
371 return *(u_short
*) addr
;
372 else if (length
== 2)
373 return *(u_int
*) addr
;
375 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
380 write_relocation(struct relocation_info
* r
, char* addr
, long value
)
382 int length
= r
->r_length
;
384 *(u_char
*) addr
= value
;
385 else if (length
== 1)
386 *(u_short
*) addr
= value
;
387 else if (length
== 2)
388 *(u_int
*) addr
= value
;
390 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
394 relocate_file(linker_file_t lf
)
396 aout_file_t af
= lf
->priv
;
397 struct relocation_info
* rel
;
398 struct relocation_info
* erel
;
399 struct relocation_info
* r
;
400 struct nzlist
* symbolbase
;
406 rel
= AOUT_RELOC(af
, struct relocation_info
, LD_REL(af
->dynamic
));
407 erel
= AOUT_RELOC(af
, struct relocation_info
,
408 LD_REL(af
->dynamic
) + LD_RELSZ(af
->dynamic
));
409 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
410 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
412 for (r
= rel
; r
< erel
; r
++) {
415 if (r
->r_address
== 0)
418 addr
= AOUT_RELOC(af
, char, r
->r_address
);
420 np
= &symbolbase
[r
->r_symbolnum
];
421 sym
= &stringbase
[np
->nz_strx
];
424 kprintf("link_aout: bad symbol name %s\n", sym
);
425 kprintf("link_aout: symbol %s not found\n", sym
);
428 if (linker_file_lookup_symbol(lf
, sym
+ 1,
429 (np
->nz_type
!= (N_SETV
+N_EXT
)), (caddr_t
*)&relocation
)) {
430 kprintf("link_aout: symbol %s not found\n", sym
);
435 relocation
+= read_relocation(r
, addr
);
438 kprintf("link_aout: can't cope with jump table relocations\n");
443 relocation
-= (intptr_t) af
->address
;
446 kprintf("link_aout: can't cope with copy relocations\n");
450 write_relocation(r
, addr
, relocation
);
452 write_relocation(r
, addr
,
453 (intptr_t)(read_relocation(r
, addr
) + af
->address
));
462 symbol_hash_value(aout_file_t af
, const char* name
)
467 hashval
= '_'; /* fake a starting '_' for C symbols */
468 for (p
= name
; *p
; p
++)
469 hashval
= (hashval
<< 1) + *p
;
471 return (hashval
& 0x7fffffff) % LD_BUCKETS(af
->dynamic
);
475 link_aout_lookup_symbol(linker_file_t file
, const char* name
,
478 aout_file_t af
= file
->priv
;
480 struct rrs_hash
* hashbase
;
481 struct nzlist
* symbolbase
;
487 if (LD_BUCKETS(af
->dynamic
) == 0)
490 hashbase
= AOUT_RELOC(af
, struct rrs_hash
, LD_HASH(af
->dynamic
));
491 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
492 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
495 hashval
= symbol_hash_value(af
, name
);
496 hp
= &hashbase
[hashval
];
497 if (hp
->rh_symbolnum
== -1)
501 np
= (struct nzlist
*) &symbolbase
[hp
->rh_symbolnum
];
502 cp
= stringbase
+ np
->nz_strx
;
504 * Note: we fake the leading '_' for C symbols.
506 if (cp
[0] == '_' && !strcmp(cp
+ 1, name
))
509 if (hp
->rh_next
== 0)
512 hp
= &hashbase
[hp
->rh_next
];
522 * Check for an aliased symbol, whatever that is.
524 if (np
->nz_type
== N_INDR
+N_EXT
) {
525 name
= stringbase
+ (++np
)->nz_strx
+ 1; /* +1 for '_' */
530 * Check this is an actual definition of the symbol.
532 if (np
->nz_value
== 0)
535 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
536 if (np
->nz_other
== AUX_FUNC
)
541 *sym
= (linker_sym_t
) np
;
548 link_aout_symbol_values(linker_file_t file
, c_linker_sym_t sym
,
549 linker_symval_t
* symval
)
551 aout_file_t af
= file
->priv
;
552 const struct nzlist
* np
= (const struct nzlist
*) sym
;
554 long numsym
= LD_STABSZ(af
->dynamic
) / sizeof(struct nzlist
);
555 struct nzlist
*symbase
;
557 /* Is it one of ours? It could be another module... */
558 symbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
561 if ((np
- symbase
) > numsym
)
564 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
566 symval
->name
= stringbase
+ np
->nz_strx
+ 1; /* +1 for '_' */
567 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
569 symval
->size
= np
->nz_value
;
571 symval
->value
= AOUT_RELOC(af
, char, np
->nz_value
);
572 symval
->size
= np
->nz_size
;
578 link_aout_search_symbol(linker_file_t lf
, caddr_t value
,
579 c_linker_sym_t
* sym
, long* diffp
)
581 aout_file_t af
= lf
->priv
;
582 u_long off
= (uintptr_t) (void *) value
;
587 struct nzlist
* best
= 0;
589 for (sp
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
)),
590 ep
= (struct nzlist
*) ((caddr_t
) sp
+ LD_STABSZ(af
->dynamic
));
592 if (sp
->nz_name
== 0)
594 sp_nz_value
= sp
->nz_value
+ (uintptr_t) (void *) af
->address
;
595 if (off
>= sp_nz_value
) {
596 if (off
- sp_nz_value
< diff
) {
597 diff
= off
- sp_nz_value
;
601 } else if (off
- sp_nz_value
== diff
) {
610 *sym
= (linker_sym_t
) best
;
616 * Look up a linker set on an a.out + gnu LD system.
619 struct generic_linker_set
{
625 link_aout_lookup_set(linker_file_t lf
, const char *name
,
626 void ***startp
, void ***stopp
, int *countp
)
629 linker_symval_t symval
;
630 void **start
, **stop
;
632 struct generic_linker_set
*setp
;
634 error
= link_aout_lookup_symbol(lf
, name
, &sym
);
637 link_aout_symbol_values(lf
, sym
, &symval
);
638 if (symval
.value
== 0)
640 setp
= (struct generic_linker_set
*)symval
.value
;
641 count
= setp
->ls_length
;
642 start
= &setp
->ls_items
[0];
643 stop
= &setp
->ls_items
[count
];