5

What's the best and most reliable way to detect if a 32-bit user mode program is running on a 64-bit kernel or not (i.e. if the system is in 'long mode')? I'd rather not call external programs if possible (or have to load any kernel modules).

Note: I want to detect whether a 64-bit kernel is being used (or really, whether the CPU is in long mode), not simply if a 64-bit capable processor is present (/proc/cpuinfo tells me that but not whether the 64-bit capability is being used).

The kernel fakes a 32-bit processor if uname is compiled 32-bit or if setarch i686 is used.

atomice
  • 3,062
  • 17
  • 23

3 Answers3

6

Call the uname() function and check the returned machine string, which will be x86_64 for a 64-bit Intel platform.

One way of reversing the effect of the use of setarch is to reset the personality:

#include <stdio.h>
#include <sys/utsname.h>
#include <sys/personality.h>

int main()
{
    struct utsname u;

    personality(PER_LINUX);

    uname(&u);
    puts(u.machine);
    return 0;
}

This shows the right results when compiled in 32-bit mode and run on a 64-bit system:

$ gcc -m32 -o u u.c
$ ./u
x86_64
$ setarch i686 ./u
x86_64

EDIT: Fixed code to reverse effect of setarch.

Reference.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
  • This sort of works, but if I run the program with `setarch`, i.e. `setarch i686 ./uname` it prints i686 instead. – atomice May 10 '11 at 14:43
  • That's correct behaviour though, isn't it? You are explicitly changing the architecture that the process is seeing. – trojanfoe May 10 '11 at 14:48
  • Well what I'm really trying to do is find out if the CPU is in long mode or not. – atomice May 10 '11 at 14:55
  • 1
    @atomice: Well, the CPU isn't in long mode while it's running your 32 bit process... – caf May 17 '11 at 05:28
1

Assuming that uname() is cheating, there are still several mechanisms. One way is to check the width of the address of any of the kernel symbols.

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char **argv) {
  char *inputline = malloc(1024);
  char *oinputline = inputline;
  int fd = open("/proc/kallsyms", O_RDONLY);
  int numnibbles = 0;
  if (fd == -1) {
      perror("open");
      free(inputline);
      exit(1);
  }
  read(fd, inputline, 1024);
  close(fd);
  while(!isspace(*inputline)) {
      numnibbles++;
      inputline++;
  }
  printf("%dbit\n", numnibbles*4);
  free(oinputline);
  exit (0);
}
Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
0

If the kernel is configured for it, you can read the kernel config from /proc/config.gz

zcat /proc/config.gz | grep CONFIG_64BIT
# CONFIG_64BIT is not set

I'm not sure how portable you need it to be- it doesn't seem like a super common config option.

tMC
  • 18,105
  • 14
  • 62
  • 98