Mac: Kernel rejects the execution of compiled binaries on arm64 #6

Closed
opened 2025-08-07 13:54:37 +00:00 by ed · 11 comments
Owner

Everything works on Intel macs, but the arm64 binaries don't run on Apple Silicon, exiting with signal: killed (9).
The arm64 assembly instructions analyzed with objdump are equal between as/ld and q produced binaries.
The most likely cause is incorrect Mach-O headers for this platform.

Everything works on Intel macs, but the arm64 binaries don't run on Apple Silicon, exiting with `signal: killed (9)`. The arm64 assembly instructions analyzed with `objdump` are equal between `as/ld` and `q` produced binaries. The most likely cause is incorrect Mach-O headers for this platform.
Author
Owner

Relevant changes that had no success so far:

Relevant changes that had no success so far: - https://git.urbach.dev/cli/q/commit/6e7b60f7bf1bb8ffd08b8ee476cad7946f02c301 - https://git.urbach.dev/cli/q/commit/9a3e14bacb75982535d7c5d44ebbc2b0a4cb4f00 - https://git.urbach.dev/cli/q/commit/d657ef04df6b9a99866cd1905e1d1576e0f075a3
ed self-assigned this 2025-08-07 17:30:14 +00:00
Author
Owner

Idemailly on GitHub has posted more testing insights:

https://github.com/ldemailly/q/issues/1

Idemailly on GitHub has posted more testing insights: https://github.com/ldemailly/q/issues/1
Author
Owner

Recent changes:

Now this comes up as an error:

dyld_info ./hello

chained_fixups: seg_count does not match number of segment

Relevant file:

SegCount uint32

