Почему сценарий Linux syscall возвращает "long"?

Я читаю Linux Kernel Development, 3-е изд., чтобы узнать о реализации и дизайне ядра. Глава 5 касается системных вызовов. Автор показывает пример объявления syscall, который определяется с помощью макроса SYSCALL_DEFINE0, который в этом конкретном примере расширяется до:

asmlinkage long sys_getpid(void)

Далее он говорит, что:

[...] Для совместимости между 32- и 64-разрядными системами системные вызовы, определенные для возврата int в пользовательском пространстве, возвращают длинные в ядре.

Он не идет глубже этого, и я не могу точно понять, почему это так. Почему использование long связано с 32- и 64-разрядными системами? Почему мы не можем вернуть простой int?

Ответ 1

Потому что на многих 64 бит машинах (например, x86-64) для общего компилятора GCC sizeof(int)==4, но sizeof(void*)==8 && sizeof(long)==8; Это называется моделью данных I32LP64 (или просто LP64) .

Например, скомпилируйте и запустите следующую программу в системе Linux/x86-64:

#include<stdio.h>
#include<stdint.h>
int main ()
{
  printf ("sizeof(int)=%d\n", (int) sizeof (int));
  printf ("sizeof(intptr_t)=%d\n", (int) sizeof (intptr_t));
  printf ("sizeof(short)=%d\n", (int) sizeof (short));
  printf ("sizeof(long)=%d\n", (int) sizeof (long));
  printf ("sizeof(long long)=%d\n", (int) sizeof (long long));
  printf ("sizeof(void*)=%d\n", (int) sizeof (void *));
  return 0;
}

После компиляции в моей системе с gcc -Wall s.c -o s и запуском ./s на моем процессоре Debian/Sid/x86-64 (i3770k GCC 4.8.2):

sizeof(int)=4
sizeof(intptr_t)=8
sizeof(short)=2
sizeof(long)=8
sizeof(long long)=8
sizeof(void*)=8

после компиляции в режиме 32 бит с использованием gcc -m32 -Wall s.c -o s32 и запуска ./s32:

sizeof(int)=4
sizeof(intptr_t)=4
sizeof(short)=2
sizeof(long)=4
sizeof(long long)=8
sizeof(void*)=4

Я получаю тот же вывод, если компиляция для x32 с помощью gcc -mx32 -O3 -Wall s.c -o sx32!

Кстати, возможно, лучший вопрос - почему бы не использовать intptr_t.... Я понятия не имею (вероятно, вопрос привычек; когда Linus начал чтобы закодировать его ядро, C99 стандарт -defining <stdint.h> и intptr_t - еще не существовал).

Подробнее о ABI, в частности, внимательно прочитайте X86-64 ABI (см. также x32 ABI...) и wikipage на соглашениях x86.