linux /proc/cpuinfo로 aarch64인지 x86_64인지 가리고 싶습니다

Stephen Kyoungwon Kim@Google의 이미지

x86_64에서 빌드된 프로그램이 있습니다. x86_64에서는 그냥 돌아가고, arm64에서는 qemu+kvm을 이용해서 binary translation을 해서 수행시키는 것으로 알고 있습니다. 두 환경 모두에 완전히 동일한 실행 파일을 사용합니다. 앞으로 arm이나 몇 가지 다른 타겟에서 마찬가지로 qemu+kvm 가상화를 이용해서 수행될 가능성이 있습니다.

실행 중에 이 프로그램의 host가 x86_64인지 arm64인지 혹은 다른 무엇인지 간단하게 구분하고 싶습니다. 현재 찾아낸 방법은 우선 uname -m을 fork-exec으로 수행하고, pipe를 이용해서 output을 읽어오는 것입니다. uname() 콜은 에뮬레이트 되더군요.

이것보다 간단하고 신뢰성 높은 방법을 찾고 있습니다.

한 가지 생각나는 건 뭔가 /proc/cpuinfo를 확인하는 것이었습니다. 제 데스크탑, 회사 워크스테이션, 그리고 회사의 arm64 보드에서 /proc/cpuinfo를 수행시켜 보니 우선 해당 파일의 형식이 많이 달라 보이더군요. 그 세 가지만 비교한다면, arm64는 cpu implementor라는 라인이 있고 x86_64는 없다거나, 형식과 내용에서 차이가 있어 보였습니다.

만약 눈으로 /proc/cpuinfo를 본다면, 주어진 cpuinfo가 arm64인지 x86_64인지 혹은 다른 무엇인지 알아낼 수 있는 방법이 있는지요?

%P.S. 여러 가지 아이디어들 감사합니다. popen으로 uname -m을 불러 해결했습니다.

ymir의 이미지

man -s 2 uname
uname 명령이 uname() 을 사용합니다.

중간에 uname() 콜이 에뮬레이트 된다는 표현이 있었군요.
가상 환경에서 host 의 정보를 확인하시려는 건가요?
그래서 uname() 이 안먹히는 상황이구요?

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

ymir의 이미지

단순히 실행되는 곳이 가상 환경인지 아닌지 판단하시려는 용도라면..
virt-what 같은 걸 써보시는도 괜찮을 것 같네요.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

Stephen Kyoungwon Kim@Google의 이미지

긴 이야기를 너무 짧게 썼는데, 제가 일하는 소프트웨어는 거대한 소프트웨어 프로젝트의 일부입니다. 아마 빌드 시스템이나 거기 들어 있는 몇몇 컴포넌트 때문에 aarch64 위에서 native로 컴파일 할 수는 없는 모양입니다. 빌드를 타겟 별로 다르게 하는 것도 고려할 수 없는 상황인 것 같구요.

그런데 aarch64 위에서도 동작을 해야 하게 되어서 qemu+kvm을 이용해 x86_64 바이너리를 돌리고 있습니다.

그간은 호스트 아키텍쳐를 알 필요가 없었습니다. 그런데 새 feature를 추가하면서 보니 호스트 아키텍쳐를 반드시 알아야 하는 상황이 되었습니다. 빌드 타임에 알면 더 좋지만 그건 안 되니까 런타임에라도 알았으면 했고요.

qemu 위에 실행되는 건 주로 호스트가 arm64일 때이긴 한데 x86도 그런 식으로 할 수는 있어서 가상 환경인지 아닌지를 아는 것만으로는 충분하지 않은 것 같습니다. 정확히는 현재로선 x86_64인지 aarch64인지 알아야 하고, 앞으로는 arm인지 mips인지 등등을 추가로 알아내야 할 수도 있습니다.

uname -m의 아웃풋을 파이프를 통해 읽는 건 이미 거의 어렵지 않게 되기는 한데, uname() 콜 한 번으로 될 일을 저렇게 복잡하게 처리하는 게 최선은 아닌 것 같아서 혹시 더 간단한 방법이 없는지 생각해 보게 되었습니다. /proc/cpuinfo도 보아하니 커널마다 다르고 권고 사항이 있지 사실 강제는 없다고 하는 것 같네요.

ymir의 이미지

개인적인 생각으로.. cpuinfo 를 파싱해서 정보를 뽑아 내는 것은..
이미 확인된 시스템에서는 확실하겠지만..
(거의 없을 것 같기는 하지만) 시스템이 변경되거나 했을 때..
계속해서 추가로 확인하는 작업을 해줘야 하고..
적절한 주석이 없다면 오히려 의도를 파악하기 힘들 수도 있을 것 같습니다.
일단은 uname 을 실행해서 아웃풋을 뽑아내놓고..
이후에 다른 방법은 없는지 찬찬히 모색해도 괜찮을 것 같습니다.

fork, exec, pipe 를 언급하셨는데..
popen 대신 직접 따로 구현하신 것처럼 들리네요.
특별한 이유가 있는게 아니라면, 간단히 이미 있는 거 써도 괜찮을 것 같습니다.

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

