一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

Linux|Centos|Ubuntu|系統進程|Fedora|注冊表|Bios|Solaris|Windows7|Windows10|Windows11|windows server|

服務器之家 - 服務器系統 - Linux - Linux的ldconfig命令的代碼原理:ldconfig如何從指定目錄中查找動態庫文件信息?

Linux的ldconfig命令的代碼原理:ldconfig如何從指定目錄中查找動態庫文件信息?

2023-12-27 17:04未知服務器之家 Linux

ldconfig的代碼中,search_dir()函數的關鍵內容[1] 這部分關鍵代碼,負責查找指定目錄的動態庫文件,與系統已有的ld.so.cache的記錄對比,如果有變化或系統緩存記錄中不存在,則將當前動態庫的信息加入到緩存信息鏈表。 /* Add libra

Linux的ldconfig命令的代碼原理:ldconfig如何從指定目錄中查找動態庫文件信息?

ldconfig的代碼中,search_dir()函數的關鍵內容[1]

這部分關鍵代碼,負責查找指定目錄的動態庫文件,與系統已有的ld.so.cache的記錄對比,如果有變化或系統緩存記錄中不存在,則將當前動態庫的信息加入到緩存信息鏈表。

/* Add library to list.  將動態庫信息添加到鏈表*/
      struct dlib_entry *dlib_ptr;
      for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
 {
   /* Is soname already in list?  檢查SONAME記錄在鏈表中是否已存在,避免同一個庫重復添加多次*/
   if (strcmp (dlib_ptr->soname, soname) == 0)
     {
       /* Prefer a file to a link, otherwise check which one
   is newer.  
         SONAME的判定,以常規文件為優先來源,而不優先以鏈接文件作為SONAME的來源。
         */
       if ((!is_link && dlib_ptr->is_link)
    || (is_link == dlib_ptr->is_link
        && _dl_cache_libcmp (dlib_ptr->name, direntry->d_name) < 0))
  {
    /* It s newer - add it.  */
    /* Flag should be the same - sanity check.  */
    if (dlib_ptr->flag != flag)
      {
        if (dlib_ptr->flag == FLAG_ELF
     && (flag == FLAG_ELF_LIBC5 || flag == FLAG_ELF_LIBC6))
   dlib_ptr->flag = flag;
        else if ((dlib_ptr->flag == FLAG_ELF_LIBC5
    || dlib_ptr->flag == FLAG_ELF_LIBC6)
          && flag == FLAG_ELF)
   dlib_ptr->flag = flag;
        else
   error (0, 0, _("libraries %s and %s in directory %s have same soname but different type."),
          dlib_ptr->name, direntry->d_name,
          entry->path);
      }
    free (dlib_ptr->name);
    dlib_ptr->name = xstrdup (direntry->d_name);
    dlib_ptr->is_link = is_link;
    dlib_ptr->osversion = osversion;
    dlib_ptr->isa_level = isa_level;
  }
       /* Don t add this library, abort loop.  */
       /* Also free soname, since it s dynamically allocated.  */
       free (soname);
       break;
     }
 }
      /* Add the library if it s not already in.  
        如果該動態庫沒在緩存列表中,則添加到鏈表記錄中。
        這里看到,動態庫的信息分為name、SONAME、flag、是否為鏈接、os版本、isa_level這幾個方面
      */
      if (dlib_ptr == NULL)
 {
   dlib_ptr = (struct dlib_entry *)xmalloc (sizeof (struct dlib_entry));
   dlib_ptr->name = xstrdup (direntry->d_name);
   dlib_ptr->soname = soname;
   dlib_ptr->flag = flag;
   dlib_ptr->is_link = is_link;
   dlib_ptr->osversion = osversion;
   dlib_ptr->isa_level = isa_level;
   /* Add at head of list.  */
   dlib_ptr->next = dlibs;
   dlibs = dlib_ptr;
 }
    }

繼續處理,下面代碼仍然是 search_dir()函數的代碼,用于核對得到的緩存信息列表的文件,把那些指向軟鏈接的軟鏈接文件,判斷為多余的記錄(節點),給予剔除。

