4 ;;; Julian Squires / 2005
7 (in-package :st-linker
)
18 (defun module-segment-base (module segment
)
19 (cdr (assoc segment
(module-segment-bases module
))))
20 (defun module-segment-size (module segment
)
21 (cdr (assoc segment
(module-segment-sizes module
))))
22 (defun module-segment-relocations (module segment
)
23 (cdr (assoc segment
(module-relocations module
))))
33 (defstruct linker-symbol
37 ;; global-p, debug-info
40 (defvar *global-symbols
* nil
)
41 (defvar *current-header-length
* nil
)
45 (defun merge-symbols-into-global-table (module global-symbols
)
46 (dovector (sym (module-symbols module
))
47 (setf (linker-symbol-module sym
) module
)
48 (sif (gethash (linker-symbol-name sym
) global-symbols
)
50 (setf it
(list sym
)))))
52 (defun link (objects &key
(out-name "a.out")
55 "Link the objects specified by the filenames contained in the list
56 OBJECTS into a binary called OUT-NAME. The objects are linked
57 serially by list order."
58 (setf *global-symbols
* (make-hash-table :test
#'equal
))
59 (let* ((segment-sizes (list (cons 'text
0)
65 "Read a module with filename OBJECT, merge symbols into
66 global symbol table, and update segment sizes."
67 (let ((module (read-module object
)))
68 (merge-symbols-into-global-table module
*global-symbols
*)
69 (dolist (x segment-sizes
)
70 (incf (cdr x
) (module-segment-size module
(car x
))))
74 (allocate-module-bases modules segment-sizes
)
77 (:gemdos-prg
(link-prg modules segment-sizes out-name
))
78 (:binary
(link-raw-bin modules segment-sizes out-name entry-point
)))))
80 (defun allocate-module-bases (modules segment-sizes
)
81 (let ((bases (list (cons 'text
0)
82 (cons 'data
(cdr (assoc 'text segment-sizes
)))
83 (cons 'bss
(+ (cdr (assoc 'data segment-sizes
))
84 (cdr (assoc 'text segment-sizes
)))))))
85 (dolist (module modules
)
86 (setf (module-segment-bases module
) (copy-alist bases
))
87 (format t
"~&relocating ~A at ~A" (module-name module
)
88 (module-segment-bases module
))
90 (incf (cdr x
) (module-segment-size module
(car x
)))))))
93 (defun fix-relocation-symbol (reloc module
)
94 (if (relocation-extern-p reloc
)
95 (setf (relocation-symbol reloc
) (aref (module-symbols module
)
96 (relocation-symbol reloc
)))
97 (setf (relocation-symbol reloc
) (nth (relocation-symbol reloc
)
100 (defun fix-relocation-address (reloc module segment
)
101 (incf (relocation-address reloc
)
102 (module-segment-base module segment
)))
105 (defun process-link-time-relocations (stream modules
)
106 "Goes through the relocations for each module, applies whichever
107 relocations can be done at link time, and then pushes the remainder
108 onto the fixup list, which it returns, in ascending order of address."
110 (position (file-position stream
)))
111 (dolist (module modules
)
114 (dovector (reloc (module-segment-relocations module segment
))
115 (fix-relocation-symbol reloc module
)
116 (fix-relocation-address reloc module segment
)
118 (if (relocation-pc-relative-p reloc
)
119 (if (relocation-extern-p reloc
)
120 (relocate-pcrel-extern stream module segment reloc
)
121 (relocate-pc-relative stream module segment reloc
))
122 (if (relocation-extern-p reloc
)
123 (relocate-abs-extern stream module segment reloc
)
124 (relocate-absolute stream module segment reloc
)))
127 (file-position stream position
)
130 (defun file-offset-of-address (address)
131 (+ address
*current-header-length
*))
134 ;;; XXX should use more gensyms in case other things want to be called
136 (defmacro patch-stream
((var length stream
137 &optional
(position (file-position stream
)))
139 (let ((pos-holder (gensym)))
140 `(let ((,pos-holder
,position
))
141 (file-position ,stream
,pos-holder
)
142 (let ((,var
(read-big-endian-data ,stream
,length
)))
144 (file-position ,stream
,pos-holder
)
145 (write-big-endian-data ,stream
,var
,length
)))))
148 (defun relocate-absolute (stream module segment reloc
)
149 (declare (ignore segment
))
150 (let ((base (module-segment-base module
(relocation-symbol reloc
)))
151 (length (relocation-length reloc
)))
152 (patch-stream (value length stream
(file-offset-of-address
153 (relocation-address reloc
)))
155 ;; adjust address according to length
157 (format t
"~&short fixup ~A ~A" length
(relocation-address reloc
))
158 (decf (relocation-address reloc
) (ceiling (- 32 length
) 8))))
160 (when (oddp (relocation-address reloc
))
161 (format t
"~&probably emitting a bad fixup: ~A ~A ~A"
162 (relocation-symbol reloc
)
164 (relocation-address reloc
))
165 (incf (relocation-address reloc
)))
166 (relocation-address reloc
))
168 (defun relocate-abs-extern (stream module segment reloc
)
169 (declare (ignore segment module
))
170 (let ((symbol (find-first-non-extern-instance (relocation-symbol reloc
)))
171 (length (relocation-length reloc
)))
173 (error "~A is an undefined symbol referenced in ~A."
174 (linker-symbol-name (relocation-symbol reloc
))
175 (module-name (linker-symbol-module (relocation-symbol reloc
)))))
176 (patch-stream (value length stream
(file-offset-of-address
177 (relocation-address reloc
)))
178 (setf value
(+ (linker-symbol-value symbol
)
179 (module-segment-base (linker-symbol-module symbol
)
180 (linker-symbol-type symbol
)))))
181 ;; adjust address according to length
183 (decf (relocation-address reloc
) (ceiling (- 32 length
) 8))))
184 (relocation-address reloc
))
187 (defun find-first-non-extern-instance (symbol)
188 "Returns the first non-external instance of SYMBOL in the global
189 symbol table, or NIL."
190 (let ((sym-list (gethash (linker-symbol-name symbol
)
192 (find-if (lambda (x) (not (eq (linker-symbol-type x
) 'extern
)))
195 (defun relocate-pcrel-extern (stream module segment reloc
)
196 (declare (ignore segment module
))
197 (let ((symbol (find-first-non-extern-instance (relocation-symbol reloc
)))
198 (length (relocation-length reloc
)))
199 (patch-stream (value length stream
(file-offset-of-address
200 (relocation-address reloc
)))
201 (setf value
(- (+ (linker-symbol-value symbol
)
202 (module-segment-base (linker-symbol-module symbol
)
203 (linker-symbol-type symbol
)))
204 (relocation-address reloc
)))
206 (error "This should have been fixed.")
207 (decf value
)))) ; fix 24-bit pc-rel problem.
210 (defun relocate-pc-relative (stream module segment reloc
)
211 (declare (ignore segment module stream reloc
))
212 (error "~&pcrel: wish i could say this was being handled.")