Glibc 2.36에서 `DT_HASH` 제거가 여러 게임과 소프트웨어를 어떻게 망가뜨렸는지, 그리고 왜 Wine을 통한 Win32가 Linux에서 가장 안정적인 ABI처럼 보이는지를 다룹니다.
DT_HASH와 DT_GNU_HASHELF 형식에서는 심볼 해시 테이블을 제공하는 방법이 두 가지 있습니다. DT_HASH와 DT_GNU_HASH입니다. 첫 번째는 SYSV generic ABI의 일부이며, 잘 문서화되어 있고 필수 항목으로 표시되어 있습니다. DT_GNU_HASH는 더 새롭고, 더 작고, 더 빠른 대체물로, 문서화되어 있지 않으며, 몇몇 곳(Glibc, GNU ld, Musl, LLVM, mold 등)에 구현되어 있고, 제가 찾은 몇몇 블로그 글의 주제이기도 합니다. 그런데 이것은 DT_HASH와 동일한 기능도 제공하지 않습니다. 심볼 수를 얻으려면 이것을 완전히 파싱해야 합니다.
ELFOSABI_NONE 바이너리를 빌드하는 것이 아니라면 generic ABI를 따를 강제는 없다는 점도 언급할 가치가 있습니다. Glibc는 ELFOSABI_GNU를 사용하므로, 기술적으로는 DT_HASH를 포함하지 않아도 괜찮습니다.
Glibc는 호환성을 유지한다고 주장하며 아주 오랫동안 두 섹션을 모두 강제해 왔습니다. 이것은 최근 제거되었고, 대신 빌드는 “기본값”에 의존하게 되었습니다.
이 문제는 EAC EOS를 사용하는 게임들이 작동을 멈추면서 처음 rolling-release 배포판 사용자들에 의해 발견되었습니다. 회귀가 발생한 오픈 소스 프로젝트도 하나 있는데, libstrangle이라는 프레임 레이트 제한기입니다. EAC가 없는 게임인 Shovel Knight도 역시 망가졌습니다.
이것들은 Glibc 2.36 출시 직후, 좀 더 최전선의 배포판 사용자들이 찾아낸 몇 가지 고장 사례에 불과합니다. 2.36이 주류에 들어오면 더 많은 게임들(그리고 다른 소프트웨어들)이 망가질 것이라고 저는 의심합니다.
DT_HASH는 ABI의 일부가 아닙니다.DT_HASH를 포함할지는 배포판에 달려 있습니다.DT_HASH는 gABI에서 필수여서는 안 됩니다.정확히 무엇에 대해 누가 책임이 있는지에 대한 여러분 자신의 의견을 형성하기 위해, 연결된 모든 논의를 직접 읽어보시기를 권합니다.
개인적으로 저는 ABI를 바꾸는 것이 Linus의 의견처럼 아무도 알아차리지 못하는 동안에는 괜찮지만, 일단 그것이 눈에 띄게 되면 그때부터는 회귀라고 보는 입장에 동의합니다. 사람들이 그것에 의존하게 되는 순간, 그것은 기능이 됩니다.
안타깝게도 모든 것을 이에 맞게 쉽게 수정하거나 다시 컴파일할 수 있는 것은 아닙니다.
문제를 하류인 배포판들로 떠넘기는 것 또한 문제가 있으며 파편화를 더합니다.
저는 DT_GNU_HASH가 이미 16년째 존재하는 것과, 대부분의 배포판이 이것만을 기본값으로 사용하도록 전환했다는 점을 알고 있습니다. 하지만 그 16년 동안 호환성을 제공하고 모두를 위해 기본값을 덮어써 온 것은 Glibc였으며, 눈에 띄기 쉬운 deprecation 경고도 전혀 없었습니다. 또한 ELF를 소비하는 모든 구현체가 이 형식의 문서화되지 않은 발전을 계속 따라가리라고 기대하는 것도 비현실적입니다.
--hash-style=gnu가 기본값인가?어쩌다 보니 그렇게 된 걸까요? GCC의 기본 동작은 링커가 원하는 대로 하게 두는 것입니다. GNU Linker의 기본값은 “both”입니다.
ld --help | grep hash-style
--hash-style=STYLE Set hash style to sysv/gnu/both. Default: both
반면 mold의 기본값은 “sysv”입니다. 그렇다면 왜 대부분의 것들이 --hash-style=gnu로 빌드될까요? 많은 배포판에서 gcc -v는 다음과 같이 주장합니다.
Configured with: /build/gcc/src/gcc/configure ... --with-linker-hash-style=gnu ...
이것은 DT_GNU_HASH가 너무 초기 단계여서 ld의 기본값이 아직 sysv였던 오래전 시절의 잔재처럼 보입니다. 배포판들은 약속된 속도 향상을 원했고, 그래서 이것을 강제로 적용했으며, 그대로 굳어졌습니다.
이것은 더 널리 퍼지는 것처럼도 보입니다 - clang은 배포판을 감지하고, 배포판이 기본 gcc로 하는 일을 흉내 내는 것으로 보입니다.
저는 이 전체 상황이 왜 Linux용 네이티브 게임을 만드는 일이 어려운지를 보여준다고 생각합니다. 개발자들이 Windows를 목표로 하고 Wine + friends에 의존하는 것을 비난하기는 어렵습니다. 그쪽이 훨씬 더 안정적이고, 망가지거나 망가진 채로 남아 있을 가능성도 훨씬 낮기 때문입니다.