Stephen Kyoungwon Kim@Google의 이미지

cpuinfo는 말씀하신 것처럼 스탠다드가 없고 그냥 커널 버전/설정별로 다르게 집어넣는 것 같더군요. 우선은 uname 명령어를 사용하기로 했습니다.

그리고 popen은 몰랐네요. 감사합니다. :) C/C++로 멀티 프로세스 프로그램을 할 일이 없다 보니 옛날 옛적에 fork, exec, pipe로 쉘 만들었던 기억을 끄집어 내어 테스트를 했었습니다. 유사한 일을 할 때 bash script나 python을 써서 C에 popen이 있을 거라고 미처 생각을 못했었네요.

익명 사용자의 이미지

호스트의 /proc/cpuinfo 를 읽으려면 호스트 파일 시스템에 접근 가능해야 하는데,
그럴 바에는 오히려 호스트에서 uname 을 실행시키는게 낫지 않나요?

익명 사용자의 이미지

아.. 맞다.. arch 가 달라서 실행을 못하는구나..

Stephen Kyoungwon Kim@Google의 이미지

제가 질문을 명료하게 못 한 것 같습니다. 기본적으로 문제의 프로그램은 C/C++ 응용 프로그램입니다. 복잡한 어른들의 사정으로 인해 x86_64용으로 빌드된 것을 arm64 위에서 돌리고자 부득이하게 qemu + kvm을 사용하는 것으로 알고 있습니다. 제 이해로는 host filesystem에 접근은 가능한데, 아닌가요?

제 목표는 call을 하면 arch를 리턴해 주는 C++ 혹은 C function call을 만드는 것입니다.

제 질문글에도 나와 있듯이 현재로는 pipe, fork, exec을 이용해서 host에서 uname을 실행시키는 게 제가 생각해 낸 최선입니다. 그런데 이건 원래 native execution이라면 uname() 콜 한 번으로 해결될 일이고, 기껏해야 3, 4줄짜리 코드입니다. 이에 반해 uname -m을 서브 프로세스에서 수행시켜서 아웃풋을 리다이렉션 해오는 일은 너무 복잡하고요.

간단한 솔루션이 없을까 해서 질문을 드리게 되었습니다.

익명 사용자의 이미지

한가지 간단한 방법 찾았어요. 호스트에서 미리 uname -a 실행 후 결과를 txt 파일로 저장.
그후 게스트에서 해당 파일 읽으면 끝

Stephen Kyoungwon Kim@Google의 이미지

이렇게 하려면 파일이 생기겠죠. 그런데 이게 uname -a를 popen 등을 이용해서 처리하는 것보다 나은 점이 있어 보이지 않습니다. 후자는 지저분한 파일이 생기지 않거든요.

익명 사용자의 이미지

그러고보니 텔넷이나 스스흐로 접속해서 유네임 실행시키는 방법도 있군요

bushi의 이미지

[schoi0@sel-schoi0-d1 net]$ gcc -m32 -o elf elf.c -Wall
[schoi0@sel-schoi0-d1 net]$ ./elf
I am [Intel 80386]
Host is [AMD x86-64 architecture]
[schoi0@sel-schoi0-d1 net]$ arm-linux-gnueabihf-gcc -o elf elf.c -static -s
[schoi0@sel-schoi0-d1 net]$ aarch64-linux-gnu-gcc -o elf elf.c -static -s
[schoi0@sel-schoi0-d1 net]$ file elf
elf: ELF 64-bit LSB executable, ARM aarch64, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.7.0, stripped
[schoi0@sel-schoi0-d1 net]$ ./elf
I am [ARM AARCH64]
Host is [AMD x86-64 architecture]
[schoi0@sel-schoi0-d1 net]$ 
[schoi0@sel-schoi0-d1 net]$ arm-linux-gnueabihf-gcc -o elf elf.c -static -s
[schoi0@sel-schoi0-d1 net]$ file elf
elf: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, stripped
[schoi0@sel-schoi0-d1 net]$ ./elf
I am [ARM]
Host is [AMD x86-64 architecture]
댓글 첨부 파일: 
첨부파일 크기
Plain text icon elf.c.txt9.06 KB
Stephen Kyoungwon Kim@Google의 이미지

다른 부분은 이해가 되는데 aarch64-linux-gnu-gcc 로 컴파일 해서 aarch64 실행 파일로 보이는 게 어떻게 x86_64 머신 위에 별다른 준비 없이 실행이 되나요?

bushi의 이미지

[schoi0@sel-schoi0-d1 net]$ modinfo binfmt_misc
filename:       /lib/modules/5.1.15-300.fc30.x86_64/kernel/fs/binfmt_misc.ko.xz
license:        GPL
alias:          fs-binfmt_misc
depends:        
retpoline:      Y
intree:         Y
name:           binfmt_misc
vermagic:       5.1.15-300.fc30.x86_64 SMP mod_unload 
 
