mes/module/mes/elf.mes
Jan Nieuwenhuizen 1263d6e278 mescc: Write object files in hex2 or hex3 format.
* stage0/elf32.hex2: New file.
* module/mes/hex2.mes: New file.
* module/mes/hex2.scm: New file.
* module/language/c99/compiler.mes: Eradicate object lamdas.
  (current-eval, dec-xhex, function:-object->text, object->elf,
  object->objects, merge-objects, alist-add): Remove.
* module/mes/elf.mes (object->elf): New function, move from compiler.mes.
* module/mes/elf.scm: Export it.
* guile/mescc.scm (parse-opts): Add -g.
  (main): Use it.
* scripts/mescc.mes: Likewise.
* scripts/mescc-guile.make (MESCC.scm, MESLD.scm): Add -g flag.
* scripts/mescc-mes.make (MESCC.mes, MESLD.mes): Likewise.
* scaffold/m.c: Add proper includes.
* scaffold/argv.c: New file.
* scaffold/hello.c: Simplify.
* scaffold/micro-mes.c: Add proper includes.
* scaffold/t.c: Add proper includes.
2017-06-11 13:11:40 +02:00

310 lines
9.1 KiB
Scheme

<;;; -*-scheme-*-
;;; Mes --- Maxwell Equations of Software
;;; Copyright © 2016,2017 Jan Nieuwenhuizen <janneke@gnu.org>
;;;
;;; This file is part of Mes.
;;;
;;; Mes is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; Mes is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with Mes. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; elf.mes - produce a i386 elf executable.
;;; Code:
(cond-expand
(guile)
(mes
(mes-use-module (srfi srfi-1))
(mes-use-module (mes elf-util))))
(define elf32-addr int->bv32)
(define elf32-half int->bv16)
(define elf32-off int->bv32)
(define elf32-word int->bv32)
(define (make-elf functions globals init)
(define vaddress #x08048000)
(define ei-magic `(#x7f ,@(string->list "ELF")))
(define ei-class '(#x01)) ;; 32 bit
(define ei-data '(#x01)) ;; little endian
(define ei-version '(#x01))
(define ei-osabi '(#x00))
(define ei-pad '(#x0 #x0 #x0 #x0 #x0 #x0 #x0 #x0))
(define e-ident
(append
ei-magic
ei-class
ei-data
ei-version
ei-osabi
ei-pad))
(define ET-EXEC 2)
(define EM-386 3)
(define EV-CURRENT 1)
(define p-filesz (elf32-word 0))
(define p-memsz (elf32-word 0))
(define PF-X 1)
(define PF-W 2)
(define PF-R 4)
(define p-flags (elf32-word (logior PF-X PF-W PF-R)))
(define p-align (elf32-word 1))
(define (program-header type offset text)
(append
(elf32-word type)
(elf32-off offset)
(elf32-addr (+ vaddress offset))
(elf32-addr (+ vaddress offset))
(elf32-word (length text))
(elf32-word (length text))
p-flags
p-align
))
(define (section-header name type flags offset text sh-link sh-info sh-entsize)
(append
(elf32-word name)
(elf32-word type)
;;;;(elf32-word 3) ;; write/alloc must for data hmm
(elf32-word flags)
(elf32-addr (+ vaddress offset))
(elf32-off offset)
(elf32-word (length text))
(elf32-word sh-link)
(elf32-word sh-info)
(elf32-word 1)
(elf32-word sh-entsize)))
(define e-type (elf32-half ET-EXEC))
(define e-machine (elf32-half EM-386))
(define e-version (elf32-word EV-CURRENT))
(define e-entry (elf32-addr 0))
;;(define e-entry (elf32-addr (+ vaddress text-offset)))
;;(define e-phoff (elf32-off 0))
(define e-shoff (elf32-off 0))
(define e-flags (elf32-word 0))
;;(define e-ehsize (elf32-half 0))
(define e-phentsize (elf32-half (length (program-header 0 0 '()))))
(define e-phnum (elf32-half 2)) ; text+data
(define e-shentsize (elf32-half (length (section-header 0 0 0 0 '() 0 0 0))))
(define e-shnum (elf32-half 7)) ; sections: 7
(define e-shstrndx (elf32-half 4))
(define (elf-header size entry sections)
(append
e-ident
e-type
e-machine
e-version
(elf32-addr (+ vaddress entry)) ;; e-entry
(elf32-off size) ;; e-phoff
(elf32-off sections) ;; e-shoff
e-flags
(elf32-half size) ;; e-ehsize
e-phentsize
e-phnum
e-shentsize
e-shnum
e-shstrndx
))
(define elf-header-size
(length (elf-header 0 0 0)))
(define program-header-size
(* 2 (length (program-header 0 0 '()))))
(define text-offset
(+ elf-header-size program-header-size))
(define PT-LOAD 1)
(define (program-headers text data)
(append
(program-header PT-LOAD text-offset text)
(program-header PT-LOAD data-offset data)))
(define comment
(string->list
(string-append
"MES"
;;"Mes -- Maxwell Equations of Software\n"
;;"https://gitlab.com/janneke/mes"
)
;; #x05 #x00 #x00 #x00 #x00 #x00 #x00 #x00 #x02 #x00 #x00 #x00
;; #\i #\3 #\8 #\6 #x00 #x00 #x00 #x00
))
(define shstr
`(
#x00 ; 0
,@(string->list ".text") #x00 ; 1
,@(string->list ".data") #x00 ; 7
,@(string->list ".comment") #x00 ; 13
,@(string->list ".shstrtab") #x00 ; 22
,@(string->list ".symtab") #x00 ; 32
,@(string->list ".strtab") #x00 ; 40
))
(define (str functions)
(cons
0
(append-map
(lambda (s) (append (string->list s) (list 0)))
(map car functions))))
(define text-length
(length (functions->text functions globals 0 0 0)))
(define data-offset
(+ text-offset text-length))
(define stt-func 2)
(define stt-global-func 18)
(define (symbol-table-entry st-name st-offset st-length st-info st-other st-shndx)
(append
(elf32-word st-name)
(elf32-addr st-offset)
(elf32-word st-length)
(list st-info)
(list st-other)
(elf32-half st-shndx)))
(define (sym functions globals)
(define (symbol->table-entry o)
(let* ((name (car o))
(offset (function-offset name functions))
(len (if (not (cdr o)) 0 (length (text->list (cddr o)))))
(str (append-map (lambda (x) (cons 0 (string->list x))) (cdr (member name (reverse (map car functions))))))
(i (1+ (length str))))
(symbol-table-entry i (+ vaddress text-offset offset) len stt-func 0 1)))
(append
(symbol-table-entry 0 0 0 0 0 0)
(append-map symbol->table-entry functions)))
(define data-address (+ data-offset vaddress))
(define text-address (+ text-offset vaddress))
(define data-length
(length (globals->data functions globals 0 0)))
(define comment-length
(length comment))
(define comment-offset
(+ data-offset data-length))
(define shstr-offset
(+ comment-offset comment-length))
(define shstr-length
(length shstr))
(define sym-offset
(+ shstr-offset shstr-length))
(define SHT-PROGBITS 1)
(define SHT-SYMTAB 2)
(define SHT-STRTAB 3)
(define SHT-NOTE 7)
(define SHF-WRITE 1)
(define SHF-ALLOC 2)
(define SHF-EXEC 4)
(define SHF-STRINGS #x20)
(let* ((text (functions->text functions globals text-address 0 data-address))
(raw-data (globals->data functions globals text-address data-address))
;; (data (let loop ((data raw-data) (init init))
;; (if (null? init) data
;; (loop ((car init) functions globals text-address 0 data-address data) (cdr init)))))
(data raw-data)
(entry (+ text-offset (function-offset "_start" functions)))
(sym (sym functions globals))
(str (str functions)))
(define (section-headers)
(append
(section-header 0 0 0 0 '() 0 0 0)
(section-header 1 SHT-PROGBITS (logior SHF-ALLOC SHF-EXEC) text-offset text 0 0 0)
(section-header 7 SHT-PROGBITS (logior SHF-ALLOC SHF-WRITE) data-offset data 0 0 0)
(section-header 13 SHT-PROGBITS 0 comment-offset comment 0 0 0)
(section-header 22 SHT-STRTAB 0 shstr-offset shstr 0 0 0)
(section-header 32 SHT-SYMTAB 0 sym-offset sym 6 0 (length (symbol-table-entry 0 0 0 0 9 0)))
(section-header 40 SHT-STRTAB 0 str-offset str 0 0 0)))
(define sym-length
(length sym))
(define str-offset
(+ sym-offset sym-length))
(define str-length
(length str))
(define section-headers-offset
(+ str-offset str-length))
(if (< (length text) 2000)
(format (current-error-port) "ELF text=~a\n" (map dec->hex text)))
(if (< (length raw-data) 200)
(format (current-error-port) "ELF raw-data=~a\n" (map dec->hex raw-data)))
(if (< (length data) 200)
(format (current-error-port) "ELF data=~a\n" (map dec->hex data)))
(format (current-error-port) "text-offset=~a\n" text-offset)
(format (current-error-port) "data-offset=~a\n" data-offset)
(format (current-error-port) "_start=~a\n" (number->string entry 16))
(append
(elf-header elf-header-size entry section-headers-offset)
(program-headers text data)
text
data
comment
shstr
sym
str
(section-headers))))
(define (logf port string . rest)
(apply format (cons* port string rest))
(force-output port)
#t)
(define (stderr string . rest)
(apply logf (cons* (current-error-port) string rest)))
(define (write-any x)
(write-char
(cond ((char? x) x)
((and (number? x) (< (+ x 256) 0))
(format (current-error-port) "***BROKEN*** x=~a ==> ~a\n" x (dec->hex x)) (integer->char #xaa))
((number? x) (integer->char (if (>= x 0) x (+ x 256))))
((procedure? x)
(stderr "write-any: proc: ~a\n" x)
(stderr " ==> ~a\n" (map dec->hex (x '() '() 0 0)))
(error "procedure: write-any:" x))
(else (stderr "write-any: ~a\n" x) (error "write-any: else: " x)))))
(define (object->elf object)
(display "dumping elf\n" (current-error-port))
(for-each
write-any
(make-elf (filter cdr (assoc-ref object 'functions)) (assoc-ref object 'globals) (assoc-ref object 'inits))))