ldconfig的幫助文檔[2]說,/etc/ld.so.cache 文件的內容是有序列表,記錄了/etc/ld.so.conf配置文件(及/etc/ld.so.conf.d/*.conf 這些子配置文件)中指定的目錄,這些所有目錄下的動態庫文件的有效信息。除了這些目錄,還包含了 通過命令行指定的目錄、以及系統必要的目錄 /lib、 /lib64 中的動態庫文件信息。

/* Now dlibs contains a list of all libs - add those to the cache
     and created all symbolic links.  
     dlibs 包含了指定目錄下查找到的所有動態庫信息。將用于添加到緩存,并創建軟鏈接(SONAME 文件)。
     */
  struct dlib_entry *dlib_ptr;
  for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)
    {
      /* The cached file name is the soname for non-glibc-hwcaps
  subdirectories (relying on symbolic links; this helps with
  library updates that change the file name), and the actual
  file for glibc-hwcaps subdirectories.  
     /etc/ld.so.cache 文件的
     */
      const char *filename;
      if (entry->hwcaps == NULL)
 {
   /* Don t create links to links.  
      不創建指向鏈接文件的鏈接。
      */
   if (dlib_ptr->is_link == 0)
     create_links (dir_name, entry->path, dlib_ptr->name,
     dlib_ptr->soname);
   filename = dlib_ptr->soname;
 }
      else
 {
   /* Do not create links in glibc-hwcaps subdirectories, but
      still log the cache addition.  
         glibc 的 hwcaps 是2.33 版本開始引入的功能,
         支持hwcaps意味著除了常規編譯的庫之外,現在還可以使用來自最新 CPU 
         的擴展 cpu 指令集來安裝庫,glibc 將自動選擇針對當前使用的
         cpu 優化的版本。ldconfig對于glibc-hwcaps子目錄下的動態庫,
         不會創建對應的SONAME,但仍會記錄記錄到/etc/ld.so.cache文件內。
         以被Linux在運行時按需使用。
         */
   if (opt_verbose)
     printf ("\t%s -> %s\n", dlib_ptr->soname, dlib_ptr->name);
   filename = dlib_ptr->name;
 }
      if (opt_build_cache)
 add_to_cache (entry->path, filename, dlib_ptr->soname,
        dlib_ptr->flag, dlib_ptr->osversion,
        dlib_ptr->isa_level, hwcap, entry->hwcaps);
    }

從上面代碼出現的hwcaps相關的處理,在此補充一下關于glibc-hwcaps的作用說明 Hackweek 20: glibc-hwcaps in openSUSE[3];glibc-hwcaps 與AMD CPU的性能優化的關系[4],指出glibc-hwcaps 是基礎設施的開始,以便能夠更容易地根據硬件功能交付優化的庫/共享對象。這是在庫級別,用于提供插入式優化庫,而不是 GCC 的 FMV(函數多版本控制)之類的庫,后者在構建時試圖提供優化的函數,然后在運行時根據 CPU 主機進行選擇。

以上代碼最后看到的 add_to_cache(……),的用法是這樣的:

add_to_cache (entry->path, filename, dlib_ptr->soname,
        dlib_ptr->flag, dlib_ptr->osversion,
        dlib_ptr->isa_level, hwcap, entry->hwcaps);

從名稱上看,就是把 找到的一個動態庫的記錄,添加到緩存數據結構(鏈表)中。這個是在for (dlib_ptr = dlibs; dlib_ptr != NULL; dlib_ptr = dlib_ptr->next)的for 每次循環過程的最后執行的,也就是把有效的動態庫信息添加到鏈表。

從上層看,概要的,ldconfig 生成緩存文件,有這樣的大體流程:

main() {……
    search_dirs (void)//獲取所有待查找的目錄列表
    {
      struct dir_entry *entry;
      for (entry = dir_entries; entry != NULL; entry = entry->next)
        search_dir (entry); // 進入每個目錄,查找動態庫,并記錄到鏈表中
      } 
    }
     if (opt_build_cache)//若命令行參數要求生成緩存文件
    {
      save_cache (cache_file); //保存最終的緩存結果數據到 指定的緩存文件
                               //不指定文件路徑則默認是/etc/ld.so.cache 文件。
      if (aux_cache_file)// aux_cache_file是輔助緩存文件。
     save_aux_cache (aux_cache_file);
      }
}

看一看這個流程,就對ldconfig如何將最新從/etc/ld.so.conf文件讀取的動態庫目錄下的所有動態庫的緩存信息,生成為/etc/ld.so.cache緩存文件,有了整體的認識。

