ARM64 fixes, Meson build system, and Maco-O support #22
No reviewers
Labels
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: ariadne/libucontext#22
Loading…
Reference in New Issue
There is no content yet.
Delete Branch "qemu-support"
Deleting a branch is permanent. Although the deleted branch may exist for a short time before cleaning up, in most cases it CANNOT be undone. Continue?
These changes are to get libucontext working with Apple Silicon as well as building as a subproject of QEMU. Additionally, there's a few bug fixes.
FETCH_LINKPTR
was defined to use both register and memory output. But for x86, arm, and arm64, the MOV instruction only accepts register outputs. This causes an assembler error if the compiler decides to use a memory output. To be safe, I changed all the archs to only use register outputs.FETCH_LINKPTR
had the wrong operands. Other than x86_64 (correct), I did not check any other archs._GNU_SOURCE
may be defined by the build system (i.e. when building with QEMU) so I added a guard to itmakecontext
should also be exported only whenEXPORT_UNPREFIXED
is defined.global func ; .align 2 ; func:
). This may be a bug but it means we cannot use preprocessor macros to output multiple directives as macros always expand to a single line regardless. Unfortunately this makes the arm64 functions out of place, so maybe there's a better solution (like a manual preprocess step that expands the newlines).bits.h
uses size_t which requires stddef.hbits.h
headers so-isystem
is not required. This allows Meson builds to work.-DLIBUCONTEXT_ASSEMBLY
.VERSION
file to keep track of the version number which is used by both Make and Meson_Static_assert
to verify that the offset matches what's in def.h. I would recommend this for the other archs as well.makecontext
says that each argument isint
type. In aarch64, this means 32 bit ints in 64 bit registers as well as 32 bit ints in the stack.I don't think we actually declare
libucontext_sigset_t
anywhere?@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
What happens if we pass a pointer as a stack argument to makecontext then?
I think it would be better to just change the non-Meson build system to do -D_GNU_SOURCE on the commandline.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
Wouldn’t be allowed according to the man pages https://man7.org/linux/man-pages/man3/makecontext.3.html
I added it above but it’s not used and can easily be substituted. I just copy pasted the layout from some C library (forgot which).
~Sure but there’s still a problem where if it’s used as a sub project and it inherits cflags from the parent (i.e. qemu) then it gets defined but if built standalone with meason it needs to be defined.~
EDIT: nvm I just realized there’s no problem with having -D_GNU_SOURCE twice.
Musl defines
sigset_t
as:That works out to 16 bytes on aarch64.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
The NetBSD and glibc implementations also do not narrow the arguments like this code is doing. The macOS implementation also does not appear to do so. What problem are you trying to solve here?
I see, well it doesn’t seem to actually matter since it’s not used and is laid out after the regs.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
Well you need to choose some size or the stack layout won’t work. The old code doesn’t work because it assumed every register is 4 bytes so I bumped the register arguments to 8 bytes and kept the stack arguments at 4 bytes. You can make everything 8 bytes as I originally tried but then I read the man pages and realized it expects ‘int’ which is 4 bytes for all arguments.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
To clarify I didn’t “narrow” any arguments. I widened it for the register arguments. unsigned long is 4 bytes on arm and arm64.
Hmm, but mcontext comes after the sigset. __pad was intended to include the sigset here.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
Yeah, I was misreading what the patch did. This is fine.
@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
Wait what?
On my
aarch64
machine,unsigned long
is definitely 8 bytes:@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
Apple says
unsigned long
is 8 bytes on Darwin ARM64 too. https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms@ -48,3 +57,3 @@
for (; i < argc; i++)
*sp++ = va_arg (va, unsigned long);
*sp++ = va_arg (va, int);
It seems to me that having it any other way would break alignment assumptions made by aarch64 CPUs? So I'm back to being confused about the two ARM-specific patches.
This was an interesting bug, it turns out gcc was optimizing the struct layout in a way that matched my assumptions, but clang was not doing the same optimization. So I fixed the padding size in
b1902729
.Everything in here except for the clang assembler directive workaround should be merged (excluding the struct layout changes, I took a different approach there), please give the current head a go.
Pull request closed