Patching ELF files to play games on Linux

So recently, I bought Mini Metro. It has official Linux support on Steam, so it should work fine, right? Well, starting up the game, I was greeted by a black screen. Time to figure out what’s wrong!


Digging around a bit, I found the game’s log file at ~/.config/unity3d/Dinosaur Polo Club/Mini Metro/Player.log. In the logs, you could see an exception like this being repeated:

DllNotFoundException: minimetrox
  at (wrapper managed-to-native) NativeExtensions.getDisplayCount()
  at Bootstrap.SelectResolution () [0x001bd] in <b5705b2105bc44d5a8bd0d768be49884>:0 
  at Bootstrap.Update () [0x00020] in <b5705b2105bc44d5a8bd0d768be49884>:0 

and also:

Unable to preload the following plugins:
	libminimetrox.so

So… maybe the game just can’t find libminimetrox.so? But looking in the game files, there is libminimetrox.so in Mini Metro_Data/Plugins.


Next idea, maybe the game can’t load libminimetrox.so for some other reason? Using ldd libminimetrox.so you could see that it uses /usr/lib64/ld-linux-x86-64.so.2 as the linker:

$ ldd libminimetrox.so
	linux-vdso.so.1 (0x00007fff029cc000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007f3362118000)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f33627a1000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007f3361f31000)
	/usr/lib64/ld-linux-x86-64.so.2 (0x00007f3362807000)

I found out that you can actually invoke the linker directly from command line, so let’s try that out:

$ /usr/lib64/ld-linux-x86-64.so.2 ./libminimetrox.so
./libminimetrox.so: symbol lookup error: ./libminimetrox.so: undefined symbol: __gxx_personality_v0

I guess it means that libminimetrox.so is linked to a symbol named __gxx_personality_v0, but the symbol is not found in any of the linked libraries. Searching for __gxx_personality_v0 on the internet, I found that it should actually be implemented by libstdc++.so.

We can use patchelf to add a new dependency to an existing ELF file:

patchelf --add-needed libstdc++.so.6 libminimetrox.so

We can verify our change with ldd:

$ ldd libminimetrox.so
	linux-vdso.so.1 (0x00007ffe20ddb000)
	libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f51e8600000)
	libm.so.6 => /usr/lib/libm.so.6 (0x00007f51e8f93000)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f51e89e0000)
	libc.so.6 => /usr/lib/libc.so.6 (0x00007f51e8419000)
	/usr/lib64/ld-linux-x86-64.so.2 (0x00007f51e90c1000)

See the new line for libstdc++.so.6?

Anyway, trying to open the game now, it booted up fine. Yay!


By yan, 2023-01-20