Linux:从32位用户模式程序检测64位内核(长模式)

5
什么是检测32位用户模式程序是否在64位内核下运行的最佳和最可靠方法(即系统是否处于“长模式”)?如果可能的话,我宁愿不调用外部程序(或加载任何内核模块)。
注意:我想检测是否使用了64位内核(或者说CPU是否处于长模式),而不仅仅是有没有64位处理器(/proc/cpuinfo告诉我这一点,但并不能告诉我64位能力是否被使用)。
如果使用32位编译的uname或者使用setarch i686,则内核会伪装成一个32位处理器。

你可以查看 /proc/vmallocinfo ,看一下地址是32位还是64位。 - Erik
只有 root 用户才能读取,对吧? - atomice
/proc/kallsyms 是一个备选项,它是默认的可读取全局文件。 - caf
3个回答

6

调用 uname() 函数并检查返回的 machine 字符串,对于 64 位 Intel 平台,它将是 x86_64

撤销使用 setarch 的效果的一种方法是重置个性:

#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;
}

当以32位模式编译并在64位系统上运行时,此代码将产生正确的结果:

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

编辑:修正了代码以撤销 setarch 的影响。

参考文献


这种方法可以运行,但如果我使用 setarch 运行程序,即 setarch i686 ./uname,它会打印出 i686。 - atomice
这是正确的行为,不是吗?您正在显式地更改进程所看到的架构。 - trojanfoe
我真正想做的是找出CPU是否处于长模式。 - atomice
1
@atomice:嗯,当您运行32位进程时,CPU并不处于长模式下... - caf

1

假设uname()作弊,仍然有几种机制。一种方法是检查任何内核符号地址的宽度。

#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);
}

0

如果内核已经进行了配置,你可以从/proc/config.gz读取内核配置。

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

我不确定你需要多么可移植 - 它似乎不是一个超级常见的配置选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接