Wine hoạt động như thế nào 101
(werat.dev)- Wine là một lớp tương thích cho phép chạy chương trình Windows trên các hệ điều hành tương thích POSIX (Linux, macOS, BSD)
- Steam Deck của Valve cũng sử dụng giải pháp dựa trên Wine
WINE = Wine Is Not an Emulator
- Cách làm kiểu giả lập thì chậm, và trên thực tế Linux/macOS có thể chạy nhị phân Windows một cách native (nếu được hỗ trợ một chút)
- Bài viết giải thích chi tiết cách nhị phân Linux/Windows hoạt động thông qua debugger
Hello, Wine!
- Về cơ bản, Wine là một "Dynamic Loader" cho file thực thi Windows
- Nó là một nhị phân Linux native và biết cách xử lý EXE hay DLL
- Wine nạp file thực thi Windows vào bộ nhớ, phân tích nó để xác định các phụ thuộc, rồi nhảy tới đoạn mã cần chạy
- Chỉ riêng như vậy cũng đã đủ để chạy nhị phân Windows, nhưng vẫn có ngoại lệ
System Calls
- Các lời gọi hệ thống, hay còn gọi là syscall, là thứ khiến Wine trở nên phức tạp
- Syscall được triển khai trong hệ điều hành, chứ không nằm trong file thực thi hoặc thư viện
- Các syscall do hệ điều hành cung cấp chính là OS API
- Linux: read, write, open, brk, getpid,..
- Windows: NtReadFile, NtCreateProcess, NtCreateMutant,..
- Lời gọi hệ thống khác với lời gọi hàm thông thường trong mã. Ví dụ, việc mở file phải được kernel xử lý vì nó cần theo dõi file descriptor
- Vì vậy mã ứng dụng cần có cách tự "ngắt" và chuyển quyền điều khiển cho kernel ("Context Switch")
- Tập hàm và cách gọi do hệ điều hành cung cấp là khác nhau giữa các OS
- Trên Linux, khi gọi hàm read() thì phải đặt file descriptor vào thanh ghi
%rdi, con trỏ buffer vào%rsi, và số byte cần đọc vào%rdx - Nhưng trên Windows thì không có hàm read() trong kernel
- Trên Linux, khi gọi hàm read() thì phải đặt file descriptor vào thanh ghi
- Nếu chạy cùng một đoạn mã in ra "Hello World!" trên Linux/Windows thì
- Linux gọi
putscủalibc.so, còn Windows gọiprintfcủaucrtbase.dll - Trên Linux ngày nay, việc liên kết tĩnh khá phổ biến, nên phần cài đặt của
putsđược đưa luôn vào trong nhị phân vàlibc.sothường không được dùng khi chạy
- Linux gọi
- Trên Windows, ít nhất cho tới khá gần đây, "chỉ malware mới trực tiếp dùng system call"
- Ứng dụng thông thường luôn phụ thuộc vào
kernel32.dll/kernelbase.dll/ntdll.dllđể tránh giao tiếp trực tiếp với kernel
- Ứng dụng thông thường luôn phụ thuộc vào
Runtime translation of Syscalls
- Nếu chặn syscall lại thì sao?
Ứng dụng gọiNtWriteFile()thì chen vào, gọiwrite()rồi trả kết quả theo đúng định dạng mà nhị phân mong đợi? - Điều đó có thể làm được nếu cung cấp một phiên bản
ucrtbase.dlltùy biến, nhưng sẽ phát sinh những vấn đề phức tạp - Thay vào đó, Wine sửa
ntdll.dll, thành phần nằm giữa nhị phân và kernel - Các phiên bản Wine gần đây gồm
ntdll.dll(nhị phân PE) vàntdll.so(nhị phân ELF)- DLL là một lớp mỏng chỉ đơn giản chuyển hướng lời gọi sang phía ELF
- ELF có một hàm đặc biệt tên là
__wine_syscall_dispatcher, thực hiện phép màu chuyển đổi stack hiện tại từ Windows sang Linux, hoặc ngược lại
- Trình điều phối syscall này là cây cầu nối giữa thế giới Windows và thế giới Linux
- Nó xử lý calling convention, cấp phát không gian stack, di chuyển các thanh ghi, v.v.
- Khi luồng thực thi đi vào
ntdll.sovà chuyển sang nhị phân Linux, ta có thể sử dụng toàn bộ Linux API
Thế là xong à?
- Nghe có vẻ rất dễ, nhưng...
- Windows API là một hệ rất lớn, tài liệu không đầy đủ, có cả bug đã biết/chưa biết, và chúng phải được giữ nguyên như vốn có. Phần lớn mã của Wine là phần cài đặt cho các DLL Windows khác nhau
- Có nhiều cách khác nhau để gọi syscall, và về mặt kỹ thuật không có cách nào ngăn ứng dụng gọi syscall trực tiếp
(Hãy nhớ rằng game Windows làm đủ mọi trò điên rồ)
Kernel Linux có cơ chế đặc biệt để xử lý chuyện này, và dĩ nhiên điều đó lại làm tăng thêm độ phức tạp - Vấn đề 32-bit và 64-bit cũng rất phi lý. Có vô số game 32-bit, và chúng sẽ không được phát hành lại dưới dạng 64-bit. Wine hỗ trợ cả hai nên điều này tiếp tục làm tăng độ phức tạp
- Ở đây còn chưa nhắc đến
wine-server. Đây là một tiến trình riêng do Wine tạo ra, dùng để duy trì "trạng thái" của kernel (file descriptor, mutex, v.v.) - Muốn chạy game à? Bạn còn phải xử lý DirectX, PulseAudio, thiết bị nhập liệu và nhiều thứ khác nữa nên khối lượng công việc là rất lớn
- Wine đã được phát triển trong thời gian dài và đã đi một chặng đường rất xa. Ngày nay nó có thể chạy trơn tru các game mới như Cyberpunk 2077 hay Elden Ring
Thậm chí đôi khi Wine còn cho hiệu năng tốt hơn cả Windows
11 bình luận
Nội dung thì hay, nhưng chất lượng của phần tóm tắt thực sự quá xuất sắc. Cảm ơn bạn.
Tôi đang sử dụng yes24 và Kyobo Bookstore, các dịch vụ đọc sách theo hình thức thuê bao.
Sau khi chuyển môi trường PC ở nhà sang Ubuntu, tôi đã thử chạy YES24 và Kyobo Bookstore bằng Wine.
Cả hai đều dùng DRM riêng nên tôi đã nghĩ không biết có chạy được không, nhưng YES24, mà tôi biết là được làm bằng QT, thì chạy tốt, còn ebook của Kyobo Bookstore thì lại không chạy. (UI chạy, DRM không chạy)
Tôi biết cả hai đều có áp dụng DRM nên cũng đã nghĩ vì sao cái thì chạy còn cái thì không, nhưng đọc bài viết trên xong thì có vẻ tôi hiểu đại khái rồi đấy (ảnh meme kiểu "tôi đã hiểu hoàn hảo rồi")
Từ sau
wine5.0, KakaoTalk chạy được mà không cần bất kỳ thiết lập nào nên tôi rất vui. (Dù đó là chuyện khác với việc tôi có muốn dùng KakaoTalk hay không..) Một vài chỗ hiển thị màn hình vẫn còn chút vấn đề, nhưng các chức năng như gửi ảnh qua clipboard hoạt động rất liền mạch. Có vẻ như Wine chủ yếu tập trung vào việc chạy game, nhưng cũng rất tốt khi nó chạy được nhiều ứng dụng khác nhau. Ngay cả khi có bàn chuyện triển khai Linux ở các cơ quan công, việc họ còn chẳng nghĩ tới phiên bản KakaoTalk cho Linux thì đúng là... khá tệ.. Trong khi đó bản cho Mac thì lại làm ra rất nhanh..Dù trước giờ cũng biết sơ sơ, nhưng được giải thích chi tiết về Wine như thế này thấy thú vị thật .. haha
Nói chung, vì Wine chạy khá tốt các chương trình Windows, nên liệu có thể hình dung việc dùng Wine để tạo ứng dụng đa nền tảng không? (chỉ giới hạn ở desktop)
Tôi nhớ là ngày xưa rất lâu rồi, HWP của Hancom cũng từng được port sang Linux dựa trên Wine và phát hành. (R4 thì có một lớp thư viện tương thích win32 riêng, còn bản dùng Wine là R5 hay 2002 thì tôi cũng nhớ không rõ nữa.)
Vì vậy, đã từng có thời người ta đùa rằng nhờ có Wine mà win32 là API đa nền tảng phổ biến và thành công nhất.
Nhưng giờ thì là thời đại của Electron/wasm;;
Hơi lạc đề một chút, nhưng nếu bạn định làm như vậy -- vì giấy phép của Wine là LGPL, nên tùy vào cách bạn viết mã, bạn có thể phải công khai một phần hoặc toàn bộ mã nguồn.
Như bài gốc cũng giải thích, lý do Wine không phải là trình giả lập là vì nó sử dụng trực tiếp các lệnh CPU. Điều đó có nghĩa là, về cơ bản, phần mềm có thể chạy bằng Wine là phần mềm dành cho Windows hoạt động trên CPU x86 hoặc x86-64.
Ở thời điểm hiện tại, khi Apple đã chuyển toàn bộ Mac sang kiến trúc ARM, hơn nữa Microsoft cũng đang tung ra bộ công cụ phát triển dựa trên ARM, thì có lẽ hơi gượng ép nếu gọi phần mềm chỉ chạy trên CPU nền tảng x86(-64) là “hỗ trợ đa nền tảng”.
Vâng. Đúng như bạn nói... có lẽ tôi đã vô thức tự giới hạn nó vào các máy thuộc dòng x86.
Vì đã có electron hoặc tauri nên nếu phải làm đa nền tảng ngay từ đầu thì có vẻ đây không phải là lựa chọn tốt.
Nếu có những ràng buộc đặc biệt khiến không thể dùng công nghệ dựa trên trình duyệt web
thì có lẽ dùng thư viện như Qt, vốn hỗ trợ cross-compiling tốt, sẽ phù hợp hơn..
222