-
Notifications
You must be signed in to change notification settings - Fork 211
[aapcs64] Change size_t and ptrdiff_t definitions #335
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
The current definition[1] of `size_t` as `unsigned long` causes many problems with recent versions of gcc and glibc[*] and other software packages. When `size_t` is defined link this gcc issues warnings/errors when a pointer to a `size_t` variable is to be assigned to a `uint32_t *` variable (`uint32_t` is defined[2][3] as `unsigned int`) even though both `unsigned long int` and `unsigned int` are the same size (4 bytes). Two other ILP32 ABIs supported in the gcc and glibc (i.e. MIPS n32[4] and Intel x32[5]) define `size_t` as `unsigned int`. [1] https://github.com/ARM-software/abi-aa/blob/ee6b627a58988b56a761d1a3d545fc01b9b78241/aapcs64/aapcs64.rst?plain=1#L2954 [2] https://sourceware.org/git?p=glibc.git;a=blob;f=posix/bits/types.h;hb=d6c2760ef7f7cdeab912767f04db4b14632fbb5f#l42 [3] https://sourceware.org/git?p=glibc.git;a=blob;f=bits/stdint-uintn.h;hb=d6c2760ef7f7cdeab912767f04db4b14632fbb5f#l26 [4] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/config/mips/mips.h;hb=2f2e9bcfb0fd9cbf46e2d0d03b3f32f7df8d4fff#l3112 [5] https://gcc.gnu.org/git?p=gcc.git;a=blob;f=gcc/config/i386/x86-64.h;hb=2f2e9bcfb0fd9cbf46e2d0d03b3f32f7df8d4fff#l40 [*] both need to be patched to support ILP32, but the problems creep into more platform independent code Signed-off-by: Łukasz Stelmach <[email protected]>
|
Unfortunately I don't think we can change the type from long to int as this will change the name mangling of C++ functions with size_t as a parameter and that is a breaking change.
I sympathize with the request, but we would have to find a way of making it without breaking existing objects. |
Even if the ILP32 ABI is currently marked as (Beta), which allows such changes? |
|
It has been in Beta since 2016, mainly due to the lack of acceptance into the mainstream linux kernel and glibc. So while yes in theory it is in Beta which permits changes, in practice there is 9 years worth of legacy out there. |
|
And after a long time of not being actively used or maintained, ILP32 has been deprecated in GCC15 and may be removed in a future release. |
|
As you wrote, the ABI hasn't been accepted neither in linux nor in glibc and was recently deprecated in gcc. I don't know how much legacy binaries are out there, but recent toolchains available from Arm don't come with ILP32 glibc/libstdc++, so I guess their owners of AArch64 ILP32 binaries fully control those deployments and rebuilding them would be completely possible though annoying, I agree. The reason I propose this change is that code as simple as this #include <stdint.h>
#include <stdio.h>
int main(int ac, char* av[]) {
size_t foo = (size_t)ac;
uint32_t *bar = &foo;
printf("uint32_t: %zx\n", sizeof(uint32_t));
printf("size_t: %zx\n", sizeof(size_t));
return 0;
}fails to build for ILP32 using Arm's own toolchain. I believe there is a lot of source code that assumes, and rightly so, that on a 32-bit system these pointers are equivalent. These assumptions lead very far and cannot be worked around easily. For example there is this code in kmod static inline bool uadd32_overflow(uint32_t a, uint32_t b, uint32_t *res)
{
#if (HAVE___BUILTIN_UADD_OVERFLOW && __SIZEOF_INT__ == 4)
return __builtin_uadd_overflow(a, b, res);
#else
*res = a + b;
return UINT32_MAX - a < b;
#endif
}
static inline bool uaddsz_overflow(size_t a, size_t b, size_t *res)
{
#if __SIZEOF_SIZE_T__ == 8
return uadd64_overflow(a, b, res);
#elif __SIZEOF_SIZE_T__ == 4
return uadd32_overflow(a, b, res);
#else
#error "Unknown sizeof(size_t)"
#endif
}which builds fine on AArch64 and AArch32 but not on AArch64 ILP32 and it is impossible to fix (without an explicit cast like In my recent work of building different packages I found more similar cases of spaghetti dependencies where you are pulling on one end and need to dig through twisted knots and sometimes like here you hit a wall anyway. Indeed, my proposal breaks ABI, but current definition of |
|
It's generally wrong to make assumptions about Btw do you actually use ILP32? So far nobody has objected the deprecation. |
Alas these assumptions are already everywhere starting with glibc, gcc and llvm.
We are building a full distro to evaluate it. We are rebuilding all the packages we have built for armv7l and aarch64 and that is how we stumble upon such problems.
I figure it's been, because everyone, who needed to run 32-bit code on aarch64 for any reason (memory savings, porting issues) has used armv7l. And now some vendors phase out it from their SoCs. |
The current definition of
size_tasunsigned longcauses many problems with recent versions of gcc and glibc* and other software packages. Whensize_tis defined like this gcc issues warnings/errors when a pointer to asize_tvariable is to be assigned to auint32_t *variable (uint32_tis defined asunsigned int) even though bothunsigned long intandunsigned intare the same size (4 bytes).Two other ILP32 ABIs supported in the gcc and glibc (i.e. MIPS n32 and Intel x32) define
size_tasunsigned int.* both need to be patched to support AArch64 ILP32, but the problems creep
into more platform independent code