SoLo – Giải pháp "lạ" giúp file binary tĩnh Linux sử dụng GPU từ driver glibc
SoLo là một bộ nạp thư viện .so dành riêng cho file binary tĩnh trên Linux, giúp chúng giao tiếp với driver GPU của hệ thống (thường được biên dịch với glibc) mà không cần container, AppImage hay nạp libc thứ hai vào tiến trình. Dự án đạt hiệu suất khủng khi có thể tải thành công hơn 2.100 thư viện phổ biến nhất trên Debian trong CI. Đây là hướng tiếp cận mới giải quyết bài toán "một file, không phụ thuộc" nhưng vẫn cần dùng phần cứng đồ họa.

SoLo – Cú bắt tay kỳ diệu giữa binary tĩnh và driver GPU của Linux
Trong thế giới Linux, một file binary tĩnh thường được xem là "chuẩn mực" của sự đơn giản: chỉ một file, không phụ thuộc gì, không gì có thể hỏng. Nhưng khoảnh khắc ứng dụng cần GPU, câu chuyện trở nên phức tạp. Các driver Vulkan hay OpenGL do hệ thống cung cấp đều là thư viện động (shared object) được biên dịch với glibc, trong khi binary tĩnh thường dùng musl và không thể gọi dlopen() chúng một cách bình thường. SoLo xuất hiện để xóa bỏ rào cản đó bằng một bộ nạp ELF riêng và cầu nối ABI glibc ngay bên trong tiến trình tĩnh.
Vấn đề kinh điển: Binary tĩnh và "bức tường" GPU
Việc phân phối phần mềm dưới dạng một file thực thi tĩnh có sức hút đặc biệt với các nhà phát triển vì không phải lo lắng về thư viện hệ thống, thư viện dính kèm hay xung đột phiên bản. Tuy nhiên, các driver đồ họa (như Mesa, RADV cho AMD, NVIDIA) luôn được cung cấp ở dạng thư viện động theo chuẩn glibc. Khi một ứng dụng tĩnh viết bằng musl (một thư viện C thay thế, nhẹ hơn) cố nạp chúng, sự khác biệt về ABI (Application Binary Interface) khiến mọi thứ đổ vỡ.
Thông thường, người ta giải quyết bằng container (Docker), AppImage hoặc Flatpak – thực chất là "giấu" một bản phân phối nhỏ bên trong ứng dụng. SoLo làm điều ngược lại hoàn toàn.
SoLo – Kiến trúc "một tiến trình, hai thế giới"
SoLo không nạp glibc vào tiến trình. Thay vào đó, nó tự viết một bộ nạp ELF cho riêng mình (hỗ trợ kiến trúc x86-64 và aarch64), đảm nhận việc ánh xạ các phân đoạn ELF, quản lý biểu tượng (symbols), tương thích TLS (Thread Local Storage) và thực hiện relocation.
Sau đó, mọi lời gọi malloc, pthread_mutex_lock hay printf từ driver GPU (vốn được biên dịch theo chuẩn glibc) sẽ được glibc_shim.cpp "dịch" sang các hàm tương thích chạy trên nền musl sẵn có trong tiến trình. Điều này cho phép một executable tĩnh duy nhất giao tiếp trực tiếp với driver của hệ thống:
┌──────────────────── fully static executable ────────────────────┐
│ │
│ application → embedded Vulkan loader → SoLo dlopen/dlsym │
│ ├─ x86-64 ELF mapper │
│ └─ glibc ABI → musl │
│ │ │
└───────────────────────────────────────────┬─────────────────────┘
│ maps at runtime
▼
system Mesa/Vulkan ICD.so + DSOs
Bằng chứng sắt đá: Chạy Vulkan từ một file tĩnh
Không chỉ dừng ở lý thuyết, SoLo đi kèm một bản demo hoàn chỉnh. Bạn có thể tải file binary tĩnh, thực thi và nó sẽ tự động khám phá driver Vulkan của hệ thống (ICD manifest), nạp chúng qua SoLo, tạo một compute shader và ghi kết quả ra file PNG. Điều đáng kinh ngạc là demo này chạy tốt trên các GPU AMD (RADV, RadeonSI), Intel, NVIDIA và cả Apple M1 thông qua Asahi Linux.
Câu lệnh thử nghiệm ngay lập tức:
curl -LO https://github.com/pg83/solo/releases/latest/download/vulkan-x86_64
chmod +x vulkan-x86_64
./vulkan-x86_64 hello.png
Kiểm tra để chắc chắn rằng nó thực sự tĩnh:
readelf -lW ./vulkan-x86_64 | grep INTERP # no output
readelf -dW ./vulkan-x86_64 # "There is no dynamic section"
Điểm mạnh khác biệt so với các dự án tiền nhiệm
- Không có libc thứ hai: Các dự án như Detour hay gcompat thường khởi động hệ thống
ld-linuxvà cho phép hai libc cùng tồn tại, dẫn đến phức tạp về TLS. SoLo đi theo hướng ngược lại: tự ánh xạ DSO và "dịch" imports glibc qua musl. - Callback an toàn: Không có chuyện mỗi lần gọi hàm ngoài lại phải chuyển đổi TLS bằng trampoline kiểu graphics.gd. Toàn bộ tiến trình chỉ có một thế giới TLS (musl).
- Ngoại lệ C++ xuyên biên giới: Cơ chế unwinding hoạt động xuyên suốt, không có hai hệ thống exception riêng biệt.
- Độ phủ ABI glibc được kiểm thử thực tế: CI của dự án tải toàn bộ thư viện dùng chung (shared objects) từ 1.000 gói phần mềm phổ biến nhất Debian, tương đương hơn 2.100 đối tượng, trên cả hai kiến trúc.
"Mục tiêu là biến bức tường cứng giữa 'hoàn toàn tĩnh' và 'dùng GPU hệ thống' thành một lớp tương thích hữu hạn và có thể kiểm thử. File PNG tạo từ Vulkan chính là minh chứng đầu tiên rằng bức tường đó có cánh cửa."
Ứng dụng thực tế và hạn chế hiện tại
SoLo không chỉ dành riêng cho GPU. Nó còn là nền tảng để xây dựng các công cụ mạnh mẽ như terminal emulator Shitty (tên hài hước nhưng tốc độ "blazingly fast"). Ở phạm vi rộng hơn, bất kỳ ứng dụng tĩnh nào cần tương tác với thư viện động của hệ thống (như Wayland) đều có thể hưởng lợi.
Tuy nhiên, dự án vẫn có giới hạn rõ ràng:
- Chỉ hỗ trợ Linux trên hai kiến trúc x86-64 và aarch64.
- Một số hàm glibc chưa được triển khai sẽ khiến chương trình "chết" một cách kêu vang (fail loudly) thay vì làm hỏng tiến trình.
- Threads tạo trước khi gọi dlopen có thể nhận TLS của module nạp sau với giá trị khởi tạo bằng 0, nên cần chú ý thứ tự nạp thư viện.
CI status
Codecov
Tương lai cho "boring" nhưng mạnh mẽ
Với người dùng Việt Nam đang làm việc trong lĩnh vực phát triển hệ thống, DevOps hay hạ tầng đám mây, SoLo mở ra một hướng đi rất thú vị: bạn không cần phải mang theo cả một bộ công cụ phức tạp, chỉ cần một file thực thi duy nhất nhưng vẫn có thể khai thác triệt để sức mạnh phần cứng của máy chủ. Nó biến khái niệm "tĩnh" không còn là giới hạn, mà là một lựa chọn triển khai linh hoạt và an toàn.
Hãy thử nghiệm dự án ngay hôm nay:
git clone https://github.com/pg83/solo.git
cd solo
./build vulkan
./vulkan hello.png