看完這些代碼,說幾點印象:

  • 這些代碼考慮到很多方面,不是一次成型的,通過git提交記錄,以及changelog文件,我們看到Linux動態庫的版本格式從glib4/5/6 有發展演化。
  • glibc 的ldconfig的代碼是C語言實現的,其生成的/etc/ld.so.cache緩存文件,對于Linux下的依賴動態庫的可執行文件的正常運行,關系重大。所以為了優化,和確保軟件更新后的穩定性,會有一套命名標準。比如SONAME的命名機制。對軟鏈接是否有效的判斷,以及對新動態庫的軟鏈接信息的更新。所以總體流程還是比較繁雜的。要考慮到的細節比較多。從git commit歷史看,代碼維護者的名稱大部分是國外開發者。
  • ldconfig 的C語言風格有編碼排版約定,可讀性尚可。也做了模塊拆分(如 ldconfig的功能,劃分到了多個文件,如入口文件 ldconfig.c 、緩存的讀寫邏輯實現文件 cache.c 、SONAME文件輔助功能文件readlib.c 、 chroot功能文件 chroot_canon.c )
  • ldconfig 的代碼存在的不足,也是很多C項目的問題,使用了很多全局變量,各個函數到處在直接操作全局變量。雖然功能上沒問題,高手寫的代碼也不會有運行異常,但總感覺可讀性和內聚程度降低了。如果是我來實現ldcnfig,我會在內聚性和代碼注釋方面做一些改進。減少全局靜態變量的使用;改成main()內部的變量,且通過main向被調用的函數傳參指針參數的方式傳入待讀寫的變量。以此提高可讀性。

Linux的ldconfig命令的代碼原理:ldconfig如何從指定目錄中查找動態庫文件信息?

  • 部分函數的單函數代碼行數過長,比如search_dir(),還可以再拆分成多個函數。也是為了可讀性能好一些。
  • 部分關鍵結構體的成員變量定義時,沒有注釋說明其作用。雖然通過看調用代碼能知道,但這樣的struct定義降低了可讀性。

總之,通過本系列文章對Linux 的ldconfig命令的源碼,從讀動態緩存文件、打印庫緩存信息、查找/etc/ld.so.conf 指定的目錄的動態庫信息等功能做了原理分析。希望對讀者理解ldconfig的原理些許幫助。

參考資料:

  • [1]ldconfig的代碼中,search_dir()函數的關鍵內容: http://www.ythuaji.com.cn/uploads/allimg/1hqbdtsviyj data-id="ld70c578-v7EavERA">[2]ldconfig的幫助文檔: https://www.man7.org/linux/man-pages/man8/ldconfig.8.html
  • [3]Hackweek 20: glibc-hwcaps in openSUSE: https://antlarr.io/tag/glibc-hwcaps/
  • [4]glibc-hwcaps 與AMD CPU的性能優化的關系: http://www.ythuaji.com.cn/uploads/allimg/btgishasx03

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 5278欧美一区二区三区 | 成人123| 国产精品久久国产三级国电话系列 | 91久操 | 精品午夜寂寞影院在线观看 | 91极品女神久色在线播放 | 免费a视频在线观看 | 91天堂素人 | 久久中文字幕综合不卡一二区 | 国产亚洲精aa在线观看香蕉 | 男人影院天堂网址 | 国产91精品区 | 国产青草亚洲香蕉精品久久 | 国产精品女同久久免费观看 | 国产精自产拍久久久久久 | 日本大乳护士的引诱图片 | 91麻豆精品国产自产在线 | a级精品九九九大片免费看 a级动漫 | 国人精品视频在线观看 | 国产精品视频一区二区三区不卡 | 美女福利网站 | 好大用力深一点女公交车 | 国产精品露脸国语对白手机视频 | 欧美裸妇 | 激情乱文| 欧美一区二区三区四区视频 | 欧美老女人b | 欧美日本一道高清二区三区 | 天天综合色天天综合 | 思久久 | bdsm中国精品调教 | 韩国理论三级在线观看视频 | 国内精品久久久久久野外 | 国产视频一区在线观看 | 俄罗斯12一15处交 | 精品一区二区三区视频 | 久久精品国产清白在天天线 | 四虎影视在线影院在线观看观看 | 香蕉在线精品亚洲第一区 | 国产精品区牛牛影院 | free性丰满hd性欧美人体 |