SlideShare una empresa de Scribd logo
1 de 51
Descargar para leer sin conexión
Android C Library:
 Bionic 成長計畫



Kito Cheng   ( 程皇嘉 )
Developer, 0xlab
                              kito@0xlab.org
                       April 14, 2012 / OSDC
Rights to copy
                                          © Copyright 2012 0xlab
                                               http://0xlab.org/
                                                contact@0xlab.org
 Attribution – ShareAlike 3.0
                                Corrections, suggestions, contributions
 You are free                              and translations are welcome!
to copy, distribute, display, and perform the work
to make derivative works                      Latest update: Mar 21, 2012
to make commercial use of the work
 Under the following conditions
      Attribution. You must give the original author credit.
      Share Alike. If you alter, transform, or build upon this work,
      you may distribute the resulting work only under a license
      identical to this one.
For any reuse or distribution, you must make clear to others the
license terms of this work.
Any of these conditions can be waived if you get permission from the
copyright holder.
 Your fair use and other rights are in no way affected by the above.
 License text: http://creativecommons.org/licenses/by-sa/3.0/legalcode
簡短自我介紹




 博班菸酒生 @   熱血工讀生 @
天大地大台科大     0xlab
簡短自我介紹
成長計畫 ?
成長計畫 !
可解讀 GNU-
        style
                  成長計畫 !
    hash 的帥氣墨鏡

具備 S/L 大法的
 時間魔法陣




  針對 JNI 量測效
       能         強化版 8-bit
    的機械錶         prelink map
可解讀 GNU-
    style
hash 的帥氣墨鏡
GNU-Style Hash



GNU-Style Hash 是啥 ?
GNU-Style Hash



GNU-Style Hash 是啥 ?


先來看看他是用在哪 !
程式啟動流程


執行檔讀入記憶體

                    libc/libm/
                    libdvm...    在更新符號的時候需要大量的符號查找操
載入相關動態函式庫




 更新符號位址
(Relocation)
               printf, sin, cos, ...



  開始執行 !
程式載入範例




libc          libfoo

              prog 使用到 libc 跟 libfoo 的東西
       prog
程式載入範例
strtoumax             foo
  statfs              bar
 wcsncmp              ogc
