[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: ABI mismatch on boot on arm32 system
From: |
Christoph Buck |
Subject: |
Re: ABI mismatch on boot on arm32 system |
Date: |
Tue, 29 Oct 2024 18:11:27 +0100 |
User-agent: |
mu4e 1.12.0; emacs 30.0.50 |
Hi!
In case anybody is reading along here. I digged deeper and found
something rather interessting :P
>From my understanding by reading through the records.scm from guix (and
please note that im a total scheme newbee), the abi check works by
calculation a string-hash over the record field names and storing the
hash as hidden field in the record. During runtime this string-hash is
computed again and compared to the compiled hash. If they don't
match, the abi is broken because a field was added or removed.
The hash is calculated in the `compute-abi-cookie` procedure in the
records.scm.
I extended the procedure with the following debug outputs
--8<---------------cut here---------------start------------->8---
(define (compute-abi-cookie field-specs)
;; Compute an "ABI cookie" for the given FIELD-SPECS. We use
;; 'string-hash' because that's a better hash function that 'hash' on a
;; list of symbols.
(let ((hash
(syntax-case field-specs ()
(((field get properties ...) ...)
(string-hash (object->string
(syntax->datum #'((field properties ...) ...)))
;; (bla)
(cond-expand
(guile-3 (target-most-positive-fixnum))
(else most-positive-fixnum))
))))
(fd (syntax-case field-specs ()
(((field get properties ...) ...)
(object->string
(syntax->datum #'((field properties ...) ...)))))))
(format #t "Compute-abi-cookie: ~a~%" hash)
(format #t "field-specs: ~a~%" field-specs)
(format #t "fd: ~a~%" fd)
(format #t "hashsize ~a~%: " (cond-expand
(guile-3 (target-most-positive-fixnum))
(else most-positive-fixnum)))
hash))
--8<---------------cut here---------------end--------------->8---
Now, if i compile a simple test record
--8<---------------cut here---------------start------------->8---
(define-record-type* <test-system> test-system
make-test-system
test-system?
(device test-system-device)
(mount-point test-system-mount-point))
(define test-abi (test-system
(device "my-root")
(mount-point "/")))
--8<---------------cut here---------------end--------------->8---
on x64 using guile cross-compiling (in a `guix shell --container guix
guile` environment) using the call
--8<---------------cut here---------------start------------->8---
(with-target "arm-linux-gnueabihf" (lambda () (compile-file "test-abi.scm")))
--8<---------------cut here---------------end--------------->8---
the following outputs are generated:
--8<---------------cut here---------------start------------->8---
Compute-abi-cookie: 212719825
field-specs: ((#<syntax device> #<syntax test-system-device>) (#<syntax
mount-point> #<syntax test-system-mount-point>))
fd: ((device) (mount-point))
hashsize 536870911
--8<---------------cut here---------------end--------------->8---
The abi cookie is computed by calculating the string hash over
"((device) (mount-point))" while limiting the size of the hash by
536870911. One can manually check this by calling
--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (string-hash "((device) (mount-point))" 536870911)
$1 = 212719825
--8<---------------cut here---------------end--------------->8---
in the repl.
Now, if i do the same in a qemu arm32 environment (using `guix shell
--container guix guile --system=armhf-linux`), a different hash is
printed, even though the hash is calculated over the same string, see:
--8<---------------cut here---------------start------------->8---
Compute-abi-cookie: 2434018
field-specs: ((#<syntax device> #<syntax test-system-device>) (#<syntax
mount-point> #<syntax test-system-mount-point>))
fd: ((device) (mount-point))
hashsize 536870911
--8<---------------cut here---------------end--------------->8---
You can verify this in the repl as well:
--8<---------------cut here---------------start------------->8---
scheme@(guile-user)> (string-hash "((device) (mount-point))" 536870911)
$1 = 2434018
--8<---------------cut here---------------end--------------->8---
My first intuition after seeing the source of `compute-abi-cookie` was,
that maybe the `target-most-positive-fixnum` results in an wrong value
when called in a cross-compile context. But as you can see, this is not
the case. Instead, the `string-hash` calculates a different hash
even thought the input values are the same.
Now, i am not even sure if one can expect that hash functions running on
different architectures result in the same hash if the input is the
same. If not, then the implementation in guix record.scm would be
buggy. If one expects that the hash of `string-hash` for the same input
must be the same regardless of the architecture, then this would hint to
a bug in the `string-hash` function in guile for arm32.
Any inputs and thoughts regarding this issue would be appreciated.
Greetings
Christoph
--
Best regards
Christoph