source: branches/arm/library/elf.lisp @ 13986

Last change on this file since 13986 was 13986, checked in by gb, 10 years ago

Conditionalize for ARM (and maybe PPC, finally.)

File size: 21.1 KB
Line 
1;;; Copyright 2009 Clozure Associates
2;;; This file is part of Clozure CL. 
3;;;
4;;; Clozure CL is licensed under the terms of the Lisp Lesser GNU
5;;; Public License , known as the LLGPL and distributed with Clozure
6;;; CL as the file "LICENSE".  The LLGPL consists of a preamble and
7;;; the LGPL, which is distributed with Clozure CL as the file "LGPL".
8;;; Where these conflict, the preamble takes precedence.
9;;;
10;;; Clozure CL is referenced in the preamble as the "LIBRARY."
11;;;
12;;; The LLGPL is also available online at
13;;; http://opensource.franz.com/preamble.html
14
15(in-package "CCL")
16
17(eval-when (:compile-toplevel :execute)
18  (use-interface-dir :elf))
19
20
21(defloadvar *readonly-area*
22    (do-consing-areas (a)
23      (when (eql (%fixnum-ref a target::area.code)
24                 ccl::area-readonly)
25        (return a))))
26
27;;; String tables: used both for symbol names and for section names.
28(defstruct elf-string-table
29  (hash (make-hash-table :test #'equal))
30  (string (make-array 100 :element-type '(unsigned-byte 8) :fill-pointer 1 :adjustable t)))
31
32;;; Collect info about Elf symbols.
33(defstruct elf-symbol-table
34  (strings (make-elf-string-table))
35  data                                  ; foreign pointer
36  nsyms
37  )
38
39;;; Wrapper around libelf's "elf" pointer
40(defstruct elf-object
41  libelf-pointer
42  fd
43  pathname
44  )
45
46
47;;; Is libelf thread-safe ?  Who knows, there's no
48;;; documentation ...
49(defun libelf-error-string (&optional (errnum -1))
50  (let* ((p (#_elf_errmsg errnum)))
51    (if (%null-ptr-p p)
52      (format nil "ELF error ~d" errnum)
53      (%get-cstring p))))
54
55(defloadvar *checked-libelf-version* nil)
56
57(defun check-libelf-version ()
58  (or *checked-libelf-version*
59      (progn
60        (open-shared-library "libelf.so")
61        (let* ((version (#_elf_version #$EV_CURRENT)))
62          (if (eql #$EV_NONE version)
63            (error "ELF library initialization failed: ~a" (libelf-error-string)))
64          (setq *checked-libelf-version* version)))))
65
66
67;;; Prepate to create an ELF object file at PATHNAME, overwriting
68;;; whatever might have been there.
69(defun create-elf-object (pathname)
70  (let* ((namestring (native-translated-namestring pathname))
71         (fd (ccl::fd-open namestring
72                           (logior #$O_RDWR #$O_CREAT #$O_TRUNC)
73                           #o755)))
74    (if (< fd 0)
75      (signal-file-error fd pathname)
76      (progn
77        (check-libelf-version)
78        (let* ((ptr (#_elf_begin fd #$ELF_C_WRITE +null-ptr+)))
79          (if (%null-ptr-p ptr)
80            (error "Can't initialize libelf object for ~s: ~a"
81                   pathname (libelf-error-string))
82            (make-elf-object :libelf-pointer (assert-pointer-type ptr :<E>lf)
83                             :fd fd
84                             :pathname pathname)))))))
85
86(defun elf-end (object)
87  (#_elf_end (elf-object-libelf-pointer object))
88  (setf (elf-object-libelf-pointer object) nil
89        (elf-object-fd object) nil))
90
91(defun new-elf-file-header (object format type machine)
92  (let* ((ehdr (#+64-bit-target #_elf64_newehdr #+32-bit-target #_elf32_newehdr (elf-object-libelf-pointer object))))
93    (if (%null-ptr-p ehdr)
94      (error "Can't create ELF file header for ~s: ~a"
95             (elf-object-pathname object)
96             (libelf-error-string))
97      (progn
98        (setf (paref (pref ehdr
99                           #+64-bit-target :<E>lf64_<E>hdr.e_ident
100                           #+32-bit-target :<E>lf32_<E>hdr.e_ident) (:* :unsigned-char) #$EI_DATA) format
101              (pref ehdr
102                    #+64-bit-target :<E>lf64_<E>hdr.e_machine
103                    #+32-bit-target :<E>lf32_<E>hdr.e_machine) machine
104              (pref ehdr
105                    #+64-bit-target :<E>lf64_<E>hdr.e_type
106                    #+32-bit-target :<E>lf32_<E>hdr.e_type) type
107              (pref ehdr
108                    #+64-bit-target :<E>lf64_<E>hdr.e_version
109                    #+32-bit-target :<E>lf32_<E>hdr.e_version) *checked-libelf-version*)
110        (assert-pointer-type ehdr
111                             #+64-bit-target :<E>lf64_<E>hdr
112                             #+32-bit-target :<E>lf32_<E>hdr)))))
113
114(defun new-elf-program-header (object &optional (count 1))
115  (let* ((phdr (#+64-bit-target #_elf64_newphdr #+32-bit-target #_elf32_newphdr (elf-object-libelf-pointer object) count)))
116    (if (%null-ptr-p phdr)
117      (error "Can't create ELF program header for ~s: ~a"
118             (elf-object-pathname object)
119             (libelf-error-string))
120      (assert-pointer-type phdr
121                           #+64-bit-target :<E>lf64_<P>hdr
122                           #+32-bit-target :<E>lf32_<P>hdr))))
123
124(defun new-elf-section (object)
125  (let* ((scn (#_elf_newscn (elf-object-libelf-pointer object))))
126    (if (%null-ptr-p scn)
127      (error "Can' create ELF section for ~s: ~a"
128             (elf-object-pathname object)
129             (libelf-error-string))
130      (assert-pointer-type scn :<E>lf_<S>cn))))
131
132(defun elf-section-header-for-section (object section)
133  (let* ((shdr (#+64-bit-target #_elf64_getshdr #+32-bit-target #_elf32_getshdr  section)))
134    (if (%null-ptr-p shdr)
135      (error "Can' obtain ELF section header for ~s: ~a"
136             (elf-object-pathname object)
137             (libelf-error-string))
138      (assert-pointer-type shdr
139                           #+64-bit-target :<E>lf64_<S>hdr
140                           #+32-bit-target :<E>lf32_<S>hdr))))
141
142(defun elf-data-pointer-for-section (object section)
143  (let* ((data (#_elf_newdata section)))
144    (if (%null-ptr-p data)
145      (error "Can' obtain ELF data pointer for ~s: ~a"
146             (elf-object-pathname object)
147             (libelf-error-string))
148      (assert-pointer-type data :<E>lf_<D>ata))))
149                   
150
151(defun elf-register-string (string table)
152  (let* ((hash (elf-string-table-hash table))
153         (s (elf-string-table-string table)))
154    (when (gethash string hash)
155      (format t "~& duplicate: ~s" string))
156    (or (gethash string hash)
157        (setf (gethash string hash)
158              (let* ((n (length s)))
159                (dotimes (i (length string) (progn (vector-push-extend 0 s) n))
160                  (let* ((code (char-code (char string i))))
161                    (declare (type (mod #x110000) code))
162                    (if (> code 255)
163                      (vector-push-extend (char-code #\sub) s)
164                      (vector-push-extend code s)))))))))
165
166
167(defun elf-lisp-function-name (f)
168  (let* ((name (format nil "~s" f)))
169    (subseq (nsubstitute #\0 #\# (nsubstitute #\. #\Space name)) 1)))
170
171
172#+x86-target
173(defun collect-elf-static-functions ()
174  (collect ((functions))
175    (purify)
176    (block walk
177      (%map-areas (lambda (o)
178                    (when (typep o
179                                 #+x8664-target 'function-vector
180                                 #-x8664-target 'function)
181                      (functions (function-vector-to-function o))))
182                  ccl::area-readonly
183                  ccl::area-readonly
184                  ))
185    (functions)))
186
187#+(or arm-target ppc-target)
188(defun collect-elf-static-functions ()
189  (ccl::purify)
190  (multiple-value-bind (pure-low pure-high)
191      (ccl::do-gc-areas (a)
192        (when (eql(ccl::%fixnum-ref a target::area.code)
193                  ccl::area-readonly)
194          (return
195            (values (ash (ccl::%fixnum-ref a target::area.low) target::fixnumshift)
196                    (ash (ccl::%fixnum-ref a target::area.active) target::fixnumshift)))))
197    (let* ((hash (make-hash-table :test #'eq))
198           (code-vector-index #+ppc-target 0 #+arm-target 1))
199      (ccl::%map-lfuns #'(lambda (f)
200                           (let* ((code-vector  (ccl:uvref f code-vector-index))
201                                  (startaddr (+ (ccl::%address-of code-vector)
202                                                target::misc-data-offset)))
203                             (when (and (>= startaddr pure-low)
204                                        (< startaddr pure-high))
205                               (push f (gethash code-vector hash))))))
206      (let* ((n 0))
207        (declare (fixnum n))
208        (maphash #'(lambda (k v)
209                     (declare (ignore k))
210                     (if (null (cdr v))
211                       (incf n)))
212                 hash)
213        (let* ((functions ()))
214          (maphash #'(lambda (k v)
215                       (declare (ignore k))
216                       (when (null (cdr v))
217                         (push (car v) functions)))
218                   hash)
219          (sort functions
220                #'(lambda (x y)
221                    (< (ccl::%address-of (uvref x code-vector-index))
222                       (ccl::%address-of (uvref y code-vector-index))))))))))
223
224(defun register-elf-functions (section-number)
225  (let* ((functions (collect-elf-static-functions))
226         (n (length functions))
227         (data (#_calloc (1+ n) (record-length #+64-bit-target :<E>lf64_<S>ym
228                                               #+32-bit-target :<E>lf32_<S>ym)))
229         (string-table (make-elf-string-table)))
230    (declare (fixnum n))
231    (do* ((i 0 (1+ i))
232          (p (%inc-ptr data
233                       (record-length #+64-bit-target :<E>lf64_<S>ym
234                                      #+32-bit-target :<E>lf32_<S>ym))
235             (progn (%incf-ptr p
236                               (record-length #+64-bit-target :<E>lf64_<S>ym
237                                              #+32-bit-target :<E>lf32_<S>ym))
238                    p))
239          (f (pop functions) (pop functions)))
240         ((= i n)
241          (make-elf-symbol-table :strings string-table :data data :nsyms n))
242      (declare (fixnum n))
243      (setf (pref p
244                  #+64-bit-target :<E>lf64_<S>ym.st_name
245                  #+32-bit-target :<E>lf32_<S>ym.st_name)
246            (elf-register-string (elf-lisp-function-name f) string-table)
247            (pref p
248                  #+64-bit-target :<E>lf64_<S>ym.st_info
249                  #+32-bit-target :<E>lf32_<S>ym.st_info)
250            (logior (ash #$STB_GLOBAL 4) #$STT_FUNC)
251            (pref p
252                  #+64-bit-target :<E>lf64_<S>ym.st_shndx
253                  #+32-bit-target :<E>lf32_<S>ym.st_shndx) section-number
254            (pref p
255                  #+64-bit-target :<E>lf64_<S>ym.st_value
256                  #+32-bit-target :<E>lf32_<S>ym.st_value)
257            #+x86-target (%address-of f)
258            #+ppc-target (- (%address-of (uvref f 0)) (- ppc::fulltag-misc ppc::node-size))
259            #+arm-target (- (%address-of (uvref f 1)) (- arm::fulltag-misc arm::node-size))
260            (pref p
261                  #+64-bit-target :<E>lf64_<S>ym.st_size
262                  #+32-bit-target :<E>lf32_<S>ym.st_size)
263            #+x86-target (1+ (ash (1- (%function-code-words f)) target::word-shift))
264            #+ppc-target (ash (uvsize (uvref f 0)) ppc::word-shift)
265            #+arm-target (ash (uvsize (uvref f 1)) arm::word-shift)
266            ))))
267
268(defun elf-section-index (section)
269  (#_elf_ndxscn section))
270
271(defun elf-set-shstrab-section (object scn)
272  #+freebsd-target
273  (#_elf_setshstrndx (elf-object-libelf-pointer object) (elf-section-index scn))
274  #-freebsd-target
275  (declare (ignore object scn)))
276
277
278(defun elf-init-section-data-from-string-table (object section string-table)
279  (let* ((strings-data (elf-data-pointer-for-section object section))
280         (s (elf-string-table-string string-table))
281         (bytes (array-data-and-offset s))
282         (n (length s))
283         (buf (#_malloc n)))
284    (%copy-ivector-to-ptr bytes 0 buf 0 n)
285    (setf (pref strings-data :<E>lf_<D>ata.d_align) 1
286          (pref strings-data :<E>lf_<D>ata.d_off) 0
287          (pref strings-data :<E>lf_<D>ata.d_type) #$ELF_T_BYTE
288          (pref strings-data :<E>lf_<D>ata.d_version) #$EV_CURRENT
289          (pref strings-data :<E>lf_<D>ata.d_size) n
290          (pref strings-data :<E>lf_<D>ata.d_buf) buf)
291    n))
292
293(defun elf-init-symbol-section-from-symbol-table (object section symbols)
294  (let* ((symbols-data (elf-data-pointer-for-section object section))
295         (buf (elf-symbol-table-data symbols))
296         (nsyms (elf-symbol-table-nsyms symbols) )
297         (n (* (1+ nsyms) (record-length #+64-bit-target :<E>lf64_<S>ym
298                                         #+32-bit-target :<E>lf32_<S>ym))))
299    (setf (pref symbols-data :<E>lf_<D>ata.d_align) 8
300          (pref symbols-data :<E>lf_<D>ata.d_off) 0
301          (pref symbols-data :<E>lf_<D>ata.d_type) #$ELF_T_SYM
302          (pref symbols-data :<E>lf_<D>ata.d_version) #$EV_CURRENT
303          (pref symbols-data :<E>lf_<D>ata.d_size) n
304          (pref symbols-data :<E>lf_<D>ata.d_buf) buf)
305    nsyms))
306
307(defun elf-make-empty-data-for-section (object section &optional (size 0))
308  (let* ((data (elf-data-pointer-for-section object section))
309         (buf +null-ptr+))
310    (setf (pref data :<E>lf_<D>ata.d_align) 0
311          (pref data :<E>lf_<D>ata.d_off) 0
312          (pref data :<E>lf_<D>ata.d_type) #$ELF_T_BYTE
313          (pref data :<E>lf_<D>ata.d_version) #$EV_CURRENT
314          (pref data :<E>lf_<D>ata.d_size) size
315          (pref data :<E>lf_<D>ata.d_buf) buf)
316    0))
317 
318
319(defun elf-flag-phdr (object cmd flags)
320  (#_elf_flagphdr (elf-object-libelf-pointer object) cmd flags))
321
322(defun elf-update (object cmd)
323  (let* ((size (#_elf_update (elf-object-libelf-pointer object) cmd)))
324    (if (< size 0)
325      (error "elf_update failed for for ~s: ~a"
326             (elf-object-pathname object)
327             (libelf-error-string))
328      size)))
329
330(defun fixup-lisp-section-offset (fd eof sectnum)
331  (fd-lseek fd 0 #$SEEK_SET)
332  (rlet ((fhdr #+64-bit-target :<E>lf64_<E>hdr
333               #+32-bit-target :<E>lf32_<E>hdr)
334         (shdr #+64-bit-target :<E>lf64_<S>hdr
335               #+32-bit-target :<E>lf32_<S>hdr))
336    (fd-read fd fhdr (record-length #+64-bit-target :<E>lf64_<E>hdr
337                                    #+32-bit-target :<E>lf32_<E>hdr))
338    (let* ((pos (+ (pref fhdr #+64-bit-target :<E>lf64_<E>hdr.e_shoff
339                         #+32-bit-target :<E>lf32_<E>hdr.e_shoff)
340                   (* sectnum (pref fhdr #+64-bit-target :<E>lf64_<E>hdr.e_shentsize
341                                    #+32-bit-target :<E>lf32_<E>hdr.e_shentsize)))))
342      (fd-lseek fd pos #$SEEK_SET)
343      (fd-read fd shdr (record-length #+64-bit-target :<E>lf64_<S>hdr
344                                      #+32-bit-target :<E>lf32_<S>hdr))
345      ;; On 64-bit platforms, the section data precedes the image
346      ;; header; on 32-bit platforms, the image header and image
347      ;; section table precede the image data for the first (static)
348      ;; section.  With alignment, the header/section headers are
349      ;; one 4K page, and the static section size is 8K ...
350      (setf (pref shdr #+64-bit-target :<E>lf64_<S>hdr.sh_offset
351                  #+32-bit-target :<E>lf32_<S>hdr.sh_offset)
352            (+ #+32-bit-target #x1000 #+64-bit-target 0  #x2000 (logandc2 (+ eof 4095) 4095))) 
353      (setf (pref shdr #+64-bit-target :<E>lf64_<S>hdr.sh_type
354                  #+32-bit-target :<E>lf32_<S>hdr.sh_type)
355            #$SHT_PROGBITS)
356      (fd-lseek fd pos #$SEEK_SET)
357      (fd-write fd shdr (record-length #+64-bit-target :<E>lf64_<S>hdr
358                                       #+32-bit-target :<E>lf32_<S>hdr))
359      t)))
360 
361(defun write-elf-symbols-to-file (pathname)
362  (let* ((object (create-elf-object pathname))
363         (file-header (new-elf-file-header object
364                                           #+little-endian-target #$ELFDATA2LSB
365                                           #+big-endian-target #$ELFDATA2MSB
366                                           #$ET_DYN
367                                           #+x8664-target #$EM_X86_64
368                                           #+x8632-target #$EM_386
369                                           #+ppc32-target #$EM_PPC
370                                           #+ppc64-target #$EM_PPC64
371                                           #+arm-target #$EM_ARM
372                                           ))
373         (program-header (new-elf-program-header object))
374         (lisp-section (new-elf-section object))
375         (symbols-section (new-elf-section object))
376         (strings-section (new-elf-section object))
377         (shstrtab-section (new-elf-section object))
378         (section-names (make-elf-string-table))
379         (lisp-section-index (elf-section-index lisp-section))
380         (symbols (register-elf-functions lisp-section-index))
381         (lisp-section-header (elf-section-header-for-section object lisp-section))
382         (symbols-section-header (elf-section-header-for-section object symbols-section))
383         (strings-section-header (elf-section-header-for-section object strings-section))
384         (shstrtab-section-header (elf-section-header-for-section object shstrtab-section)))
385   
386    (setf (pref file-header #+64-bit-target :<E>lf64_<E>hdr.e_shstrndx
387                #+32-bit-target :<E>lf32_<E>hdr.e_shstrndx) (elf-section-index shstrtab-section))
388    (setf (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_name
389                #+32-bit-target :<E>lf32_<S>hdr.sh_name) (elf-register-string ".lisp" section-names)
390          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_type
391                #+32-bit-target :<E>lf32_<S>hdr.sh_type) #$SHT_NOBITS
392          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_flags
393                #+32-bit-target :<E>lf32_<S>hdr.sh_flags) (logior #$SHF_WRITE #$SHF_ALLOC #$SHF_EXECINSTR)
394          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_addr
395                #+32-bit-target :<E>lf32_<S>hdr.sh_addr) (ash (%fixnum-ref *readonly-area* target::area.low) target::fixnumshift)
396          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_size
397                #+32-bit-target :<E>lf32_<S>hdr.sh_size) (ash (- (%fixnum-ref *readonly-area* target::area.active) (%fixnum-ref *readonly-area* target::area.low) )target::fixnumshift)
398          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_offset
399                #+32-bit-target :<E>lf32_<S>hdr.sh_offset) 0
400          (pref lisp-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_addralign
401                #+32-bit-target :<E>lf32_<S>hdr.sh_addralign) 1)
402    (setf (pref symbols-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_name
403                #+32-bit-target :<E>lf32_<S>hdr.sh_name) (elf-register-string ".symtab" section-names)
404          (pref symbols-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_type
405                #+32-bit-target :<E>lf32_<S>hdr.sh_type) #$SHT_SYMTAB
406          (pref symbols-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_entsize
407                #+32-bit-target :<E>lf32_<S>hdr.sh_entsize) (record-length #+64-bit-target :<E>lf64_<S>ym
408                                                                           #+32-bit-target :<E>lf32_<S>ym)
409          (pref symbols-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_link
410                #+32-bit-target :<E>lf32_<S>hdr.sh_link) (elf-section-index strings-section))
411    (setf (pref strings-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_name
412                #+32-bit-target :<E>lf32_<S>hdr.sh_name) (elf-register-string ".strtab" section-names)
413          (pref strings-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_type
414                #+32-bit-target :<E>lf32_<S>hdr.sh_type) #$SHT_STRTAB
415          (pref strings-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_flags
416                #+32-bit-target :<E>lf32_<S>hdr.sh_flags) (logior #$SHF_STRINGS #$SHF_ALLOC))
417    (setf (pref shstrtab-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_name
418                #+32-bit-target :<E>lf32_<S>hdr.sh_name) (elf-register-string ".shstrtab" section-names)
419          (pref shstrtab-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_type
420                #+32-bit-target :<E>lf32_<S>hdr.sh_type) #$SHT_STRTAB
421          (pref shstrtab-section-header #+64-bit-target :<E>lf64_<S>hdr.sh_flags
422                #+32-bit-target :<E>lf32_<S>hdr.sh_flags) (logior #$SHF_STRINGS #$SHF_ALLOC))
423    (elf-make-empty-data-for-section object lisp-section (ash (- (%fixnum-ref *readonly-area* target::area.active) (%fixnum-ref *readonly-area* target::area.low) )target::fixnumshift))
424    (elf-init-section-data-from-string-table object strings-section (elf-symbol-table-strings symbols))
425    (elf-init-section-data-from-string-table object shstrtab-section section-names)
426    (elf-init-symbol-section-from-symbol-table object symbols-section symbols)
427    ;; Prepare in-memory data structures.
428    (elf-update object #$ELF_C_NULL)
429    ;; Fix up the program header.
430    (setf (pref program-header
431                #+64-bit-target :<E>lf64_<P>hdr.p_type
432                #+32-bit-target :<E>lf32_<P>hdr.p_type) #$PT_PHDR
433          (pref program-header #+64-bit-target :<E>lf64_<P>hdr.p_offset
434                #+32-bit-target :<E>lf32_<P>hdr.p_offset)
435          (pref file-header
436                #+64-bit-target :<E>lf64_<E>hdr.e_phoff
437                #+32-bit-target :<E>lf32_<E>hdr.e_phoff)
438          (pref program-header
439                #+64-bit-target :<E>lf64_<P>hdr.p_filesz
440                #+32-bit-target :<E>lf32_<P>hdr.p_filesz)
441          (#+64-bit-target #_elf64_fsize #+32-bit-target #_elf32_fsize #$ELF_T_PHDR 1 #$EV_CURRENT))
442    ;; Mark the program header as being dirty.
443    (elf-flag-phdr object #$ELF_C_SET #$ELF_F_DIRTY)
444    (let* ((eof (elf-update object #$ELF_C_WRITE))
445           (fd (elf-object-fd object)))
446      (elf-end object)
447      (fixup-lisp-section-offset fd eof lisp-section-index)
448      (fd-close fd))
449    pathname))
450
451     
452   
453   
Note: See TracBrowser for help on using the repository browser.