dlmallopt             orz
  printf              ...
    ...              ox1ab
 strtoul
 getutent
                             libc 及 libfoo 各自提供這堆符號 ( 函數 /


  libc             libfoo

                   prog 使用到 libc 跟 libfoo 的東西
            prog
程式載入範例
 strtoumax             foo
   statfs              bar
  wcsncmp              ogc
 dlmallopt             orz
   printf              ...
     ...              ox1ab
  strtoul
  getutent
                              libc 及 libfoo 各自提供這堆符號 ( 函數 /


   libc             libfoo

                    prog 使用到 libc 跟 libfoo 的東西
             prog

假設 prog 只有使用到 printf, foo, bar 這 3 個函數
程式載入範例
 strtoumax            foo
   statfs             bar
  wcsncmp             ogc
 dlmallopt            orz
   printf             ...
     ...             ox1ab
  strtoul
  getutent




   libc             libfoo
                              只用到 3 個符號 ,
                             但在這個例子需要查找
                                5 次符號

             prog

假設 prog 只有使用到 printf, foo, bar 這 3 個函數
程式載入範例
 strtoumax            foo
   statfs             bar
  wcsncmp             ogc
 dlmallopt            orz
   printf             ...
     ...             ox1ab
  strtoul                     查找符號次數 : O(n*m)
  getutent                    n : 相依的函數庫數目
                                  m : 符號數



   libc             libfoo
                              只用到 3 個符號 ,
                             但在這個例子需要查找
                                5 次符號

             prog

假設 prog 只有使用到 printf, foo, bar 這 3 個函數
GNU-Style Hash


     GNU-Style Hash
則是可以加速這個查詢過程的方法之一 !
GNU-Style Hash


     GNU-Style Hash
則是可以加速這個查詢過程的方法之一 !



  原本 ELF 中就有採用 Hash
 來加速查找速度 , 但不盡理想
GNU-Style Hash
        elf 預設的 hash 方法

name    2sym collision #                3sym collision #   3+sym collision #
sysv            1749                           5
libiberty       42
dcache          37                                gnu-style hash 的方法
djb2            29
sdbm            39
djb3            31
rot             337                             39                     61
sax             34
fnv             40
oat             30


                  原本 ELF 中就有採用 Hash
                 來加速查找速度 , 但不盡理想

Experiment by Jakub Jelinek
http://cygwin.com/ml/libc-alpha/2006-06/msg00098.html
GNU-Style Hash


Bit array




                      v

      H = {x, y, z} = hash functions


   並且使用 bloom filter 來進一步加速整體查找流程 !
GNU-Style Hash


Bit array




                      v

      H = {x, y, z} = hash functions


   並且使用 bloom filter 來進一步加速整體查找流程 !



            號稱可以加速 50% 的載入時間 !
GNU-Style hash 背後的故事 ...
GNU-Style Hash
所以在 Android 使用則有些地方要注意 ...

 某些傢伙自帶 Dynamic Linker 所以不支援
  ex: Unity 3D, B2G...

 因此必須要採用向後相容方案 , 新舊的 hash table
  都要放 ,-Wl,--hash-style=both
  但 gold 有 bug, 所以最好用 bfd 的 linker...
     http://sourceware.org/bugzilla/show_bug.cgi?
      id=13597
強化版 8-bit
prelink map
No prelink in ICS




      Android 太貪吃
     所以 prelink map 掉
            了
No prelink in ICS
      The speedup that it afforded in the early days of
        Android is now nullified by the speed of hardware,
        as well as by the presence of Zygote
      The space savings that come with prelinking are no
        longer important either.
      Prelinking reduces the effectiveness of Address-
        Space-Layout Randomization.
      Since it is not part of the gcc suite, the prelinker
        needs to be maintained separately.



                                                 官方說法
Git log from
https://github.com/android/platform_build/commit/b375e71d306f2fd356b9b356b636e568c4581fa1
No prelink in ICS
      硬體進步跟 Zygote 機制 , Prelink 加速跟沒有一樣

      只省一丁點空間 , 現在記憶體大又便宜

      Prelink 後 Address-Space-Layout
        Randomization 效果會變弱

      不是 GNU toolchain 的東西 ,
       要維護很麻煩
                                      官方說法 ( 白話版 )
Git log from
https://github.com/android/platform_build/commit/b375e71d306f2fd356b9b356b636e568c4581fa1
No prelink in ICS


但 prelink 對於開機時間還是有影響阿阿
No prelink in ICS


但 prelink 對於開機時間還是有影響阿阿




事實上 Prelink 在 ICS 可以撿回來用
程式啟動流程


執行檔讀入記憶體

                    libc/libm/
                    libdvm...    在更新符號的時候需要大量的符號查找操
載入相關動態函式庫




 更新符號位址
(Relocation)
               printf, sin, cos, ...



  開始執行 !
程式啟動流程
               Prelink 就是把這邊要找的東西統統都先作掉
                           一勞永逸

執行檔讀入記憶體

                     libc/libm/
                     libdvm...    在更新符號的時候需要大量的符號查找操
載入相關動態函式庫




 更新符號位址
(Relocation)
                printf, sin, cos, ...



  開始執行 !
int bar() {
  return 100;
}                                  做個實驗
int foo () {
  printf(“foo”);
  return bar();
}



    libc


   libfoo


            本實驗中假設已經有一個建好的且 prelink 過後的 libc.so
int bar() {
  return 100;
}                                          做個實驗
int foo () {
                    # arm-eabi-objdump libfoo.so -R
  printf(“foo”);
  return bar();     libfoo.so:    file format elf32-
}                   littlearm

                    DYNAMIC RELOCATION RECORDS
                    OFFSET   TYPE                VALUE
                    000010e8 R_ARM_JUMP_SLOT     printf
    libc            000010ec R_ARM_JUMP_SLOT     __cxa_finalize
                    00000424 R_ARM_RELATIVE      *ABS*
                    0000100c R_ARM_RELATIVE      *ABS*


   libfoo
    objdump -R 可檢視 Relocation Record, libfoo.so 共有四個 R
int bar() {
  return 100;
}                                         做個實驗
int foo () {
                   # arm-eabi-objdump libfoo.so -R
  printf(“foo”);
  return bar();    libfoo.so:    file format elf32-
}                  littlearm

                   DYNAMIC RELOCATION RECORDS
                   OFFSET   TYPE                VALUE
                   000010e8 R_ARM_JUMP_SLOT     printf
    libc           000010ec R_ARM_JUMP_SLOT     __cxa_finalize
                   00000424 R_ARM_RELATIVE      *ABS*
                   0000100c R_ARM_RELATIVE      *ABS*


   libfoo           一個 *ABS* 是 bar 的位址
                    另一個是系統用的
int bar() {
  return 100;
}                                               做個實驗
int foo () {
                       # apriori --locals-only 
  printf(“foo”);       --prelinkmap prelink-linux-arm.map 
  return bar();        libfoo.so --output prelinked/libfoo.so
}



    libc


                   接著對 libfoo.so 進行 prelink
   libfoo          apriori 在 out/host/linux-x86/bin/
                   prelink map 在 build/core
                   --locals-only(-l) 指定進行 local prelink
int bar() {
  return 100;
}                                               做個實驗
int foo () {
                       # apriori --locals-only 
  printf(“foo”);       --prelinkmap prelink-linux-arm.map 
  return bar();        libfoo.so --output prelinked/libfoo.so
}


                      build/tools/apriori/prelinkmap.c(183):
    libc              library 'libfoo.so' not in prelink map



                   出現錯誤 , 抱怨在 prelink map 找不到 libfoo..
   libfoo
Prelink Map
# core system libraries
libdl.so                  0xAFF00000 # [<64K]
libc.so                   0xAFD00000 # [~2M]
libstdc++.so              0xAFC00000 # [<64K]
libm.so                   0xAFB00000 # [~1M]
liblog.so                 0xAFA00000 # [<64K]
libcutils.so                       預先分配每個動態函式庫的基底位址 (Base
                          0xAF900000 # [~1M]
libthread_db.so           0xAF800000 # [<64K]
libz.so                   0xAF700000 # [~1M] 的函式庫都要加進來
                                   要 Prelink
libevent.so               0xAF600000 # [???]
libssl.so                 0xAF400000 # [~2M]
libcrypto.so              0xAF000000 # [~4M]
libsysutils.so            0xAEF00000 # [~1M]

# bluetooth
liba2dp.so                0xAEE00000 # [~1M]
audio.so                  0xAED00000 # [~1M]
input.so                  0xAEC00000 # [~1M]
…
liblept.so                0x9CA00000 # [~5M]
Prelink Map
# core system libraries
libdl.so                  0xAFF00000 # [<64K]
libc.so                   0xAFD00000 # [~2M]
libstdc++.so              0xAFC00000 # [<64K]
libm.so                   0xAFB00000 # [~1M]
liblog.so                 0xAFA00000 # [<64K]
libcutils.so                       預先分配每個動態函式庫的基底位址 (Base
                          0xAF900000 # [~1M]
libthread_db.so           0xAF800000 # [<64K]
libz.so                   0xAF700000 # [~1M] 的函式庫都要加進來
                                   要 Prelink
libevent.so               0xAF600000 # [???]
libssl.so                 0xAF400000 # [~2M]
libcrypto.so              0xAF000000 # [~4M]
libsysutils.so            0xAEF00000 # [~1M]

# bluetooth                                    把 libfoo 加進來
liba2dp.so                0xAEE00000 # [~1M]
audio.so                  0xAED00000 # [~1M]
input.so                  0xAEC00000 # [~1M]
…
liblept.so                0x9CA00000 # [~5M]
libfoo                    0x9C900000
int bar() {
  return 100;
}                                              做個實驗
int foo () {
                      # apriori --locals-only 
  printf(“foo”);      --prelinkmap prelink-linux-arm.map 
  return bar();       libfoo.so --output prelinked/libfoo.so
}



    libc


                   加入 Prelink Map 後就可以順利進行 Prelink 了
   libfoo
int bar() {
  return 100;
}                                              做個實驗
int foo () {
                      # arm-eabi-objdump prelinked/libfoo.so -R
  printf(“foo”);
  return bar();       libfoo.so:    file format elf32-littlearm
}
                      DYNAMIC RELOCATION RECORDS
                      OFFSET   TYPE              VALUE
                      000010e8 R_ARM_JUMP_SLOT   printf
                      000010ec R_ARM_JUMP_SLOT   __cxa_finalize
    libc


                   可以發現只剩下兩個 Relocation 了 !
   libfoo
int bar() {
    return 100;
  }                                            做個實驗
  int foo () {
                      # arm-eabi-objdump prelinked/libfoo.so -R
    printf(“foo”);
    return bar();     libfoo.so:    file format elf32-littlearm
  }
                      DYNAMIC RELOCATION RECORDS
                      OFFSET   TYPE              VALUE
                      000010e8 R_ARM_JUMP_SLOT   printf
                      000010ec R_ARM_JUMP_SLOT   __cxa_finalize
       libc


oo.so 的 Base Address 在 prelink map 中固定 , 而事實上處理 Relocatio
      libfoo
int bar() {
  return 100;
}                                              做個實驗
int foo () {
                      # apriori --locals-only 
  printf(“foo”);      --prelinkmap prelink-linux-arm.map 
  return bar();       libfoo.so --output prelinked/libfoo.so
}



    libc
                   回顧剛才的參數有個— locals-only,
                   通常有 local 就有相對的 global

   libfoo
int bar() {
  return 100;
}                                              做個實驗
int foo () {
                      # apriori 
  printf(“foo”);      --prelinkmap prelink-linux-arm.map 
  return bar();       libfoo.so --output prelinked/libfoo.so
}
                     build/tools/apriori/main.c(195): There
                     are command-line-option errors.

    libc
                   但直接拔掉該參數會跟你抱怨參數錯誤 ...


   libfoo
int bar() {
  return 100;
}                                           做個實驗
int foo () {
                   # apriori 
  printf(“foo”);   --prelinkmap prelink-linux-arm.map 
  return bar();    libfoo.so --output prelinked/libfoo.so
}
                   build/tools/apriori/main.c(195): There
                   are command-line-option errors.

    libc
      不明原因在 apriori 的 global prelink 的部份程式沒有完成 , 但


   libfoo
int bar() {
  return 100;
}                                               做個實驗
int foo () {
                       # apriori 
  printf(“foo”);       --prelinkmap prelink-linux-arm.map 
  return bar();        libfoo.so --output prelinked/libfoo.so
}



    libc
                   所以接下來的實驗請記得先去 0xdroid 撿 patch

                   散落在下面三個地方 :
   libfoo          build/
                   external/elfutils/
                   external/elfcopy/
int bar() {
  return 100;
}                                               做個實驗
int foo () {
                       # apriori --inc-global-prelink 
  printf(“foo”);       --prelinkmap prelink-linux-arm.map 
  return bar();        -L /system/lib 
}                      libfoo.so --output prelinked/libfoo.so



    libc
                   patch 打上後把參數加上
                   --inc-global-prelink
                   -L < 其他函數庫的路徑 >
   libfoo          就會開始進行 Incremental Global Prelink!
int bar() {
    return 100;
  }                                              做個實驗
  int foo () {
                        # apriori --inc-global-prelink 
    printf(“foo”);      --prelinkmap prelink-linux-arm.map 
    return bar();       -L /system/lib 
  }                     libfoo.so --output prelinked/libfoo.so

                        # arm-eabi-objdump prelinked/libfoo.so -R

      libc              libfoo.so:    file format elf32-littlearm

                        DYNAMIC RELOCATION RECORDS (none)



         Incremental
     libfoo            Global Prelink 完後就沒有任何 Relocation 要處




Local Prelink 再去處理 Global Prelink 的漸進方式 , 故命名之 , 因此輸
int bar() {
    return 100;
  }                                           做個實驗
  int foo () {
                     # apriori --inc-global-prelink 
    printf(“foo”);   --prelinkmap prelink-linux-arm.map 
    return bar();    -L /system/lib 
  }                  libfoo.so --output prelinked/libfoo.so

                     # arm-eabi-objdump prelinked/libfoo.so -R

      libc           libfoo.so:    file format elf32-littlearm

                     DYNAMIC RELOCATION RECORDS (none)



nk 的過程中 , 會試著搜索外部的符號 , 如果找的到且該函式庫也 Prelink 過 ,
      libfoo
int bar() {
     return 100;
   }                                           做個實驗
   int foo () {
                      # apriori --inc-global-prelink 
     printf(“foo”);   --prelinkmap prelink-linux-arm.map 
     return bar();    -L /system/lib 
   }                  libfoo.so --output prelinked/libfoo.so

                      # arm-eabi-objdump prelinked/libfoo.so -R

       libc           libfoo.so:    file format elf32-littlearm

                      DYNAMIC RELOCATION RECORDS (none)



nk 的過程中 , 會試著搜索外部的符號 , 如果找的到且該函式庫也 Prelink 過 ,
      libfoo


以發現 , 不在 Prelink Map 的函式庫事實上也是可以處理掉部份的 Relocation!
int bar() {
    return 100;
  }                                做個實驗
  int foo () {
    printf(“foo”);
    return bar();
  }



      libc


     libfoo


現在為了實驗目的將 libfoo 從 prelink map 中驅逐出境
並且加上 LOCAL_PRELINK_MODULE := false
來建置
int bar() {
  return 100;
}                                           做個實驗
int foo () {
                   # apriori --partial-global-prelink 
  printf(“foo”);   -L /system/lib 
  return bar();    libfoo.so --output prelinked/libfoo.so
}



    libc


  接著加上新的參數 --partial-global-prelink 來進行 Partial Glo
   libfoo

Más contenido relacionado

La actualidad más candente

Java7 fork join framework and closures
Java7 fork join framework and closuresJava7 fork join framework and closures
Java7 fork join framework and closureswang hongjiang
 
全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版Simen Li
 
Linux常用命令与工具简介
Linux常用命令与工具简介Linux常用命令与工具简介
Linux常用命令与工具简介weihe
 
如何設計電腦 -- 還有讓電腦變快的那些方法
如何設計電腦  -- 還有讓電腦變快的那些方法如何設計電腦  -- 還有讓電腦變快的那些方法
如何設計電腦 -- 還有讓電腦變快的那些方法鍾誠 陳鍾誠
 
系統程式 -- 第 12 章
系統程式 -- 第 12 章系統程式 -- 第 12 章
系統程式 -- 第 12 章鍾誠 陳鍾誠
 
嵌入式平台移植技巧概說
嵌入式平台移植技巧概說嵌入式平台移植技巧概說
嵌入式平台移植技巧概說Joseph Lu
 
Hcsm lect-20120913
Hcsm lect-20120913Hcsm lect-20120913
Hcsm lect-20120913lusecheng
 
用Cython封装c++代码为python模块的一点经验
用Cython封装c++代码为python模块的一点经验用Cython封装c++代码为python模块的一点经验
用Cython封装c++代码为python模块的一点经验Leo Zhou
 
在 golang 中透過組合語言實作 SIMD
在 golang 中透過組合語言實作 SIMD在 golang 中透過組合語言實作 SIMD
在 golang 中透過組合語言實作 SIMDYangHao Yuan
 
HITCON CTF 2014 BambooFox 解題心得分享
HITCON CTF 2014 BambooFox 解題心得分享HITCON CTF 2014 BambooFox 解題心得分享
HITCON CTF 2014 BambooFox 解題心得分享Chong-Kuan Chen
 
C++工程实践
C++工程实践C++工程实践
C++工程实践Shuo Chen
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月鍾誠 陳鍾誠
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出wang hongjiang
 
[Crypto Course] Block Cipher Mode
[Crypto Course] Block Cipher Mode[Crypto Course] Block Cipher Mode
[Crypto Course] Block Cipher ModeWEI CHIEH CHAO
 
igdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack FirmwareSimen Li
 

La actualidad más candente (20)

from Source to Binary: How GNU Toolchain Works
from Source to Binary: How GNU Toolchain Worksfrom Source to Binary: How GNU Toolchain Works
from Source to Binary: How GNU Toolchain Works
 
Java7 fork join framework and closures
Java7 fork join framework and closuresJava7 fork join framework and closures
Java7 fork join framework and closures
 
LLVM introduction
LLVM introductionLLVM introduction
LLVM introduction
 
全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版全端物聯網探索之旅 - 重點整理版
全端物聯網探索之旅 - 重點整理版
 
Linux常用命令与工具简介
Linux常用命令与工具简介Linux常用命令与工具简介
Linux常用命令与工具简介
 
如何設計電腦 -- 還有讓電腦變快的那些方法
如何設計電腦  -- 還有讓電腦變快的那些方法如何設計電腦  -- 還有讓電腦變快的那些方法
如何設計電腦 -- 還有讓電腦變快的那些方法
 
系統程式 -- 第 12 章
系統程式 -- 第 12 章系統程式 -- 第 12 章
系統程式 -- 第 12 章
 
嵌入式平台移植技巧概說
嵌入式平台移植技巧概說嵌入式平台移植技巧概說
嵌入式平台移植技巧概說
 
Ipaq with linux
Ipaq with linuxIpaq with linux
Ipaq with linux
 
Hcsm lect-20120913
Hcsm lect-20120913Hcsm lect-20120913
Hcsm lect-20120913
 
用Cython封装c++代码为python模块的一点经验
用Cython封装c++代码为python模块的一点经验用Cython封装c++代码为python模块的一点经验
用Cython封装c++代码为python模块的一点经验
 
在 golang 中透過組合語言實作 SIMD
在 golang 中透過組合語言實作 SIMD在 golang 中透過組合語言實作 SIMD
在 golang 中透過組合語言實作 SIMD
 
HITCON CTF 2014 BambooFox 解題心得分享
HITCON CTF 2014 BambooFox 解題心得分享HITCON CTF 2014 BambooFox 解題心得分享
HITCON CTF 2014 BambooFox 解題心得分享
 
C++工程实践
C++工程实践C++工程实践
C++工程实践
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月
 
HITCON GIRLS Malware Analysis
HITCON GIRLS Malware AnalysisHITCON GIRLS Malware Analysis
HITCON GIRLS Malware Analysis
 
Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出Shell,信号量以及java进程的退出
Shell,信号量以及java进程的退出
 
[Crypto Course] Block Cipher Mode
[Crypto Course] Block Cipher Mode[Crypto Course] Block Cipher Mode
[Crypto Course] Block Cipher Mode
 
igdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT introigdshare 110220: LuaJIT intro
igdshare 110220: LuaJIT intro
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
 

Similar a Android C Library: Bionic 成長計畫

COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺hydai
 
Phalcon the fastest php framework 阿土伯
Phalcon   the fastest php framework 阿土伯Phalcon   the fastest php framework 阿土伯
Phalcon the fastest php framework 阿土伯Hash Lin
 
Phalcon phpconftw2012
Phalcon phpconftw2012Phalcon phpconftw2012
Phalcon phpconftw2012Rack Lin
 
Simple tech-talk
Simple tech-talkSimple tech-talk
Simple tech-talkliltos
 
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure National Cheng Kung University
 
Python 入门
Python 入门Python 入门
Python 入门kuco945
 
Vim hacks
Vim hacksVim hacks
Vim hacksXuYj
 
Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿jiannrong
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用勇浩 赖
 
Php More
Php MorePhp More
Php Morehenbo
 
Linux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeLinux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeAngel Boy
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7javatwo2011
 
基于XMPP的Gtalk机器人
基于XMPP的Gtalk机器人基于XMPP的Gtalk机器人
基于XMPP的Gtalk机器人roamin9 Zhou
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemadKitor23
 
Learning python in the motion picture industry by will zhou
Learning python in the motion picture industry   by will zhouLearning python in the motion picture industry   by will zhou
Learning python in the motion picture industry by will zhouWill Zhou
 
Python学习笔记
Python学习笔记Python学习笔记
Python学习笔记Lingfei Kong
 
Golangintro
GolangintroGolangintro
Golangintro理 傅
 
用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式Stanley Ho
 

Similar a Android C Library: Bionic 成長計畫 (20)

COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺COSCUP2016 - LLVM框架、由淺入淺
COSCUP2016 - LLVM框架、由淺入淺
 
Phalcon the fastest php framework 阿土伯
Phalcon   the fastest php framework 阿土伯Phalcon   the fastest php framework 阿土伯
Phalcon the fastest php framework 阿土伯
 
Phalcon phpconftw2012
Phalcon phpconftw2012Phalcon phpconftw2012
Phalcon phpconftw2012
 
Simple tech-talk
Simple tech-talkSimple tech-talk
Simple tech-talk
 
Execution
ExecutionExecution
Execution
 
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure
Accelerating or Complicating PHP execution by LLVM Compiler Infrastructure
 
Python 入门
Python 入门Python 入门
Python 入门
 
Vim hacks
Vim hacksVim hacks
Vim hacks
 
Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿Python匯出入csv以及繪製圖表初稿
Python匯出入csv以及繪製圖表初稿
 
Python 于 webgame 的应用
Python 于 webgame 的应用Python 于 webgame 的应用
Python 于 webgame 的应用
 
Php More
Php MorePhp More
Php More
 
Linux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeLinux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledge
 
千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7千呼萬喚始出來的Java SE 7
千呼萬喚始出來的Java SE 7
 
基于XMPP的Gtalk机器人
基于XMPP的Gtalk机器人基于XMPP的Gtalk机器人
基于XMPP的Gtalk机器人
 
ajax_onlinemad
ajax_onlinemadajax_onlinemad
ajax_onlinemad
 
Learning python in the motion picture industry by will zhou
Learning python in the motion picture industry   by will zhouLearning python in the motion picture industry   by will zhou
Learning python in the motion picture industry by will zhou
 
Python学习笔记
Python学习笔记Python学习笔记
Python学习笔记
 
Rootkit 101
Rootkit 101Rootkit 101
Rootkit 101
 
Golangintro
GolangintroGolangintro
Golangintro
 
用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式用Raspberry PI學Linux驅動程式
用Raspberry PI學Linux驅動程式
 

Android C Library: Bionic 成長計畫

  • 1. Android C Library: Bionic 成長計畫 Kito Cheng ( 程皇嘉 ) Developer, 0xlab kito@0xlab.org April 14, 2012 / OSDC
  • 2. Rights to copy © Copyright 2012 0xlab http://0xlab.org/ contact@0xlab.org Attribution – ShareAlike 3.0 Corrections, suggestions, contributions You are free and translations are welcome! to copy, distribute, display, and perform the work to make derivative works Latest update: Mar 21, 2012 to make commercial use of the work Under the following conditions Attribution. You must give the original author credit. Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. For any reuse or distribution, you must make clear to others the license terms of this work. Any of these conditions can be waived if you get permission from the copyright holder. Your fair use and other rights are in no way affected by the above. License text: http://creativecommons.org/licenses/by-sa/3.0/legalcode
  • 3. 簡短自我介紹 博班菸酒生 @ 熱血工讀生 @ 天大地大台科大 0xlab
  • 7. 可解讀 GNU- style 成長計畫 ! hash 的帥氣墨鏡 具備 S/L 大法的 時間魔法陣 針對 JNI 量測效 能 強化版 8-bit 的機械錶 prelink map
  • 8. 可解讀 GNU- style hash 的帥氣墨鏡
  • 10. GNU-Style Hash GNU-Style Hash 是啥 ? 先來看看他是用在哪 !
  • 11. 程式啟動流程 執行檔讀入記憶體 libc/libm/ libdvm... 在更新符號的時候需要大量的符號查找操 載入相關動態函式庫 更新符號位址 (Relocation) printf, sin, cos, ... 開始執行 !
  • 12. 程式載入範例 libc libfoo prog 使用到 libc 跟 libfoo 的東西 prog
  • 13. 程式載入範例 strtoumax foo statfs bar wcsncmp ogc dlmallopt orz printf ... ... ox1ab strtoul getutent libc 及 libfoo 各自提供這堆符號 ( 函數 / libc libfoo prog 使用到 libc 跟 libfoo 的東西 prog
  • 14. 程式載入範例 strtoumax foo statfs bar wcsncmp ogc dlmallopt orz printf ... ... ox1ab strtoul getutent libc 及 libfoo 各自提供這堆符號 ( 函數 / libc libfoo prog 使用到 libc 跟 libfoo 的東西 prog 假設 prog 只有使用到 printf, foo, bar 這 3 個函數
  • 15. 程式載入範例 strtoumax foo statfs bar wcsncmp ogc dlmallopt orz printf ... ... ox1ab strtoul getutent libc libfoo 只用到 3 個符號 , 但在這個例子需要查找 5 次符號 prog 假設 prog 只有使用到 printf, foo, bar 這 3 個函數
  • 16. 程式載入範例 strtoumax foo statfs bar wcsncmp ogc dlmallopt orz printf ... ... ox1ab strtoul 查找符號次數 : O(n*m) getutent n : 相依的函數庫數目 m : 符號數 libc libfoo 只用到 3 個符號 , 但在這個例子需要查找 5 次符號 prog 假設 prog 只有使用到 printf, foo, bar 這 3 個函數
  • 17. GNU-Style Hash GNU-Style Hash 則是可以加速這個查詢過程的方法之一 !
  • 18. GNU-Style Hash GNU-Style Hash 則是可以加速這個查詢過程的方法之一 ! 原本 ELF 中就有採用 Hash 來加速查找速度 , 但不盡理想
  • 19. GNU-Style Hash elf 預設的 hash 方法 name 2sym collision # 3sym collision # 3+sym collision # sysv 1749 5 libiberty 42 dcache 37 gnu-style hash 的方法 djb2 29 sdbm 39 djb3 31 rot 337 39 61 sax 34 fnv 40 oat 30 原本 ELF 中就有採用 Hash 來加速查找速度 , 但不盡理想 Experiment by Jakub Jelinek http://cygwin.com/ml/libc-alpha/2006-06/msg00098.html
  • 20. GNU-Style Hash Bit array v H = {x, y, z} = hash functions 並且使用 bloom filter 來進一步加速整體查找流程 !
  • 21. GNU-Style Hash Bit array v H = {x, y, z} = hash functions 並且使用 bloom filter 來進一步加速整體查找流程 ! 號稱可以加速 50% 的載入時間 !
  • 23. GNU-Style Hash 所以在 Android 使用則有些地方要注意 ... 某些傢伙自帶 Dynamic Linker 所以不支援 ex: Unity 3D, B2G... 因此必須要採用向後相容方案 , 新舊的 hash table 都要放 ,-Wl,--hash-style=both 但 gold 有 bug, 所以最好用 bfd 的 linker... http://sourceware.org/bugzilla/show_bug.cgi? id=13597
  • 25. No prelink in ICS Android 太貪吃 所以 prelink map 掉 了
  • 26. No prelink in ICS The speedup that it afforded in the early days of Android is now nullified by the speed of hardware, as well as by the presence of Zygote The space savings that come with prelinking are no longer important either. Prelinking reduces the effectiveness of Address- Space-Layout Randomization. Since it is not part of the gcc suite, the prelinker needs to be maintained separately. 官方說法 Git log from https://github.com/android/platform_build/commit/b375e71d306f2fd356b9b356b636e568c4581fa1
  • 27. No prelink in ICS 硬體進步跟 Zygote 機制 , Prelink 加速跟沒有一樣 只省一丁點空間 , 現在記憶體大又便宜 Prelink 後 Address-Space-Layout Randomization 效果會變弱 不是 GNU toolchain 的東西 , 要維護很麻煩 官方說法 ( 白話版 ) Git log from https://github.com/android/platform_build/commit/b375e71d306f2fd356b9b356b636e568c4581fa1
  • 28. No prelink in ICS 但 prelink 對於開機時間還是有影響阿阿
  • 29. No prelink in ICS 但 prelink 對於開機時間還是有影響阿阿 事實上 Prelink 在 ICS 可以撿回來用
  • 30. 程式啟動流程 執行檔讀入記憶體 libc/libm/ libdvm... 在更新符號的時候需要大量的符號查找操 載入相關動態函式庫 更新符號位址 (Relocation) printf, sin, cos, ... 開始執行 !
  • 31. 程式啟動流程 Prelink 就是把這邊要找的東西統統都先作掉 一勞永逸 執行檔讀入記憶體 libc/libm/ libdvm... 在更新符號的時候需要大量的符號查找操 載入相關動態函式庫 更新符號位址 (Relocation) printf, sin, cos, ... 開始執行 !
  • 32. int bar() { return 100; } 做個實驗 int foo () { printf(“foo”); return bar(); } libc libfoo 本實驗中假設已經有一個建好的且 prelink 過後的 libc.so
  • 33. int bar() { return 100; } 做個實驗 int foo () { # arm-eabi-objdump libfoo.so -R printf(“foo”); return bar(); libfoo.so: file format elf32- } littlearm DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf libc 000010ec R_ARM_JUMP_SLOT __cxa_finalize 00000424 R_ARM_RELATIVE *ABS* 0000100c R_ARM_RELATIVE *ABS* libfoo objdump -R 可檢視 Relocation Record, libfoo.so 共有四個 R
  • 34. int bar() { return 100; } 做個實驗 int foo () { # arm-eabi-objdump libfoo.so -R printf(“foo”); return bar(); libfoo.so: file format elf32- } littlearm DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf libc 000010ec R_ARM_JUMP_SLOT __cxa_finalize 00000424 R_ARM_RELATIVE *ABS* 0000100c R_ARM_RELATIVE *ABS* libfoo 一個 *ABS* 是 bar 的位址 另一個是系統用的
  • 35. int bar() { return 100; } 做個實驗 int foo () { # apriori --locals-only printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } libc 接著對 libfoo.so 進行 prelink libfoo apriori 在 out/host/linux-x86/bin/ prelink map 在 build/core --locals-only(-l) 指定進行 local prelink
  • 36. int bar() { return 100; } 做個實驗 int foo () { # apriori --locals-only printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } build/tools/apriori/prelinkmap.c(183): libc library 'libfoo.so' not in prelink map 出現錯誤 , 抱怨在 prelink map 找不到 libfoo.. libfoo
  • 37. Prelink Map # core system libraries libdl.so 0xAFF00000 # [<64K] libc.so 0xAFD00000 # [~2M] libstdc++.so 0xAFC00000 # [<64K] libm.so 0xAFB00000 # [~1M] liblog.so 0xAFA00000 # [<64K] libcutils.so 預先分配每個動態函式庫的基底位址 (Base 0xAF900000 # [~1M] libthread_db.so 0xAF800000 # [<64K] libz.so 0xAF700000 # [~1M] 的函式庫都要加進來 要 Prelink libevent.so 0xAF600000 # [???] libssl.so 0xAF400000 # [~2M] libcrypto.so 0xAF000000 # [~4M] libsysutils.so 0xAEF00000 # [~1M] # bluetooth liba2dp.so 0xAEE00000 # [~1M] audio.so 0xAED00000 # [~1M] input.so 0xAEC00000 # [~1M] … liblept.so 0x9CA00000 # [~5M]
  • 38. Prelink Map # core system libraries libdl.so 0xAFF00000 # [<64K] libc.so 0xAFD00000 # [~2M] libstdc++.so 0xAFC00000 # [<64K] libm.so 0xAFB00000 # [~1M] liblog.so 0xAFA00000 # [<64K] libcutils.so 預先分配每個動態函式庫的基底位址 (Base 0xAF900000 # [~1M] libthread_db.so 0xAF800000 # [<64K] libz.so 0xAF700000 # [~1M] 的函式庫都要加進來 要 Prelink libevent.so 0xAF600000 # [???] libssl.so 0xAF400000 # [~2M] libcrypto.so 0xAF000000 # [~4M] libsysutils.so 0xAEF00000 # [~1M] # bluetooth 把 libfoo 加進來 liba2dp.so 0xAEE00000 # [~1M] audio.so 0xAED00000 # [~1M] input.so 0xAEC00000 # [~1M] … liblept.so 0x9CA00000 # [~5M] libfoo 0x9C900000
  • 39. int bar() { return 100; } 做個實驗 int foo () { # apriori --locals-only printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } libc 加入 Prelink Map 後就可以順利進行 Prelink 了 libfoo
  • 40. int bar() { return 100; } 做個實驗 int foo () { # arm-eabi-objdump prelinked/libfoo.so -R printf(“foo”); return bar(); libfoo.so: file format elf32-littlearm } DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf 000010ec R_ARM_JUMP_SLOT __cxa_finalize libc 可以發現只剩下兩個 Relocation 了 ! libfoo
  • 41. int bar() { return 100; } 做個實驗 int foo () { # arm-eabi-objdump prelinked/libfoo.so -R printf(“foo”); return bar(); libfoo.so: file format elf32-littlearm } DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 000010e8 R_ARM_JUMP_SLOT printf 000010ec R_ARM_JUMP_SLOT __cxa_finalize libc oo.so 的 Base Address 在 prelink map 中固定 , 而事實上處理 Relocatio libfoo
  • 42. int bar() { return 100; } 做個實驗 int foo () { # apriori --locals-only printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } libc 回顧剛才的參數有個— locals-only, 通常有 local 就有相對的 global libfoo
  • 43. int bar() { return 100; } 做個實驗 int foo () { # apriori printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } build/tools/apriori/main.c(195): There are command-line-option errors. libc 但直接拔掉該參數會跟你抱怨參數錯誤 ... libfoo
  • 44. int bar() { return 100; } 做個實驗 int foo () { # apriori printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } build/tools/apriori/main.c(195): There are command-line-option errors. libc 不明原因在 apriori 的 global prelink 的部份程式沒有完成 , 但 libfoo
  • 45. int bar() { return 100; } 做個實驗 int foo () { # apriori printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); libfoo.so --output prelinked/libfoo.so } libc 所以接下來的實驗請記得先去 0xdroid 撿 patch 散落在下面三個地方 : libfoo build/ external/elfutils/ external/elfcopy/
  • 46. int bar() { return 100; } 做個實驗 int foo () { # apriori --inc-global-prelink printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); -L /system/lib } libfoo.so --output prelinked/libfoo.so libc patch 打上後把參數加上 --inc-global-prelink -L < 其他函數庫的路徑 > libfoo 就會開始進行 Incremental Global Prelink!
  • 47. int bar() { return 100; } 做個實驗 int foo () { # apriori --inc-global-prelink printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); -L /system/lib } libfoo.so --output prelinked/libfoo.so # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS (none) Incremental libfoo Global Prelink 完後就沒有任何 Relocation 要處 Local Prelink 再去處理 Global Prelink 的漸進方式 , 故命名之 , 因此輸
  • 48. int bar() { return 100; } 做個實驗 int foo () { # apriori --inc-global-prelink printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); -L /system/lib } libfoo.so --output prelinked/libfoo.so # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS (none) nk 的過程中 , 會試著搜索外部的符號 , 如果找的到且該函式庫也 Prelink 過 , libfoo
  • 49. int bar() { return 100; } 做個實驗 int foo () { # apriori --inc-global-prelink printf(“foo”); --prelinkmap prelink-linux-arm.map return bar(); -L /system/lib } libfoo.so --output prelinked/libfoo.so # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS (none) nk 的過程中 , 會試著搜索外部的符號 , 如果找的到且該函式庫也 Prelink 過 , libfoo 以發現 , 不在 Prelink Map 的函式庫事實上也是可以處理掉部份的 Relocation!
  • 50. int bar() { return 100; } 做個實驗 int foo () { printf(“foo”); return bar(); } libc libfoo 現在為了實驗目的將 libfoo 從 prelink map 中驅逐出境 並且加上 LOCAL_PRELINK_MODULE := false 來建置
  • 51. int bar() { return 100; } 做個實驗 int foo () { # apriori --partial-global-prelink printf(“foo”); -L /system/lib return bar(); libfoo.so --output prelinked/libfoo.so } libc 接著加上新的參數 --partial-global-prelink 來進行 Partial Glo libfoo
  • 52. int bar() { return 100; } 做個實驗 int foo () { # apriori --partial-global-prelink printf(“foo”); -L /system/lib return bar(); libfoo.so --output prelinked/libfoo.so } # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS 00000424 R_ARM_RELATIVE *ABS* 0000100c R_ARM_RELATIVE *ABS* libfoo 來自 libc 符號的 Relocation 都 Prelink 掉了 !
  • 53. int bar() { return 100; } 做個實驗 int foo () { # apriori --partial-global-prelink printf(“foo”); -L /system/lib return bar(); libfoo.so --output prelinked/libfoo.so } # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS 00000424 R_ARM_RELATIVE *ABS* 0000100c R_ARM_RELATIVE *ABS* libfoo 進行 Prelink 後符號的位址都已經固定且已知 , 因此即使 libfoo 沒有分配 Base
  • 54. int bar() { return 100; } 做個實驗 int foo () { # apriori --partial-global-prelink printf(“foo”); -L /system/lib return bar(); libfoo.so --output prelinked/libfoo.so } # arm-eabi-objdump prelinked/libfoo.so -R libc libfoo.so: file format elf32-littlearm DYNAMIC RELOCATION RECORDS 00000424 R_ARM_RELATIVE *ABS* 0000100c R_ARM_RELATIVE *ABS* libfoo 進行 Prelink 後符號的位址都已經固定且已知 , 因此即使 libfoo 沒有分配 Base 這個機制命名為 Partial Global Prelink
  • 56. 針對 JNI 量測效 能 的機械錶
  • 57. Aprof : Android Profiler
  • 58. Aprof : Android Profiler 針對 JNI 部份客製化 類似於常見的 gprof 工具 Sample Based Instrumentation Based
  • 59. Aprof : Android Profiler
  • 60. Aprof : Android Profiler Sample Based 定期查看程式跑到哪 Instrumentation Based 每次函數被呼叫時會紀錄
  • 61. Aprof : Android Profiler % cumulative self self total time time time calls ms/call ms/call name 99.52 2170 2140 2178309 0 0 fib 0.00 2170 0 1 0 217 main 0.32 0 20 0 0 0 write 0.16 0 10 0 0 0 memcpy Call graph (explanation follows) ------------------------------------------------------------- Image : foo Cumulative time : 2170 ms Self time : 2140 ms Function % time cumulative self Count Call by fib 2170 2140 100.00 2170 0 1 main 100.00 2170 2140 2178308 fib main 2170 0 100.00 2170 0 1 __libc_init ------------------------------------------------------------- Image : foo Cumulative time : 2170 ms Self time : 30 ms write 0 20 memcpy 0 10
  • 62. Aprof : Android Profiler
  • 63. 具備 S/L 大法 的 時間魔法陣
  • 67. 現存的 Checkpoint 工具 CryoPID http://cryopid.berlios.de/ BLCR https://ftg.lbl.gov/projects/Checkpoint Restart/ DMTCP http://dmtcp.sourceforge.net/
  • 68. DMTCP 支援大部分 OS 功能 檔案 , 網路 , Shared Memory, SysV IPC... 純 user-space checkpoint 實作 架構良好易於擴充且開發活耀 ! C++-based
  • 70. DMTCP for Android 但 Android 上有許多特殊的機制 Logger, binder, ashmem, wakelock... 目前尚在進行中