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.14 2005/04/30 23:04:21 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
= malloc(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
= malloc(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 printf("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 free(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
, td
);
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
= malloc(sizeof(struct aout_file
), M_LINKER
, M_WAITOK
);
246 bzero(af
, sizeof(*af
));
247 af
->address
= malloc(header
.a_text
+ header
.a_data
+ header
.a_bss
,
251 * Read the text and data sections and zero the bss.
253 VOP_LEASE(vp
, td
, p
->p_ucred
, LEASE_READ
);
254 error
= vn_rdwr(UIO_READ
, vp
, (void*) af
->address
,
255 header
.a_text
+ header
.a_data
, 0,
256 UIO_SYSSPACE
, IO_NODELOCKED
, p
->p_ucred
, &resid
, td
);
259 bzero(af
->address
+ header
.a_text
+ header
.a_data
, header
.a_bss
);
262 * Assume _DYNAMIC is the first data item.
264 af
->dynamic
= (struct _dynamic
*) (af
->address
+ header
.a_text
);
265 if (af
->dynamic
->d_version
!= LD_VERSION_BSD
) {
266 free(af
->address
, M_LINKER
);
270 af
->dynamic
->d_un
.d_sdt
= (struct section_dispatch_table
*)
271 ((char *)af
->dynamic
->d_un
.d_sdt
+ (vm_offset_t
)af
->address
);
273 lf
= linker_make_file(filename
, af
, &link_aout_file_ops
);
275 free(af
->address
, M_LINKER
);
280 lf
->address
= af
->address
;
281 lf
->size
= header
.a_text
+ header
.a_data
+ header
.a_bss
;
283 if ((error
= load_dependancies(lf
)) != 0
284 || (error
= relocate_file(lf
)) != 0) {
285 linker_file_unload(lf
);
289 lf
->flags
|= LINKER_FILE_LINKED
;
293 VOP_UNLOCK(vp
, 0, td
);
294 vn_close(vp
, FREAD
, td
);
300 link_aout_unload_file(linker_file_t file
)
302 aout_file_t af
= file
->priv
;
306 free(af
->address
, M_LINKER
);
312 link_aout_unload_module(linker_file_t file
)
314 aout_file_t af
= file
->priv
;
319 preload_delete_name(file
->filename
);
322 #define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off))
325 load_dependancies(linker_file_t lf
)
327 aout_file_t af
= lf
->priv
;
336 * All files are dependant on /kernel.
338 if (linker_kernel_file
) {
339 linker_kernel_file
->refs
++;
340 linker_file_add_dependancy(lf
, linker_kernel_file
);
343 off
= LD_NEED(af
->dynamic
);
346 * Load the dependancies.
349 sodp
= AOUT_RELOC(af
, struct sod
, off
);
350 name
= AOUT_RELOC(af
, char, sodp
->sod_name
);
352 error
= linker_load_file(name
, &lfdep
);
355 error
= linker_file_add_dependancy(lf
, lfdep
);
358 off
= sodp
->sod_next
;
363 free(filename
, M_TEMP
);
368 * XXX i386 dependant.
371 read_relocation(struct relocation_info
* r
, char* addr
)
373 int length
= r
->r_length
;
375 return *(u_char
*) addr
;
376 else if (length
== 1)
377 return *(u_short
*) addr
;
378 else if (length
== 2)
379 return *(u_int
*) addr
;
381 printf("link_aout: unsupported relocation size %d\n", r
->r_length
);
386 write_relocation(struct relocation_info
* r
, char* addr
, long value
)
388 int length
= r
->r_length
;
390 *(u_char
*) addr
= value
;
391 else if (length
== 1)
392 *(u_short
*) addr
= value
;
393 else if (length
== 2)
394 *(u_int
*) addr
= value
;
396 printf("link_aout: unsupported relocation size %d\n", r
->r_length
);
400 relocate_file(linker_file_t lf
)
402 aout_file_t af
= lf
->priv
;
403 struct relocation_info
* rel
;
404 struct relocation_info
* erel
;
405 struct relocation_info
* r
;
406 struct nzlist
* symbolbase
;
412 rel
= AOUT_RELOC(af
, struct relocation_info
, LD_REL(af
->dynamic
));
413 erel
= AOUT_RELOC(af
, struct relocation_info
,
414 LD_REL(af
->dynamic
) + LD_RELSZ(af
->dynamic
));
415 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
416 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
418 for (r
= rel
; r
< erel
; r
++) {
421 if (r
->r_address
== 0)
424 addr
= AOUT_RELOC(af
, char, r
->r_address
);
426 np
= &symbolbase
[r
->r_symbolnum
];
427 sym
= &stringbase
[np
->nz_strx
];
430 printf("link_aout: bad symbol name %s\n", sym
);
431 printf("link_aout: symbol %s not found\n", sym
);
434 if (linker_file_lookup_symbol(lf
, sym
+ 1,
435 (np
->nz_type
!= (N_SETV
+N_EXT
)), (caddr_t
*)&relocation
)) {
436 printf("link_aout: symbol %s not found\n", sym
);
441 relocation
+= read_relocation(r
, addr
);
444 printf("link_aout: can't cope with jump table relocations\n");
449 relocation
-= (intptr_t) af
->address
;
452 printf("link_aout: can't cope with copy relocations\n");
456 write_relocation(r
, addr
, relocation
);
458 write_relocation(r
, addr
,
459 (intptr_t)(read_relocation(r
, addr
) + af
->address
));
468 symbol_hash_value(aout_file_t af
, const char* name
)
473 hashval
= '_'; /* fake a starting '_' for C symbols */
474 for (p
= name
; *p
; p
++)
475 hashval
= (hashval
<< 1) + *p
;
477 return (hashval
& 0x7fffffff) % LD_BUCKETS(af
->dynamic
);
481 link_aout_lookup_symbol(linker_file_t file
, const char* name
,
484 aout_file_t af
= file
->priv
;
486 struct rrs_hash
* hashbase
;
487 struct nzlist
* symbolbase
;
493 if (LD_BUCKETS(af
->dynamic
) == 0)
496 hashbase
= AOUT_RELOC(af
, struct rrs_hash
, LD_HASH(af
->dynamic
));
497 symbolbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
498 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
501 hashval
= symbol_hash_value(af
, name
);
502 hp
= &hashbase
[hashval
];
503 if (hp
->rh_symbolnum
== -1)
507 np
= (struct nzlist
*) &symbolbase
[hp
->rh_symbolnum
];
508 cp
= stringbase
+ np
->nz_strx
;
510 * Note: we fake the leading '_' for C symbols.
512 if (cp
[0] == '_' && !strcmp(cp
+ 1, name
))
515 if (hp
->rh_next
== 0)
518 hp
= &hashbase
[hp
->rh_next
];
528 * Check for an aliased symbol, whatever that is.
530 if (np
->nz_type
== N_INDR
+N_EXT
) {
531 name
= stringbase
+ (++np
)->nz_strx
+ 1; /* +1 for '_' */
536 * Check this is an actual definition of the symbol.
538 if (np
->nz_value
== 0)
541 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
542 if (np
->nz_other
== AUX_FUNC
)
547 *sym
= (linker_sym_t
) np
;
554 link_aout_symbol_values(linker_file_t file
, c_linker_sym_t sym
,
555 linker_symval_t
* symval
)
557 aout_file_t af
= file
->priv
;
558 const struct nzlist
* np
= (const struct nzlist
*) sym
;
560 long numsym
= LD_STABSZ(af
->dynamic
) / sizeof(struct nzlist
);
561 struct nzlist
*symbase
;
563 /* Is it one of ours? It could be another module... */
564 symbase
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
));
567 if ((np
- symbase
) > numsym
)
570 stringbase
= AOUT_RELOC(af
, char, LD_STRINGS(af
->dynamic
));
572 symval
->name
= stringbase
+ np
->nz_strx
+ 1; /* +1 for '_' */
573 if (np
->nz_type
== N_UNDF
+N_EXT
&& np
->nz_value
!= 0) {
575 symval
->size
= np
->nz_value
;
577 symval
->value
= AOUT_RELOC(af
, char, np
->nz_value
);
578 symval
->size
= np
->nz_size
;
584 link_aout_search_symbol(linker_file_t lf
, caddr_t value
,
585 c_linker_sym_t
* sym
, long* diffp
)
587 aout_file_t af
= lf
->priv
;
588 u_long off
= (uintptr_t) (void *) value
;
593 struct nzlist
* best
= 0;
595 for (sp
= AOUT_RELOC(af
, struct nzlist
, LD_SYMBOL(af
->dynamic
)),
596 ep
= (struct nzlist
*) ((caddr_t
) sp
+ LD_STABSZ(af
->dynamic
));
598 if (sp
->nz_name
== 0)
600 sp_nz_value
= sp
->nz_value
+ (uintptr_t) (void *) af
->address
;
601 if (off
>= sp_nz_value
) {
602 if (off
- sp_nz_value
< diff
) {
603 diff
= off
- sp_nz_value
;
607 } else if (off
- sp_nz_value
== diff
) {
616 *sym
= (linker_sym_t
) best
;
622 * Look up a linker set on an a.out + gnu LD system.
625 struct generic_linker_set
{
631 link_aout_lookup_set(linker_file_t lf
, const char *name
,
632 void ***startp
, void ***stopp
, int *countp
)
635 linker_symval_t symval
;
636 void **start
, **stop
;
638 struct generic_linker_set
*setp
;
640 error
= link_aout_lookup_symbol(lf
, name
, &sym
);
643 link_aout_symbol_values(lf
, sym
, &symval
);
644 if (symval
.value
== 0)
646 setp
= (struct generic_linker_set
*)symval
.value
;
647 count
= setp
->ls_length
;
648 start
= &setp
->ls_items
[0];
649 stop
= &setp
->ls_items
[count
];