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
*,int);
60 static int link_aout_load_file(const char*, linker_file_t
*,int);
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
, int load_flags
);
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
,
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
, load_flags
));
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
| M_ZERO
);
162 af
->address
= baseptr
;
164 /* Assume _DYNAMIC is the first data item. */
165 af
->dynamic
= (struct _dynamic
*)(af
->address
+ ehdr
->a_text
);
166 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
168 return(0); /* we can't handle this */
170 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
171 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
173 /* Register with kld */
174 lf
= linker_make_file(filename
, af
, &link_aout_module_ops
);
179 lf
->address
= af
->address
;
180 lf
->size
= ehdr
->a_text
+ ehdr
->a_data
+ ehdr
->a_bss
;
182 /* Try to load dependancies */
183 if (((error
= load_dependancies(lf
, load_flags
)) != 0) ||
184 ((error
= relocate_file(lf
)) != 0)) {
185 linker_file_unload(lf
);
188 lf
->flags
|= LINKER_FILE_LINKED
;
194 link_aout_load_file(const char *filename
, linker_file_t
*result
, int load_flags
)
196 struct nlookupdata nd
;
197 struct thread
*td
= curthread
;
198 struct proc
*p
= td
->td_proc
;
209 if (p
->p_ucred
== NULL
) {
210 kprintf("link_aout_load_file: cannot load '%s' from filesystem"
211 " this early\n", filename
);
215 pathname
= linker_search_path(filename
);
216 if (pathname
== NULL
)
218 error
= nlookup_init(&nd
, pathname
, UIO_SYSSPACE
, NLC_FOLLOW
|NLC_LOCKVP
);
220 error
= vn_open(&nd
, NULL
, FREAD
, 0);
221 kfree(pathname
, M_LINKER
);
227 nd
.nl_open_vp
= NULL
;
231 * Read the a.out header from the file.
233 error
= vn_rdwr(UIO_READ
, vp
, (void*) &header
, sizeof header
, 0,
234 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
238 if (N_BADMAG(header
) || !(N_GETFLAG(header
) & EX_DYNAMIC
))
242 * We have an a.out file, so make some space to read it in.
244 af
= kmalloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
| M_ZERO
);
245 af
->address
= kmalloc(header
.a_text
+ header
.a_data
+ header
.a_bss
,
249 * Read the text and data sections and zero the bss.
251 error
= vn_rdwr(UIO_READ
, vp
, (void*) af
->address
,
252 header
.a_text
+ header
.a_data
, 0,
253 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
);
256 bzero(af
->address
+ header
.a_text
+ header
.a_data
, header
.a_bss
);
259 * Assume _DYNAMIC is the first data item.
261 af
->dynamic
= (struct _dynamic
*) (af
->address
+ header
.a_text
);
262 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
263 kfree(af
->address
, M_LINKER
);
267 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
268 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
270 lf
= linker_make_file(filename
, af
, &link_aout_file_ops
);
272 kfree(af
->address
, M_LINKER
);
277 lf
->address
= af
->address
;
278 lf
->size
= header
.a_text
+ header
.a_data
+ header
.a_bss
;
280 if ((error
= load_dependancies(lf
, load_flags
)) != 0
281 || (error
= relocate_file(lf
)) != 0) {
282 linker_file_unload(lf
);
286 lf
->flags
|= LINKER_FILE_LINKED
;
297 link_aout_unload_file(linker_file_t file
)
299 aout_file_t af
= file
->priv
;
303 kfree(af
->address
, M_LINKER
);
309 link_aout_unload_module(linker_file_t file
)
311 aout_file_t af
= file
->priv
;
316 preload_delete_name(file
->filename
);
319 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
322 load_dependancies(linker_file_t lf
, int load_flags
)
324 aout_file_t af
= lf
->priv
;
333 * All files are dependant on /kernel.
335 if (linker_kernel_file
) {
336 linker_kernel_file
->refs
++;
337 linker_file_add_dependancy(lf
, linker_kernel_file
);
340 off
= LD_NEED(af
->dynamic
);
343 * Load the dependancies.
346 sodp
= AOUT_RELOC(af
, struct sod
, off
);
347 name
= AOUT_RELOC(af
, char, sodp
->sod_name
);
349 error
= linker_load_file(name
, &lfdep
, load_flags
);
352 linker_file_add_dependancy(lf
, lfdep
);
353 off
= sodp
->sod_next
;
358 kfree(filename
, M_TEMP
);
363 * XXX i386 dependant.
366 read_relocation(struct relocation_info
* r
, char* addr
)
368 int length
= r
->r_length
;
370 return *(u_char
*) addr
;
371 else if (length
== 1)
372 return *(u_short
*) addr
;
373 else if (length
== 2)
374 return *(u_int
*) addr
;
376 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
381 write_relocation(struct relocation_info
* r
, char* addr
, long value
)
383 int length
= r
->r_length
;
385 *(u_char
*) addr
= value
;
386 else if (length
== 1)
387 *(u_short
*) addr
= value
;
388 else if (length
== 2)
389 *(u_int
*) addr
= value
;
391 kprintf("link_aout: unsupported relocation size %d\n", r
->r_length
);
395 relocate_file(linker_file_t lf
)
397 aout_file_t af
= lf
->priv
;
398 struct relocation_info
* rel
;
399 struct relocation_info
* erel
;
400 struct relocation_info
* r
;
401 struct nzlist
* symbolbase
;
407 rel
= AOUT_RELOC(af
, struct relocation_info
, LD_REL(af
->dynamic
));
408 erel
= AOUT_RELOC(af
, struct relocation_info
,
409 LD_REL(af
->dynamic
) + LD_RELSZ(af
->dynamic
));
410 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
411 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
413 for (r
= rel
; r
< erel
; r
++) {
416 if (r
->r_address
== 0)
419 addr
= AOUT_RELOC(af
, char, r
->r_address
);
421 np
= &symbolbase
[r
->r_symbolnum
];
422 sym
= &stringbase
[np
->nz_strx
];
425 kprintf("link_aout: bad symbol name %s\n", sym
);
426 kprintf("link_aout: symbol %s not found\n", sym
);
429 if (linker_file_lookup_symbol(lf
, sym
+ 1,
430 (np
->nz_type
!= (N_SETV
+N_EXT
)), (caddr_t
*)&relocation
)) {
431 kprintf("link_aout: symbol %s not found\n", sym
);
436 relocation
+= read_relocation(r
, addr
);
439 kprintf("link_aout: can't cope with jump table relocations\n");
444 relocation
-= (intptr_t) af
->address
;
447 kprintf("link_aout: can't cope with copy relocations\n");
451 write_relocation(r
, addr
, relocation
);
453 write_relocation(r
, addr
,
454 (intptr_t)(read_relocation(r
, addr
) + af
->address
));
463 symbol_hash_value(aout_file_t af
, const char* name
)
468 hashval
= '_'; /* fake a starting '_' for C symbols */
469 for (p
= name
; *p
; p
++)
470 hashval
= (hashval
<< 1) + *p
;
472 return (hashval
& 0x7fffffff) % LD_BUCKETS(af
->dynamic
);
476 link_aout_lookup_symbol(linker_file_t file
, const char* name
,
479 aout_file_t af
= file
->priv
;
481 struct rrs_hash
* hashbase
;
482 struct nzlist
* symbolbase
;
488 if (LD_BUCKETS(af
->dynamic
) == 0)
491 hashbase
= AOUT_RELOC(af
, struct rrs_hash
, LD_HASH(af
->dynamic
));
492 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
493 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
496 hashval
= symbol_hash_value(af
, name
);
497 hp
= &hashbase
[hashval
];
498 if (hp
->rh_symbolnum
== -1)
502 np
= (struct nzlist
*) &symbolbase
[hp
->rh_symbolnum
];
503 cp
= stringbase
+ np
->nz_strx
;
505 * Note: we fake the leading '_' for C symbols.
507 if (cp
[0] == '_' && !strcmp(cp
+ 1, name
))
510 if (hp
->rh_next
== 0)
513 hp
= &hashbase
[hp
->rh_next
];
523 * Check for an aliased symbol, whatever that is.
525 if (np
->nz_type
== N_INDR
+N_EXT
) {
526 name
= stringbase
+ (++np
)->nz_strx
+ 1; /* +1 for '_' */
531 * Check this is an actual definition of the symbol.
533 if (np
->nz_value
== 0)
536 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
537 if (np
->nz_other
== AUX_FUNC
)
542 *sym
= (linker_sym_t
) np
;
549 link_aout_symbol_values(linker_file_t file
, c_linker_sym_t sym
,
550 linker_symval_t
* symval
)
552 aout_file_t af
= file
->priv
;
553 const struct nzlist
* np
= (const struct nzlist
*) sym
;
555 long numsym
= LD_STABSZ(af
->dynamic
) / sizeof(struct nzlist
);
556 struct nzlist
*symbase
;
558 /* Is it one of ours? It could be another module... */
559 symbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
562 if ((np
- symbase
) > numsym
)
565 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
567 symval
->name
= stringbase
+ np
->nz_strx
+ 1; /* +1 for '_' */
568 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
570 symval
->size
= np
->nz_value
;
572 symval
->value
= AOUT_RELOC(af
, char, np
->nz_value
);
573 symval
->size
= np
->nz_size
;
579 link_aout_search_symbol(linker_file_t lf
, caddr_t value
,
580 c_linker_sym_t
* sym
, long* diffp
)
582 aout_file_t af
= lf
->priv
;
583 u_long off
= (uintptr_t) (void *) value
;
588 struct nzlist
* best
= 0;
590 for (sp
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
)),
591 ep
= (struct nzlist
*) ((caddr_t
) sp
+ LD_STABSZ(af
->dynamic
));
593 if (sp
->nz_name
== 0)
595 sp_nz_value
= sp
->nz_value
+ (uintptr_t) (void *) af
->address
;
596 if (off
>= sp_nz_value
) {
597 if (off
- sp_nz_value
< diff
) {
598 diff
= off
- sp_nz_value
;
602 } else if (off
- sp_nz_value
== diff
) {
611 *sym
= (linker_sym_t
) best
;
617 * Look up a linker set on an a.out + gnu LD system.
620 struct generic_linker_set
{
626 link_aout_lookup_set(linker_file_t lf
, const char *name
,
627 void ***startp
, void ***stopp
, int *countp
)
630 linker_symval_t symval
;
631 void **start
, **stop
;
633 struct generic_linker_set
*setp
;
635 error
= link_aout_lookup_symbol(lf
, name
, &sym
);
638 link_aout_symbol_values(lf
, sym
, &symval
);
639 if (symval
.value
== 0)
641 setp
= (struct generic_linker_set
*)symval
.value
;
642 count
= setp
->ls_length
;
643 start
= &setp
->ls_items
[0];
644 stop
= &setp
->ls_items
[count
];