---
# System prepended metadata

title: 執行古老的 QPE 執行檔

---

# 運作古老的 QPE 執行檔

## Qt Palmtop Environment

Qt 是由 Trolltech 公司（現為 Qt Group）開發的跨平台程式開發框架，其跨平台特性使得使用 Qt 撰寫的軟體，可在 Microsoft Windows, macOS, Linux，和 BSD 家族作業系統執行。Trolltech 也曾針對嵌入式環境推出 Qt/Embedded 產品，與桌面版本不同，Qt/Embedded 取代 X Server 和 X Library 等元件。Trolltech 公司推出針對 PDA 軟體的整體解決方案為 QPE (Qt Palmtop Environment)，從底層的圖形使用者介面、視窗管理器、軟體鍵盤到上層的個人資訊管理、檔案瀏覽器、多媒體等，全部一手包辦。

## 體驗古老的執行檔

SourceForge 網站保存 Trolltech 公司舊版的 [QPE](https://sourceforge.net/projects/qpe/) 檔案，其中 [QPE-1.3.1 ](https://sourceforge.net/projects/qpe/files/QPE/1.3.1/) 的執行檔距今超過 23 年，如今的軟硬體已有顯著差異，我們能否運作呢？以主流的 x86-64 架構來說，我們可在 Debian / Ubuntu 安裝以下套件：
```shell
$ sudo apt install lib32stdc++6
```

首先要確保 X 視窗系統正確運作，接著取得 `qpe-1.3.1-bin-x86.tar.gz`，本文假設在 `/tmp` 操作以下命令:
```shell
$ tar zxvf qpe-1.3.1-bin-x86.tar.gz 
$ cd qpe-1.3.1-bin-x86
```

上述目錄中，包含一個名為 `run_demo` 的腳本，執行後會發現欠缺 `libstdc++-libc6.1-2.so.3` 這個動態連結函式庫，該檔案距今已有 24 年的歷史，若貿然在 Google 茫茫大海搜尋，大概只會落得一場空。既然我們只想執行古老的 QPE 執行檔，不用理會程式的細部相容性議題。觀察稍早安裝的 `lib32stdc++6` 套件:
```shell
$ dpkg -L lib32stdc++6  
/usr/lib32/libstdc++.so.6.0.32
/usr/lib32/libstdc++.so.6
...
$ file /usr/lib32/libstdc++.so.6.0.32
/usr/lib32/libstdc++.so.6.0.32: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=f039e7071f444bdad22464673d49ba36ca7ffb36, stripped
```

`/usr/lib32/libstdc++.so.6.0.32` 是預先編譯、符合 i386 ABI 規範的 Linux 動態連結函式庫，提供 C++ 標準函式庫和執行時期所需的符號。我們嘗試用此取代 QPE-1.3.1 執行檔預期的 `libstdc++-libc6.1-2.so.3`:
```shell
$ ln -s /usr/lib32/libstdc++.so.6.0.32 lib/libstdc++-libc6.1-2.so.3
```

接著執行 `./run_demo`，很快會看到以下錯誤訊息：
```
./qpe: symbol lookup error: /tmp/qpe-1.3.1-bin-x86/lib/libqte.so.2: undefined symbol: __builtin_vec_new
```

這個 `__builtin_vec_new` 符號是早期 GCC 針對 C++ 程式提供的符號，現行的 GNU/Linux 已闕失。為此，我們可善用 `LD_PRELOAD` 機制，建立一個名為 `wrap.c` 的檔案，其內容如下：
```c
#include <malloc.h>

void *__builtin_new(int size)
{
    return malloc(size);
}

void *__builtin_vec_new(int size)
{
    return __builtin_new(size);
}

void __builtin_delete(void *ptr)
{
    free(ptr);
}

void __builtin_vec_delete(void *ptr)
{
    __builtin_delete(ptr);
}
```

編譯為 32 位元的動態連結函式庫:
```shell
gcc -m32 -o wrap.so -shared wrap.c
```

接著執行以下命令來啟動 QPE:
```shell
$ LD_PRELOAD=/tmp/qpe-1.3.1-bin-x86/wrap.so ./run_demo 
```

注意 `/tmp/qpe-1.3.1-bin-x86/wrap.so` 是上述編譯的動態連結函式庫所在的路徑。接著，終於啟動 QPE!
![QPE](https://hackmd.io/_uploads/SyzvOeltR.png =60%x)