Recent changes: - [Fixed the build version](https://git.urbach.dev/cli/q/commit/5e41011a5708543ec4831ea885cfbcfdb8e9e576) - [Added an empty UUID](https://git.urbach.dev/cli/q/commit/1557ae22a647786b3d30254e3e01182d9efd5040) - [Added more fixup chain details](https://git.urbach.dev/cli/q/commit/fb65b1bdcc4a07fe87a598ffad1bc6e466470038) Now this comes up as an error: ``` dyld_info ./hello chained_fixups: seg_count does not match number of segment ``` Relevant file: https://git.urbach.dev/cli/q/src/commit/1557ae22a647786b3d30254e3e01182d9efd5040/src/macho/ChainedStartsInImage.go#L5
Author
Owner
Documentation on fixups: https://wwdcnotes.com/documentation/wwdcnotes/wwdc22-110362-link-fast-improve-build-and-launch-times/#Fixups
Author
Owner

I suppose the number of segments there must be equal to the total number of segments in the binary.
cli/q@4370ba885d does this.

Now we're getting:

dyld_info ./hello
misaligned code-signature
I suppose the number of segments there must be equal to the total number of segments in the binary. https://git.urbach.dev/cli/q/commit/4370ba885d3c85ee372e1db385928ea233e1024e does this. Now we're getting: ```shell dyld_info ./hello misaligned code-signature ```
Author
Owner
Update: [Fixed dyld_info complaints](https://git.urbach.dev/cli/q/commit/7ce5d3401908fab456420caf40032bee04433024)
Author
Owner

Little update: Changed the code signature SHA256 hashing. Previously got 83... as a hash, now the hello world hash is e7... different. I removed the padding for the last memory page because I saw that Go doesn't do it in their source.

Hash can be checked with codesign -dv --verbose=4 on an executable.

Little update: Changed the code signature SHA256 hashing. Previously got 83... as a hash, now the hello world hash is e7... different. I removed the padding for the last memory page because I saw that Go doesn't do it in their source. Hash can be checked with `codesign -dv --verbose=4` on an executable.
Author
Owner

More information:

New in macOS 11 on Macs with Apple silicon, and starting in macOS Big Sur 11 beta 6, the operating system enforces that any executable must be signed before it’s allowed to run. There isn’t a specific identity requirement for this signature: a simple ad-hoc signature is sufficient. This new behavior doesn’t change the long-established policy that our users and developers can run arbitrary code on their Macs, and is designed to simplify the execution policies on Macs with Apple silicon and enable the system to better detect code modifications. This new policy doesn’t apply to translated x86 binaries running under Rosetta 2, nor does it apply to macOS 11 running on Intel-based platforms.

To reduce the impact on existing development workflows, starting with Xcode 12 beta 4, the toolchain will now automatically sign your executables whenever you build from Xcode, or use command-line utilities such as clang(1) or ld(1). Since this signing mechanism generates signatures directly at link time, and doesn’t cover any resource other than the executable, it is expected to be faster than a traditional codesign(1) invocation. If you use a custom workflow involving tools that modify a binary after linking (e.g. strip or install_name_tool) you might need to manually call codesign(1) as an additional build phase to properly ad-hoc sign your binary. These new signatures are not bound to the specific machine that was used to build the executable, they can be verified on any other system and will be sufficient to comply with the new default code signing requirement on Macs with Apple silicon. However, given that these signatures do not bear any valid identity, binaries signed this way cannot pass through Gatekeeper.

More information: - https://github.com/golang/go/issues/42684 - https://github.com/ziglang/zig/issues/7103 - https://developer.apple.com/documentation/macos-release-notes/macos-big-sur-11_0_1-universal-apps-release-notes#Code-Signing > New in macOS 11 on Macs with Apple silicon, and starting in macOS Big Sur 11 beta 6, the operating system enforces that any executable must be signed before it’s allowed to run. There isn’t a specific identity requirement for this signature: a simple ad-hoc signature is sufficient. This new behavior doesn’t change the long-established policy that our users and developers can run arbitrary code on their Macs, and is designed to simplify the execution policies on Macs with Apple silicon and enable the system to better detect code modifications. This new policy doesn’t apply to translated x86 binaries running under Rosetta 2, nor does it apply to macOS 11 running on Intel-based platforms. > > To reduce the impact on existing development workflows, starting with Xcode 12 beta 4, the toolchain will now automatically sign your executables whenever you build from Xcode, or use command-line utilities such as clang(1) or ld(1). Since this signing mechanism generates signatures directly at link time, and doesn’t cover any resource other than the executable, it is expected to be faster than a traditional codesign(1) invocation. If you use a custom workflow involving tools that modify a binary after linking (e.g. strip or install_name_tool) you might need to manually call codesign(1) as an additional build phase to properly ad-hoc sign your binary. These new signatures are not bound to the specific machine that was used to build the executable, they can be verified on any other system and will be sufficient to comply with the new default code signing requirement on Macs with Apple silicon. However, given that these signatures do not bear any valid identity, binaries signed this way cannot pass through Gatekeeper.
Author
Owner

Latest commit implements a strict flag that KILLs the process on invalid signatures even on x86-64 macs.
I needed to enable this strictness because arm macs have it by default, but it's disabled on x86-64.
So I needed it to be reproducible on my machine.
Did it work?

Tried old signature algorithm: Sigkill (9)
Tried new signature algorithm: Runs normally.

I've also completely reimplemented the signature algorithm and at least x86-64 is happy with them.
My only worry is that I might have to set the page size to a static 4k because some docs mention that.
Right now the page size for the signature is dynamic, so it will be 16k on an arm Mac - but that might be wrong behavior.
Go uses 4k. I'm willing to test 16k, and if that fails, go to a static 4k.

Latest commit implements a strict flag that KILLs the process on invalid signatures even on x86-64 macs. I needed to enable this strictness because arm macs have it by default, but it's disabled on x86-64. So I needed it to be reproducible on my machine. Did it work? Tried old signature algorithm: Sigkill (9) Tried new signature algorithm: Runs normally. I've also completely reimplemented the signature algorithm and at least x86-64 is happy with them. My only worry is that I might have to set the page size to a static 4k because some docs mention that. Right now the page size for the signature is dynamic, so it will be 16k on an arm Mac - but that might be wrong behavior. Go uses 4k. I'm willing to test 16k, and if that fails, go to a static 4k.
Author
Owner

Fixed after cli/q@7155c7bfd1.

Thank you so much to all these wonderful people who helped debug this problem:

Fixed after https://git.urbach.dev/cli/q/commit/7155c7bfd1873373943e4a16c8b1704f37f08336. Thank you so much to all these wonderful people who helped debug this problem: - [James Mills](https://prologic.shortcircuit.net.au/) - [Laurent Demailly](https://laurentsv.com/) - [Max van IJsselmuiden](https://www.maxvanijsselmuiden.nl/)
ed closed this issue 2025-08-11 07:59:18 +00:00

@ed wrote in #6 (comment):

Fixed after 7155c7bfd1.

Thank you so much to all these wonderful people who helped debug this problem:

* [James Mills](https://prologic.shortcircuit.net.au/)

* [Laurent Demailly](https://laurentsv.com/)

* [Max van IJsselmuiden](https://www.maxvanijsselmuiden.nl/)

Glad to help! The addition of two characters fixed it, typical 💯

@ed wrote in https://git.urbach.dev/cli/q/issues/6#issuecomment-95: > Fixed after [`7155c7bfd1`](https://git.urbach.dev/cli/q/commit/7155c7bfd1873373943e4a16c8b1704f37f08336). > > Thank you so much to all these wonderful people who helped debug this problem: > > * [James Mills](https://prologic.shortcircuit.net.au/) > > * [Laurent Demailly](https://laurentsv.com/) > > * [Max van IJsselmuiden](https://www.maxvanijsselmuiden.nl/) Glad to help! The addition of two characters fixed it, typical 💯
ed added spent time 2025-08-13 19:18:00 +00:00
5 days
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Total time spent: 5 days
ed
5 days
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cli/q#6
No description provided.