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 link (objects &key
(out-name "a.out")
48 "Link the objects specified by the filenames contained in the list
49 OBJECTS into a binary called OUT-NAME. The objects are linked
50 serially by list order."
51 (setf *global-symbols
* (make-hash-table :test
#'equal
))
52 (let* ((segment-sizes (list (cons 'text
0)
57 "Read a module with filename OBJECT, merge symbols
58 into global symbol table, and update segment sizes."
59 (let ((module (read-module object
)))
60 ;; merge symbols into global symbol table
61 (dovector (sym (module-symbols module
))
62 (setf (linker-symbol-module sym
) module
)
63 (sif (gethash (linker-symbol-name sym
) *global-symbols
*)
65 (setf it
(list sym
))))
66 (dolist (x segment-sizes
)
67 (incf (cdr x
) (module-segment-size module
(car x
))))
71 (allocate-module-bases modules segment-sizes
)
74 (:gemdos-prg
(link-prg modules segment-sizes out-name
))
75 (:binary
(link-raw-bin modules segment-sizes out-name entry-point
)))))
77 (defun allocate-module-bases (modules segment-sizes
)
78 (let ((bases (list (cons 'text
0)
79 (cons 'data
#1=(cdr (assoc 'text segment-sizes
)))
80 (cons 'bss
(+ (cdr (assoc 'data segment-sizes
))
82 (dolist (module modules
)
83 (setf (module-segment-bases module
) (copy-list bases
))
84 (format t
"~&relocating ~A at ~A" (module-name module
)
85 (module-segment-bases module
))
87 (incf (cdr x
) (module-segment-size module
(car x
)))))))
90 (defun fix-relocation-symbol (reloc module
)
91 (if (relocation-extern-p reloc
)
92 (setf (relocation-symbol reloc
) (aref (module-symbols module
)
93 (relocation-symbol reloc
)))
94 (setf (relocation-symbol reloc
) (nth (relocation-symbol reloc
)
97 (defun fix-relocation-address (reloc module segment
)
98 (incf (relocation-address reloc
)
99 (module-segment-base module segment
)))
102 (defun process-link-time-relocations (stream modules
)
103 "Goes through the relocations for each module, applies whichever
104 relocations can be done at link time, and then pushes the remainder
105 onto the fixup list, which it returns, in ascending order of address."
107 (position (file-position stream
)))
108 (dolist (module modules
)
111 (dovector (reloc (module-segment-relocations module segment
))
112 (fix-relocation-symbol reloc module
)
113 (fix-relocation-address reloc module segment
)
115 (if (relocation-pc-relative-p reloc
)
116 (if (relocation-extern-p reloc
)
117 (relocate-pcrel-extern stream module segment reloc
)
118 (relocate-pc-relative stream module segment reloc
))
119 (if (relocation-extern-p reloc
)
120 (relocate-abs-extern stream module segment reloc
)
121 (relocate-absolute stream module segment reloc
)))
124 (file-position stream position
)
127 (defun file-offset-of-address (address)
128 (+ address
*current-header-length
*))
131 ;;; XXX should use more gensyms in case other things want to be called
133 (defmacro patch-stream
((var length
134 stream
&optional
(position (file-position stream
)))
136 (let ((pos-holder (gensym)))
137 `(let ((,pos-holder
,position
))
138 (file-position ,stream
,pos-holder
)
139 (let ((,var
(read-big-endian-data ,stream
,length
)))
141 (file-position ,stream
,pos-holder
)
142 (write-big-endian-data ,stream
,var
,length
)))))
145 (defun relocate-absolute (stream module segment reloc
)
146 (declare (ignore segment
))
147 (let ((base (module-segment-base module
(relocation-symbol reloc
)))
148 (length (relocation-length reloc
)))
149 (patch-stream (value length stream
(file-offset-of-address
150 (relocation-address reloc
)))
152 ;; adjust address according to length
154 (format t
"~&short fixup ~A ~A" length
(relocation-address reloc
))
155 (decf (relocation-address reloc
) (ceiling (- 32 length
) 8))))
157 (when (oddp (relocation-address reloc
))
158 (format t
"~&probably emitting a bad fixup: ~A ~A ~A"
159 (relocation-symbol reloc
)
161 (relocation-address reloc
))
162 (incf (relocation-address reloc
)))
163 (relocation-address reloc
))
165 (defun relocate-abs-extern (stream module segment reloc
)
166 (declare (ignore segment module
))
167 (let ((symbol (find-first-non-extern-instance (relocation-symbol reloc
)))
168 (length (relocation-length reloc
)))
170 (error "~A is an undefined symbol referenced in ~A."
171 (linker-symbol-name (relocation-symbol reloc
))
172 (module-name (linker-symbol-module (relocation-symbol reloc
)))))
173 (patch-stream (value length stream
(file-offset-of-address
174 (relocation-address reloc
)))
175 (setf value
(+ (linker-symbol-value symbol
)
176 (module-segment-base (linker-symbol-module symbol
)
177 (linker-symbol-type symbol
)))))
178 ;; adjust address according to length
180 (decf (relocation-address reloc
) (ceiling (- 32 length
) 8))))
181 (relocation-address reloc
))
184 (defun find-first-non-extern-instance (symbol)
185 "Returns the first non-external instance of SYMBOL in the global
186 symbol table, or NIL."
187 (let ((sym-list (gethash (linker-symbol-name symbol
)
189 (find-if (lambda (x) (not (eq (linker-symbol-type x
) 'extern
)))
192 (defun relocate-pcrel-extern (stream module segment reloc
)
193 (declare (ignore segment module
))
194 (let ((symbol (find-first-non-extern-instance (relocation-symbol reloc
)))
195 (length (relocation-length reloc
)))
196 (patch-stream (value length stream
(file-offset-of-address
197 (relocation-address reloc
)))
198 (setf value
(- (+ (linker-symbol-value symbol
)
199 (module-segment-base (linker-symbol-module symbol
)
200 (linker-symbol-type symbol
)))
201 (relocation-address reloc
)))
203 (error "This should have been fixed.")
204 (decf value
)))) ; fix 24-bit pc-rel problem.
207 (defun relocate-pc-relative (stream module segment reloc
)
208 (declare (ignore segment module stream reloc
))
209 (error "~&pcrel: wish i could say this was being handled.")