January 17, 2005

LD_PRELOAD 的應用

Linux Kernel Hackers 之一的 Greg Kroah-Hartman 曾經在 LinuxJournal 上寫過一篇名為 [Modifying a Dynamic Library Without Changing the Source Code] 的文章,簡單扼要的解釋 LD_PRELOAD 環境變數的使用,並且提供一個實用的範例,我剛剛將該文翻譯成繁體中文,請見 [在不更動原始程式碼的前提下,修改動態程式庫]。 除了這個範例外,我之前在對 Access 公司出品的 NetFront 瀏覽器增加繁體中文支援時,發現 NetFront v3.1 Linux SDK 是用 GTK+ 1.2 打造的,而字型資訊是寫死在程式碼中,Access 也未放出原始程式碼,於是我透過 LD_PRELOAD 的機制,動態調整中文字形的處理,如此一來,NetFrontGTK 就能顯示繁體中文 (使用台北字形),並且,參考原本的訊息檔稍做繁體中文翻譯,執行的快照可以參考: 至於這個改過的 tarball 可以在此下載 接下來,我就提及修改的細節。NetFrontGTK 之所以無法顯示中文的原因是,當呼叫 gdk_fontset_load() 時,只載入了日文字型,所以只能顯示日文網頁。所以,如果能攔截 gdk_fontset_load() 的進入點,動態加入中文字型名稱,不就迎刃而解了?以前 XCIN 架構還不是很完備前,有個 XA (Xcin Anywhere) 的輔助程式,他的動作正是攔截特定的 X 呼叫,強迫採用 XA 內部可與 XCIN 溝通的動作。於是,我搬出 XA 的程式碼作為參考,主體的流程大致是:
/* Wrapped functions */

/*
 * PROTOTYPE:
 *   GdkFont* gdk_fontset_load   (const gchar    *fontset_name);
 * real_gdk_fontset_load 就是真正的 gdk_fontset_load() 進入點
 */
static GdkFont* (* real_gdk_fontset_load)(const gchar *fontset_name);

void load_all_syms(void *handle)
{
  real_gdk_fontset_load = dlsym(handle, "gdk_fontset_load" );
}

#define XA_LIBX11 "libgdk-1.2.so.0"
void wrap_init()
{
  static void *handle = dlopen(lib_path, RTLD_LAZY);
  load_all_syms(handle);
}

/*
 * 我們的 gdk_fontset_load() 實作
 * 看到包含 "jisx0208" 的字型名稱,自動加入台北字型
 */
GdkFont* gdk_fontset_load(const gchar *fontset_name)
{
  gchar new_fontset_name[BUF_SIZE];
  wrap_init();
  if (strstr(fontset_name, "jisx0208") != 0) {
    sprintf(new_fontset_name,
            "-taipei-ming-medium-r-normal-*-*-160-*-*-c-*-big5-0,"
            "%s", fontset_name);
    return real_gdk_fontset_load(new_fontset_name);
  }
  return real_gdk_fontset_load(fontset_name);
}
Happy Hacking! 由 jserv 發表於 January 17, 2005 07:06 PM
迴響

我在tw.bbs.comp.linux也提過一個用到LD_PRELOAD的例子,標題是
[心得]用transconnect穿過防火牆

我還在同一家公司,不過我們現在不擋telnet了,所以沒在用了.
==
咦,突然想到我們好像有擋irc ^^;

PowerOp 發表於 January 19, 2005 01:18 AM