[schoi0@sel-schoi0-d1 net]$ cat /proc/sys/fs/binfmt_misc/qemu-aarch64
enabled
interpreter /usr/bin/qemu-aarch64
flags: 
offset 0
magic 7f454c460201010000000000000000000200b700
mask ffffffffffffff00fffffffffffffffffeffffff
 
[schoi0@sel-schoi0-d1 net]$ cat /proc/sys/fs/binfmt_misc/qemu-arm
enabled
interpreter /usr/bin/qemu-arm
flags: 
offset 0
magic 7f454c4601010100000000000000000002002800
mask ffffffffffffff00fffffffffffffffffeffffff
 
[schoi0@sel-schoi0-d1 net]$ rpm -ql qemu-user-binfmt
/usr/lib/binfmt.d/qemu-aarch64-dynamic.conf
/usr/lib/binfmt.d/qemu-aarch64_be-dynamic.conf
/usr/lib/binfmt.d/qemu-alpha-dynamic.conf
/usr/lib/binfmt.d/qemu-arm-dynamic.conf
/usr/lib/binfmt.d/qemu-armeb-dynamic.conf
/usr/lib/binfmt.d/qemu-hppa-dynamic.conf
/usr/lib/binfmt.d/qemu-m68k-dynamic.conf
/usr/lib/binfmt.d/qemu-microblaze-dynamic.conf
/usr/lib/binfmt.d/qemu-microblazeel-dynamic.conf
/usr/lib/binfmt.d/qemu-mips-dynamic.conf
/usr/lib/binfmt.d/qemu-mips64-dynamic.conf
/usr/lib/binfmt.d/qemu-mips64el-dynamic.conf
/usr/lib/binfmt.d/qemu-mipsel-dynamic.conf
/usr/lib/binfmt.d/qemu-mipsn32-dynamic.conf
/usr/lib/binfmt.d/qemu-mipsn32el-dynamic.conf
/usr/lib/binfmt.d/qemu-or1k-dynamic.conf
/usr/lib/binfmt.d/qemu-ppc-dynamic.conf
/usr/lib/binfmt.d/qemu-ppc64-dynamic.conf
/usr/lib/binfmt.d/qemu-ppc64le-dynamic.conf
/usr/lib/binfmt.d/qemu-riscv32-dynamic.conf
/usr/lib/binfmt.d/qemu-riscv64-dynamic.conf
/usr/lib/binfmt.d/qemu-s390x-dynamic.conf
/usr/lib/binfmt.d/qemu-sh4-dynamic.conf
/usr/lib/binfmt.d/qemu-sh4eb-dynamic.conf
/usr/lib/binfmt.d/qemu-sparc32plus-dynamic.conf
/usr/lib/binfmt.d/qemu-xtensa-dynamic.conf
/usr/lib/binfmt.d/qemu-xtensaeb-dynamic.conf
Stephen Kyoungwon Kim@Google의 이미지

깔려 있었고 그거를 지우니 이번엔 그런 파일이 없다는 이상한 메시지가 나오면서 안 되네요. 파일은 리스팅은 됩니다.

아마 bash가 보고 파일 타입과 qemu 유무에 따라 에뮬레이션을 자동으로 해주는 모양이네요. 그럼 /proc/self/exe는 이 타-타겟용 실행파일에 대한 심볼릭 링크겠네요. 감사합니다.

수정) bash 수준에서 하는 게 아니라 리눅스 커널 수준에서 바이너리를 보고 호스트 네이티브가 아니면 qemu한테 던져주는 기능이 있나 보군요.

bushi의 이미지

본래 용도는 인터프리터가 알려진 모든 종류의 파일을 '자연스럽게 실행(execute)' 할 수 있도록 해주는 것입니다.
wine 을 설치하면 .exe (PE포맷), jre 를 설치하면 jar 파일을 '자연스럽게 실행' 할 수 있는 정도로 편합니다.

ls -l /proc/self/exe 해보세요.

라스코니의 이미지

프로그램에 인자를 주면 되지 않을까요? 이런 서비스까지 제공할 필요는 없을 것 같습니다.
./aaaa -x86_64, ./aaaa -xarm64식으로 하면 될 것 같은데요.
사용자가 물론 올바른 인자를 주어야 하는 책임이 있고요.

Stephen Kyoungwon Kim@Google의 이미지

상식적으론 그런데 (커맨드라인 옵션을 정의하고 파싱하는 좋은 라이브러리도 사내에 있고요) 실행 커맨드를 바꾸는 건 옵션이 아니라고 합니다. 저도 왜 그런지는 아직 도대체 이 프로그램이 거대한 프로젝트 내에서 어디서 어떻게 돌아가는지 다 파악을 못해서 정확히 모르겠습니다.

그리고 사실 호스트 아키텍쳐 찾는 게 그리 어려운 일은 아니구요.

cjh의 이미지

프로그램 실행하기 전에 ARCH=`uname -m`과 같이 환경변수를 지정하고 프로그램 내에서 환경변수를 읽어서 판단하는 방법도 있을것 같네요.

--
익스펙토 페트로눔

Stephen Kyoungwon Kim@Google의 이미지

프로그램을 실행하는 방식은 변경하고 싶지 않아 하더군요.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.