fix mach-o munging of 64-bit executables
This commit is contained in:
parent
9597810a99
commit
ea7c34568c
|
@ -3,12 +3,23 @@
|
||||||
(provide add-plt-segment
|
(provide add-plt-segment
|
||||||
get/set-dylib-path)
|
get/set-dylib-path)
|
||||||
|
|
||||||
|
(define exe-id
|
||||||
|
(if (equal? (path->bytes (system-library-subpath #f)) #"x86_64-macosx")
|
||||||
|
#xFeedFacf
|
||||||
|
#xFeedFace))
|
||||||
|
|
||||||
(define (read-ulong p)
|
(define (read-ulong p)
|
||||||
(integer-bytes->integer (read-bytes 4 p) #f))
|
(integer-bytes->integer (read-bytes 4 p) #f))
|
||||||
|
|
||||||
|
(define (read-xulong p)
|
||||||
|
(integer-bytes->integer (read-bytes 8 p) #f))
|
||||||
|
|
||||||
(define (write-ulong v out)
|
(define (write-ulong v out)
|
||||||
(display (integer->integer-bytes v 4 #f) out))
|
(display (integer->integer-bytes v 4 #f) out))
|
||||||
|
|
||||||
|
(define (write-xulong v out)
|
||||||
|
(display (integer->integer-bytes v 8 #f) out))
|
||||||
|
|
||||||
(define (check-same a b)
|
(define (check-same a b)
|
||||||
(unless (= a b)
|
(unless (= a b)
|
||||||
(error 'check-same "not: ~e ~e" a b)))
|
(error 'check-same "not: ~e ~e" a b)))
|
||||||
|
@ -24,11 +35,6 @@
|
||||||
|
|
||||||
(define move-link-edit? #t)
|
(define move-link-edit? #t)
|
||||||
|
|
||||||
(define exe-id
|
|
||||||
(if (equal? (path->bytes (system-library-subpath #f)) #"x86_64-macosx")
|
|
||||||
#xFeedFacf
|
|
||||||
#xFeedFace))
|
|
||||||
|
|
||||||
(define (add-plt-segment file segdata)
|
(define (add-plt-segment file segdata)
|
||||||
(let-values ([(p out) (open-input-output-file file #:exists 'update)])
|
(let-values ([(p out) (open-input-output-file file #:exists 'update)])
|
||||||
(dynamic-wind
|
(dynamic-wind
|
||||||
|
@ -45,6 +51,7 @@
|
||||||
[sym-tab-pos #f]
|
[sym-tab-pos #f]
|
||||||
[dysym-pos #f]
|
[dysym-pos #f]
|
||||||
[hints-pos #f]
|
[hints-pos #f]
|
||||||
|
[link-edit-64? #f]
|
||||||
[link-edit-pos #f]
|
[link-edit-pos #f]
|
||||||
[link-edit-addr 0]
|
[link-edit-addr 0]
|
||||||
[link-edit-offset 0]
|
[link-edit-offset 0]
|
||||||
|
@ -52,7 +59,9 @@
|
||||||
[dyld-info-pos #f]
|
[dyld-info-pos #f]
|
||||||
[dyld-info-offs #f])
|
[dyld-info-offs #f])
|
||||||
;; (printf "~a cmds, length 0x~x\n" cnt cmdssz)
|
;; (printf "~a cmds, length 0x~x\n" cnt cmdssz)
|
||||||
(read-ulong p)
|
(read-ulong p) ; flags
|
||||||
|
(when (equal? exe-id #xFeedFacf)
|
||||||
|
(read-ulong p)) ; extra reserved word for 64-bit header
|
||||||
(let loop ([cnt cnt])
|
(let loop ([cnt cnt])
|
||||||
(unless (zero? cnt)
|
(unless (zero? cnt)
|
||||||
(let ([pos (file-position p)]
|
(let ([pos (file-position p)]
|
||||||
|
@ -60,42 +69,48 @@
|
||||||
[sz (read-ulong p)])
|
[sz (read-ulong p)])
|
||||||
;; (printf "~x (~a)\n" cmd sz)
|
;; (printf "~x (~a)\n" cmd sz)
|
||||||
(case cmd
|
(case cmd
|
||||||
[(1)
|
[(1 #x19) ; #x19 is 64-bit variant
|
||||||
;; Segment
|
;; Segment
|
||||||
(let ([segname (read-bytes 16 p)]
|
(let ([64? (equal? cmd #x19)])
|
||||||
[vmaddr (read-ulong p)]
|
(let ([segname (read-bytes 16 p)]
|
||||||
[vmlen (read-ulong p)]
|
[vmaddr ((if 64? read-xulong read-ulong) p)]
|
||||||
[offset (read-ulong p)]
|
[vmlen ((if 64? read-xulong read-ulong) p)]
|
||||||
[len (read-ulong p)])
|
[offset ((if 64? read-xulong read-ulong) p)]
|
||||||
;; (printf "~s\n" segname)
|
[len ((if 64? read-xulong read-ulong) p)])
|
||||||
(when (equal? segname #"__LINKEDIT\0\0\0\0\0\0")
|
;; (printf "~s\n" segname)
|
||||||
(set! link-edit-pos pos)
|
(when (equal? segname #"__LINKEDIT\0\0\0\0\0\0")
|
||||||
(set! link-edit-addr vmaddr)
|
(set! link-edit-64? 64?)
|
||||||
(set! link-edit-offset offset)
|
(set! link-edit-pos pos)
|
||||||
(set! link-edit-len len))
|
(set! link-edit-addr vmaddr)
|
||||||
;; (printf " 0x~x 0x~x -> 0x~x 0x~x\n" offset len vmaddr vmlen)
|
(set! link-edit-offset offset)
|
||||||
(read-ulong p)
|
(set! link-edit-len len)
|
||||||
(read-ulong p)
|
(when (link-edit-len . < . 0)
|
||||||
(let ([nsects (read-ulong p)])
|
(error "bad LINKEDIT length")))
|
||||||
|
;; (printf " 0x~x 0x~x -> 0x~x 0x~x\n" offset len vmaddr vmlen)
|
||||||
(read-ulong p)
|
(read-ulong p)
|
||||||
(let loop ([nsects nsects])
|
(read-ulong p)
|
||||||
(unless (zero? nsects)
|
(let ([nsects (read-ulong p)])
|
||||||
(let ([sect (read-bytes 16 p)]
|
(read-ulong p)
|
||||||
[seg (read-bytes 16 p)]
|
(let loop ([nsects nsects])
|
||||||
[vmaddr (read-ulong p)]
|
(unless (zero? nsects)
|
||||||
[vmsz (read-ulong p)]
|
(let ([sect (read-bytes 16 p)]
|
||||||
[offset (read-ulong p)]
|
[seg (read-bytes 16 p)]
|
||||||
[align (read-ulong p)]
|
[vmaddr ((if 64? read-xulong read-ulong) p)]
|
||||||
[reloff (read-ulong p)]
|
[vmsz ((if 64? read-xulong read-ulong) p)]
|
||||||
[nreloc (read-ulong p)]
|
[offset (read-ulong p)]
|
||||||
[flags (read-ulong p)])
|
[align (read-ulong p)]
|
||||||
(when ((+ offset vmsz) . > . (+ cmdssz 28))
|
[reloff (read-ulong p)]
|
||||||
(when (offset . < . min-used)
|
[nreloc (read-ulong p)]
|
||||||
;; (printf " new min!\n")
|
[flags (read-ulong p)])
|
||||||
(set! min-used offset)))
|
(when ((+ offset vmsz) . > . (+ cmdssz (if (equal? exe-id #xFeedFacf) 32 28)))
|
||||||
;; (printf " ~s,~s 0x~x 0x~x\n" seg sect offset vmsz)
|
(when (offset . < . min-used)
|
||||||
(read-ulong p) (read-ulong p))
|
;; (printf " new min!\n")
|
||||||
(loop (sub1 nsects))))))]
|
(set! min-used offset)))
|
||||||
|
;; (printf " ~s,~s 0x~x 0x~x\n" seg sect offset vmsz)
|
||||||
|
(read-ulong p)
|
||||||
|
(read-ulong p)
|
||||||
|
(when 64? (read-ulong p)))
|
||||||
|
(loop (sub1 nsects)))))))]
|
||||||
[(2)
|
[(2)
|
||||||
;; Symbol table
|
;; Symbol table
|
||||||
(set! sym-tab-pos pos)]
|
(set! sym-tab-pos pos)]
|
||||||
|
@ -124,32 +139,36 @@
|
||||||
(file-position p (+ pos sz))
|
(file-position p (+ pos sz))
|
||||||
(loop (sub1 cnt)))))
|
(loop (sub1 cnt)))))
|
||||||
;; (printf "Start offset: 0x~x\n" min-used)
|
;; (printf "Start offset: 0x~x\n" min-used)
|
||||||
(let ([end-cmd (+ cmdssz 28)]
|
(let ([end-cmd (+ cmdssz (if (equal? exe-id #xFeedFacf) 32 28))]
|
||||||
[new-cmd-sz 56]
|
[new-cmd-sz (if link-edit-64? 72 56)]
|
||||||
[outlen (round-up-page (bytes-length segdata))]
|
[outlen (round-up-page (bytes-length segdata))]
|
||||||
[out-offset (if move-link-edit?
|
[out-offset (if move-link-edit?
|
||||||
link-edit-offset
|
link-edit-offset
|
||||||
(+ link-edit-offset (round-up-page link-edit-len)))]
|
(+ link-edit-offset (round-up-page link-edit-len)))]
|
||||||
[out-addr (+ link-edit-addr (round-up-page link-edit-len))])
|
[out-addr (+ link-edit-addr (round-up-page link-edit-len))])
|
||||||
(unless ((+ end-cmd new-cmd-sz) . < . min-used)
|
(unless ((+ end-cmd new-cmd-sz) . < . min-used)
|
||||||
(error 'check-header "no room for a new section load command"))
|
(error 'check-header
|
||||||
;; Shift commands after link-edit segment:
|
"no room for a new section load command (current end is ~a; min used is ~a)"
|
||||||
|
end-cmd min-used))
|
||||||
|
;; Shift commands starting with link-edit command:
|
||||||
|
(unless link-edit-pos (error "LINKEDIT not found"))
|
||||||
(file-position p link-edit-pos)
|
(file-position p link-edit-pos)
|
||||||
(let ([s (read-bytes (- end-cmd link-edit-pos) p)])
|
(let ([s (read-bytes (- end-cmd link-edit-pos) p)])
|
||||||
(file-position out (+ link-edit-pos 56))
|
(file-position out (+ link-edit-pos new-cmd-sz))
|
||||||
(display s out))
|
(display s out))
|
||||||
(file-position out 16)
|
(file-position out 16)
|
||||||
;; The segment:
|
;; Increment the number of load commands:
|
||||||
(write-ulong (+ cnt 1) out)
|
(write-ulong (+ cnt 1) out)
|
||||||
(write-ulong (+ cmdssz new-cmd-sz) out)
|
(write-ulong (+ cmdssz new-cmd-sz) out)
|
||||||
|
;; Write the new command:
|
||||||
(file-position out link-edit-pos)
|
(file-position out link-edit-pos)
|
||||||
(write-ulong 1 out) ; LC_SEGMENT
|
(write-ulong (if link-edit-64? #x19 1) out) ; LC_SEGMENT[_64]
|
||||||
(write-ulong new-cmd-sz out)
|
(write-ulong new-cmd-sz out)
|
||||||
(display #"__PLTSCHEME\0\0\0\0\0" out)
|
(display #"__PLTSCHEME\0\0\0\0\0" out)
|
||||||
(write-ulong out-addr out)
|
((if link-edit-64? write-xulong write-ulong) out-addr out)
|
||||||
(write-ulong outlen out)
|
((if link-edit-64? write-xulong write-ulong) outlen out)
|
||||||
(write-ulong out-offset out)
|
((if link-edit-64? write-xulong write-ulong) out-offset out)
|
||||||
(write-ulong outlen out)
|
((if link-edit-64? write-xulong write-ulong) outlen out)
|
||||||
(write-ulong 0 out)
|
(write-ulong 0 out)
|
||||||
(write-ulong 0 out)
|
(write-ulong 0 out)
|
||||||
(write-ulong 0 out)
|
(write-ulong 0 out)
|
||||||
|
@ -158,22 +177,20 @@
|
||||||
(unless sym-tab-pos
|
(unless sym-tab-pos
|
||||||
(error 'mach-o "symtab position not found"))
|
(error 'mach-o "symtab position not found"))
|
||||||
(when (sym-tab-pos . > . link-edit-pos)
|
(when (sym-tab-pos . > . link-edit-pos)
|
||||||
(set! sym-tab-pos (+ sym-tab-pos 56)))
|
(set! sym-tab-pos (+ sym-tab-pos new-cmd-sz)))
|
||||||
(unless dysym-pos
|
(unless dysym-pos
|
||||||
(error 'mach-o "dysym position not found"))
|
(error 'mach-o "dysym position not found"))
|
||||||
(when (dysym-pos . > . link-edit-pos)
|
(when (dysym-pos . > . link-edit-pos)
|
||||||
(set! dysym-pos (+ dysym-pos 56)))
|
(set! dysym-pos (+ dysym-pos new-cmd-sz)))
|
||||||
(when hints-pos
|
(when hints-pos
|
||||||
(when (hints-pos . > . link-edit-pos)
|
(when (hints-pos . > . link-edit-pos)
|
||||||
(set! hints-pos (+ hints-pos 56))))
|
(set! hints-pos (+ hints-pos new-cmd-sz))))
|
||||||
(unless link-edit-pos
|
(set! link-edit-pos (+ link-edit-pos new-cmd-sz))
|
||||||
(error 'mach-o "link-edit position not found"))
|
|
||||||
(set! link-edit-pos (+ link-edit-pos 56))
|
|
||||||
(when move-link-edit?
|
(when move-link-edit?
|
||||||
;; Update link-edit segment entry:
|
;; Update link-edit segment entry:
|
||||||
(file-position out (+ link-edit-pos 32))
|
(file-position out (+ link-edit-pos (if link-edit-64? 40 32)))
|
||||||
;; (printf "Update to ~a\n" (+ out-offset outlen))
|
;; (printf "Update to ~a\n" (+ out-offset outlen))
|
||||||
(write-ulong (+ out-offset outlen) out)
|
((if link-edit-64? write-xulong write-ulong) (+ out-offset outlen) out)
|
||||||
;; Read link-edit segment:
|
;; Read link-edit segment:
|
||||||
(file-position p link-edit-offset)
|
(file-position p link-edit-offset)
|
||||||
(let ([link-edit (read-bytes link-edit-len p)])
|
(let ([link-edit (read-bytes link-edit-len p)])
|
||||||
|
@ -207,7 +224,7 @@
|
||||||
(when dyld-info-pos
|
(when dyld-info-pos
|
||||||
(let ([update (lambda (n)
|
(let ([update (lambda (n)
|
||||||
(unless (< (vector-ref dyld-info-offs n) out-offset)
|
(unless (< (vector-ref dyld-info-offs n) out-offset)
|
||||||
(file-position out (+ dyld-info-pos 56 16 (* n 8)))
|
(file-position out (+ dyld-info-pos new-cmd-sz 16 (* n 8)))
|
||||||
(write-ulong (+ (vector-ref dyld-info-offs n) outlen) out)))])
|
(write-ulong (+ (vector-ref dyld-info-offs n) outlen) out)))])
|
||||||
(update 0)
|
(update 0)
|
||||||
(update 1)
|
(update 1)
|
||||||
|
@ -247,6 +264,8 @@
|
||||||
(let* ([cnt (read-ulong p)]
|
(let* ([cnt (read-ulong p)]
|
||||||
[cmdssz (read-ulong p)])
|
[cmdssz (read-ulong p)])
|
||||||
(read-ulong p)
|
(read-ulong p)
|
||||||
|
(when (equal? exe-id #xFeedFacf)
|
||||||
|
(read-ulong p))
|
||||||
(let loop ([cnt cnt][base 0][delta 0][result #f])
|
(let loop ([cnt cnt][base 0][delta 0][result #f])
|
||||||
(if (zero? cnt)
|
(if (zero? cnt)
|
||||||
result
|
result
|
||||||
|
|
Loading…
Reference in New Issue
Block a user