ãã®èšäºãæžãããã®ã€ã³ã¹ãã¬ãŒã·ã§ã³ã¯ãx86ã¢ãŒããã¯ãã£ã«é¢ããåæ§ã®åºçç©ãèªãã åŸã«åŸãããŸãã[1]ã
ãã®è³æã¯ãããã°ã©ã ãå
éšããã©ã®ããã«é
眮ãããŠããããã¡ã€ã³ã«å
¥ãåã«äœãèµ·ãã£ãŠããã®ãããªãããããã¹ãŠè¡ãããŠããã®ããçè§£ããã人ã«åœ¹ç«ã¡ãŸãã ãŸããglibcã©ã€ãã©ãªã®æ©èœã®ããã€ãã䜿çšããæ¹æ³ã瀺ããŸãã ãããŠæçµçã«ãå
ã®èšäº[1]ã®ããã«ãç§»åããçµè·¯ãèŠèŠçã«è¡šç€ºãããŸãã ã»ãšãã©ã®å Žåããã®èšäºã¯glibcã©ã€ãã©ãªã®è§£æã§ãã
ããã§ã¯ãæ
ãå§ããŸãããã Linux x86-64ãããã³lldbããããã°ããŒã«ãšããŠäœ¿çšããŸãã ãŸããæã
objdumpã䜿çšããŠããã°ã©ã ãéã¢ã»ã³ãã«ããŸãã
ãœãŒã¹ã³ãŒãã¯éåžžã®HelloãworldïŒ hello.cpp ïŒã§ãã
#include <iostream> int main() { std::cout << "Hello, world!" << std::endl; }
念ã®ãããã·ã¹ãã ãšããã°ã©ã ã«é¢ããæ
å ± * Clang -- 4.0.1 * lldb -- 4.0.1 * glibc -- 2.25 * `uname -r` -- 4.12.10-1-ARCH
ã³ãŒããã³ã³ãã€ã«ããŠãããã°ãéå§ããŸãã
clang++ -stdlib=libc++ hello1.cpp -g -o hello1.out lldb hello1.out
ãæ³šæããã°ã©ã ã§èæ
®ãããã³ãŒãã®ã»ãšãã©ã¯ãéžæãããã³ã³ãã€ã©ãšc ++ã©ã€ãã©ãªããã»ãšãã©ç¬ç«ããŠããŸãã ããŸããŸllvmã€ã³ãã©ã¹ãã©ã¯ãã£ãgccãããç§ã«å°ãè¿ã¥ããŠããã®ã§ãlibc ++ã©ã€ãã©ãªãåããclangã³ã³ãã€ã©ãæ€èšãããŸãããåé¡ã®ã³ãŒãã®ã»ãšãã©ãglibcã©ã€ãã©ãªããè§£æãããããã倧ããªéãã¯ãããŸããã
bash ïŒã ãã§ãªãïŒã䜿çšããå Žåã®ããã°ã©ã ã¯ã fork颿°ãåŒã³åºãã execveã䜿çšããŠã³ãã³ãã©ã€ã³åŒæ°ãæž¡ããŠæ°ããããã»ã¹ãäœæããããšã«ãã£ãŠçæãããŸãã ãŸããå®è¡å¯èœãã¡ã€ã«ã®æåã®åœä»€ã«å¶åŸ¡ãç§»ãåã«ãå
¥åããã³åºåèšè¿°åïŒSTDINãSTDOUTãSTDERRïŒãèšå®ãããŸãããã®åŸãåçãªã³ã¯ã®å Žåãããã°ã©ã ã«å¿
èŠãªã©ã€ãã©ãªãããŒãããã³åæåãããã. preinit_array ãã»ã¯ã·ã§ã³ã®é¢æ°ãåŒã³åºãããŸã ãã®ãã¹ãŠã®åŸãæåã®é¢æ°ãåŒã³åºãããŸããããã¯å®è¡å¯èœãã¡ã€ã«ïŒã .preinit_array ãã»ã¯ã·ã§ã³ãã«ãŠã³ãããªãïŒã«ãããåŸæ¥ã¯ããã°ã©ã ã®éå§ãšèŠãªããã_startãšåŒã°ããŸãã éçãªã³ã¯ã®å Žåãããšãã°ãã. preinit_array ãã»ã¯ã·ã§ã³ã®åæåãªã©ããªã³ã«ãŒã®äœæ¥ã¯å®è¡å¯èœãã¡ã€ã«å
ã«ããã颿°èªäœã¯åçã«ãªã³ã¯ãããããã°ã©ã ãšã¯å°ãç°ãªããŸãã åçã«ãªã³ã¯ãããããã°ã©ã ãæ€èšããŸãã
å®è¡å¯èœãã¡ã€ã«ã®ãšã³ããªãã€ã³ãã¯ãããããŒã«ç€ºãããŠããŸãã
readelf -h hello1.out | grep Entry
次ã«ã objdump -d hello1.out
ã䜿çšããŠããã®ã¢ãã¬ã¹ã«ãã颿°ã確èªããŸãã ããã¯æ¢ã«èª¬æãã_start颿°ã§ããããã¬ãŒã¯ãã€ã³ããèšå®ããŠãããã°ãéå§ããŸãã
b _start r
ABIã«ã€ããŠå°ããŠã£ãããã£ã¢ã®å®çŸ©ïŒ
ABIïŒã¢ããªã±ãŒã·ã§ã³ãã€ããªã€ã³ã¿ãŒãã§ã€ã¹ïŒ-äºææ§ã®ããABIãæèŒãããã·ã³éã§å®è¡å¯èœã³ãŒããç§»æ€ã§ããããã«èšèšãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ããã³ãã®ä»ã®äœã¬ãã«ãµãŒãã¹ã«ã¢ããªã±ãŒã·ã§ã³ã«ã¢ã¯ã»ã¹ããããã®äžé£ã®å¥çŽ ãœãŒã¹ã³ãŒãã¬ãã«ã§äºææ§ãèŠå¶ããAPIãšã¯ç°ãªããŸãã ABIã¯ããã€ããªã€ã³ã¿ãŒãã§ã€ã¹ãå®çŸ©ããªããããã¹ãŠã®ã³ãŒããåã³ã³ãã€ã«ããã«ãã³ã³ãã€ã«ãããã³ã³ããŒãã³ãã¢ãžã¥ãŒã«ããªã³ã«ãŒãçµåã§ããããã«ããäžé£ã®ã«ãŒã«ãšèããããšãã§ããŸãã
ABIã¬ãã«ã¯c / c ++ããã°ã©ããŒã«ã¯é ãããŠããããã®ã¬ãã«ã®ãã¹ãŠã®äœæ¥ã¯ã³ã³ãã€ã©ãŒãšæšæºlibcã©ã€ãã©ãªãŒã«ãã£ãŠå®è£
ãããŸãã ç§ã®å Žåã clangã³ã³ãã€ã©ãšglibcã©ã€ãã©ãªã¯ãã¹ãŠã®ABIã«ãŒã«ã«åŸããŸãã Linux x86-64ã®ABIã«ãŒã«ã¯ã System V AMD64 ABI [2]ã§æå®ãããŠããŸãã SolarisãLinuxãFreeBSDãOS Xã¯ããã®ããã¥ã¡ã³ãã®èŠåã«åŸããŸãã ãã€ã¯ããœããã«ã¯ç¬èªã®ABIãããããããã¯æ
éã«é ãããŠããŸãã ãã®ããã¥ã¡ã³ãã®æåã®ç« [2]ã§ã¯ããã®ã¢ãŒããã¯ãã£ã¯32ãããããã»ããµ[3]ã®ABIã«ãŒã«ã«ãæºæ ããŠãããšè¿°ã¹ãŠããŸãã ãããã£ãŠããããã¯glibcãªã©ã®äœã¬ãã«ã©ã€ãã©ãªã®éçºè
ãäŸåãã2ã€ã®åºæ¬çãªããã¥ã¡ã³ãã§ãã
ABIã«ãããšãããã°ã©ã ã®éå§æã«ã以äžãé€ããã¹ãŠã®ã¬ãžã¹ã¿ãå®çŸ©ãããŠããŸããã
- ïŒ
rdxïŒããã°ã©ã ãçµäºããåã«åŒã³åºãå¿
èŠããã颿°ãžã®ãã€ã³ã¿ãŒã
- ïŒ
rspïŒã¹ã¿ãã¯ã¯16ãã€ãå¢çã«æŽåãããåŒæ°ã®æ°ãåŒæ°èªäœãããã³ç°å¢ãå«ãŸããŸãã
0ïŒïŒ
rspïŒargc
8ïŒïŒ
rspïŒargv [0]
...
8 argcïŒïŒ
rspïŒNULL
8 ïŒargc + 1ïŒïŒïŒ
rspïŒenvp [0]
...
8 *ïŒargc + k + 1ïŒïŒïŒ
rspïŒenvp [k]
ãã«
è£å©ãã¯ãã«
...
ãã«
ãã«
è£å©ãã¯ãã«ïŒè£å©ãã¯ãã«ïŒã«ã¯ãçŸåšã®ãã·ã³ã«é¢ããæ
å ±ãå«ãŸããŠããŸãã LD_SHOW_AUXV=1 ./hello1.out
ã䜿çšããŠããããã®å€ã衚瀺ã§ããŸãã åŸãããå€ã¯ã[4]ã§ããªã詳ãã説æãããŠããŸãã
ãããŠå®éã«x `$rsp` -s8 -fu -c1
ããã°ã©ã åŒæ°ã®æ°
p *(char**)($rsp+8)
ã¯ããã°ã©ã ã®ååã§ãã ã¹ã¿ãã¯ã®æ¬¡ã¯ãããã°ã©ã åŒæ°ããŒãåºåãæåãç°å¢åŒæ°ãããã³è£å©ãã¯ãã«ã§ãã
ããã«ããã©ã°ã¬ãžã¹ã¿ãèšå®ãããSSEãšx87ãæ§æãããŸãïŒÂ§3.4.1[2]ïŒã
ã¡ã€ã³ãŠãŒã¶ãŒé¢æ°ã®åŒæ°ã®æºåãã»ãŒæŽã£ãŠããããšã«æ°ä»ããããããŸããããæ®ã£ãŠããã®ã¯æ£ãããã€ã³ã¿ãŒãèšå®ããããšã ãã§ãã ãã ãããã€ã³ã¿ãèšå®ãã以å€ã«ãã¡ã€ã³æé ãå
¥åããåã«ãŸã å€ãã®äœæ¥ãå¿
èŠã§ãã å°æ¥çã«ã¯ã説æå
ã®é¢æ°ã«ã¯ããœãŒã¹ã®å ŽæãšãããŒã«ãããã®åœ¢åŒã®ãã€ããªåœ¢åŒã®é¢æ°èªäœãä»éããŸããäŸïŒ main
_start颿°ãèŠãŠã¿ãŸããããããã¯å°ããããã®äž»ãªã¿ã¹ã¯ã¯__libc_start_main颿°ã«å¶åŸ¡ãç§»ãããšã§ãã
di
ã䜿çšããŠçŸåšã®é¢æ°ãéã¢ã»ã³ãã«ããŸãïŒæç¢ºã«ããããã«ãåºåã¯ãããšä»¥äžã§ãã©ãŒããããããŸãïŒã
_start: xor %ebp, %ebp mov %rdx, %r9 pop %rsi mov %rsp, %rdx and $-0x10, %rsp push %rax push %rsp lea 0x1aa(%rip), %r8 ; __libc_csu_fini lea 0x133(%rip), %rcx ; __libc_csu_init lea 0xec(%rip), %rdi ; main call *0x200796(%rip) ; __libc_start_main hlt
_start颿°ã¯ ããªã³ã«ãŒã«ãã£ãŠãªããžã§ã¯ããã¡ã€ã«Scrt1.oãšããŠããã°ã©ã ã«æ¥ç¶ãããŸãã åæ§ã®æ©èœãå®è¡ãããªããžã§ã¯ããã¡ã€ã«crt1ïŒgcrt1ãSrct1ãMcrt1ïŒã«ã¯ããã€ãã®çš®é¡ããããŸãããããŸããŸãªå Žåã«äœ¿çšãããŸãã ããšãã°ã Scrt1.o㯠PICã³ãŒãã®çæã«äœ¿çšãããŸã[5]ã ãªããžã§ã¯ããã¡ã€ã«ã®éžæã確èªããã«ã¯ã -v
ã¹ã€ããã䜿çšããŠããã°ã©ã ãã³ã³ãã€ã«ããŸãã ãããã®é¢æ°ã®ãªãã»ããã¯ãªã³ã¯æ®µéã§ã®ã¿èªèããããã ããªããžã§ã¯ããªãã»ãã__libc_csu_fini ã __libc_csu_initãããã³mainã¯ç€ºãããŠããªãããšã«æ³šæããŠãã ããã
ABIèŠä»¶ã«åŸã£ãŠã ãã¬ãŒã ãåæãã¬ãŒã ãšããŠããŒã¯ããã«ã¯ã ïŒ
ebpããŒãã«èšå®ããå¿
èŠããããŸããããã¯ã xorïŒ
ebpãïŒ
ebpãæ£ç¢ºã«è¡ãããšã§ãã
次ã¯ã __ libc_start_main颿°ãåŒã³åºãããã®æºåã§ãã ãã®é¢æ°ã®çœ²åã¯æ¬¡ã®åœ¢åŒã§ãã
int __libc_start_main(int (*main) (int, char **, char **), int argc, char **argv, __typeof (main) init, void (*fini) (void), void (*rtld_fini) (void), void *stack_end)
ABIã«ãããšã颿°ã®åŒæ°ã¯é©åãªå Žæã«é
眮ããå¿
èŠããããŸãã
åŒæ° | 颿°åŒã³åºãã®äœçœ® | 説æ |
---|
ã¡ã€ã³ | ïŒ
rdi | ããã°ã©ã ã®äž»ãªæ©èœ |
argc | ïŒ
rsi | ããã°ã©ã åŒæ°ã®æ° |
argv | ïŒ
rdx | åŒæ°ã®é
åã åŒæ°ãç°å¢å€æ°ã§ããããã®åŸãè£å©ãã¯ãã«ã§ããåŸ |
åæå | ïŒ
rcx | mainã®åã«åŒã³åºãããã°ããŒãã«ãªããžã§ã¯ãã³ã³ã¹ãã©ã¯ã¿ãŒã ãã®é¢æ°ã®ã¿ã€ãã¯ãã¡ã€ã³é¢æ°ãšåãã§ãã |
ãã£ã | ïŒ
r8 | ã¡ã€ã³ã®åŸã«åŒã³åºãããã°ããŒãã«ãªããžã§ã¯ããã¹ãã©ã¯ã¿ |
rtld_fini | ïŒ
r9 | åçãªã³ã«ãŒã®ãã¹ãã©ã¯ã¿ã åçã«å²ãåœãŠãããã©ã€ãã©ãªãè§£æŸããŸã |
stack_end | ïŒ
rsp | æŽåãããã¹ã¿ãã¯ã®çŸåšã®äœçœ® |
ABIã§ã¯ã颿°ãåŒã³åºããããšãã«ãã¹ã¿ãã¯ã16ãã€ãïŒåŒæ°ã®ã¿ã€ãã«å¿ããŠ32ãå Žåã«ãã£ãŠã¯64ïŒå¢çã«æŽåãããå¿
èŠããããŸãã èŠæ±ã¯ã and $ -0x10ãïŒ
rsp ïŒïŒïŒ åœä»€ã®å®è¡åŸã«æºããããŸãã ãã®ã¢ã©ã€ã¡ã³ãã®æå³ã¯ãSIMDåœä»€ïŒSSEãMMXïŒã¯ã¢ã©ã€ã¡ã³ããããããŒã¿ã§ã®ã¿åäœããã¹ã«ã©ãŒåœä»€ã¯ã¢ã©ã€ã¡ã³ããããããŒã¿ã§ããéãèªã¿æžããããããšã§ãã
16ãã€ãã®ã¢ã©ã€ã¡ã³ããä¿æããã«ã¯ã __libc_start_mainãåŒã³åºãåã«ãïŒ
raxã¬ãžã¹ã¿ãŒãã¹ã¿ãã¯ã«é
眮ãããæªå®çŸ©ã®å€ãæ ŒçŽãããŸãã ãã®ã¹ã¿ãã¯ã»ã«ã¯èªã¿åãããŸããã
ããã°ã©ã ã¯libc_start_main颿°ããè¿ãããã¹ãã§ã¯ãªããäžæ£ãªåäœã瀺ãããã«hltåœä»€ã䜿çšãããŸãã ãã®åœä»€ã®ç¹åŸŽã¯ãä¿è·ãããããã»ããµã¢ãŒãã§ã¯ä¿è·ãªã³ã°0ã§ã®ã¿å®è¡ã§ããããšã§ããã€ãŸãããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ã¿ããã®åœä»€ãåŒã³åºãããšãã§ããŸãã ãªã³ã°3ã«ãããŸããã€ãŸããããã°ã©ã ã«æš©éããªãã³ãã³ããå®è¡ããããšãããšãã»ã°ã¡ã³ããŒã·ã§ã³ãšã©ãŒãçºçããŸãã
hltåœä»€ã®åŸã«ã¯ã nopl 0x0åœä»€ïŒïŒ
raxãïŒ
raxã1ïŒããããŸã ãããã¯ã次ã®é¢æ°ã16ãã€ãå¢çã«æããããã«å¿
èŠã§ãã ABIã¯ãããå¿
èŠãšããŸããããã³ã³ãã€ã©ãŒã¯é¢æ°ã®å
é ãæããŠããã©ãŒãã³ã¹ãæ¹åããŸãïŒ 1ã2 ïŒã
ããã§ã¯å
ã«é²ã¿ãŸããã
b __libc_start_main c
__libc_start_main颿°ã®ãœãŒã¹ã³ãŒãã¯ãéçããã³åçã«ãªã³ã¯ãããã©ã€ãã©ãªã«å¯ŸããŠç°ãªãã³ãŒããçæãããããšã瀺ããŠããŸãã gdbãŸãã¯lldbã䜿çšããŠã libc.so.6ã©ã€ãã©ãªã§é¢æ°ã³ãŒããã©ã®ããã«èŠãããã確èªã§ããŸãã
lldb libc.so.6 -b -o 'di -n __libc_start_main'
__glibc_ [un]ã«ã€ããŠå°ãglibcã©ã€ãã©ãªã³ãŒãã«ã¯ã__ glibc_likelyããã³__glibc_unlikelyã®å€ãã®ãªã«ã¬ã³ã¹ãå«ãŸããŠããŸãã 倿°ã®æ¡ä»¶ä»ãæäœããã®ãã¯ãã«çœ®ãæããããŠããŸãã ãã¯ãã¯ãæçµçã«æ¬¡ã®çµã¿èŸŒã¿é¢æ°ã«å€æãããŸãã
# define __glibc_unlikely(cond) __builtin_expect ((cond), 0) # define __glibc_likely(cond) __builtin_expect ((cond), 1)
__builtin_expectã¯ãã³ã³ãã€ã©ãã¡ã¢ãªå
ã®ã³ãŒãã®ã»ã¯ã·ã§ã³ãæ£ããé
眮ããã®ã«åœ¹ç«ã€äžçš®ã®æé©åã§ãã ã©ã®ãã©ã³ããå®è¡ãããå¯èœæ§ãæãé«ãããã³ã³ãã€ã©ãŒã«éç¥ããã³ã³ãã€ã©ãŒã¯ãã®ã¡ã¢ãªãŒé åãæ¯èŒåœä»€ã®çŽåŸã«é
眮ããããšã§ãåœä»€ã®ãã£ãã·ã¥å¯èœæ§ãåäžãããã³ã³ãã€ã©ãŒã¯é¢æ°ã®æåŸã«æ®ãã®ãã©ã³ããããã°ãããé ããŸãã
__libc_start_main颿°ã¯å°ãé¢åã§ãäž»ãªã¢ã¯ã·ã§ã³ãç°¡åã«èª¬æããŸãã
- rtld_finiã__cxa_atexitã«ç»é²ããŸã
- __libc_csu_initãåŒã³åºã
- ãã£ã³ã»ã«ãã€ã³ããäœæ
- ã¡ã€ã³
- åºã
__cxa_atexit
__cxa_atexit颿°ã¯ãæåã®ã©ãããŒã®ã©ãããŒã§ããatexitãšã¯ç°ãªããç»é²æžã¿é¢æ°ã®ãã©ã¡ãŒã¿ãŒãåãããšãã§ããŸããããŠãŒã¶ãŒç©ºéããçŽæ¥åŒã³åºãããšã¯ã§ããŸããã 颿°ã¯DSOèå¥åã䜿çšãããããåŒã³åºããªãã§ãã ãããDSOèå¥åã¯ã³ã³ãã€ã©ã®ã¿ãç¥ã£ãŠããŸãã __cxa_atexitïŒfãpãdïŒãåŒã³åºããããšãDSO dãã¢ã³ããŒãããããšãã«fïŒpïŒé¢æ°ãåŒã³åºãããããã«ããå¿
èŠããããŸã[8]ã
ãã ããåŒæ°ããã©ã¡ãŒã¿ãŒé¢æ°ã«æž¡ã__cxa_atexitã®äœ¿çšäŸïŒ
#include <cstdio> extern "C" int __cxa_atexit (void (*func) (void *), void *arg, void *d); extern void* __dso_handle; void printArg(void *a) { int arg = *static_cast<int*>(a); printf("%d\n",arg); delete (int*)a; } int main() { int *k = new int(17); __cxa_atexit(printArg, k, __dso_handle); }
ãã®ããªãã¯ã¯ãçœå¿«æã®ããã«ã®ã¿äœ¿çšããããšããå§ãããŸãã ããã°ã©ã ãçµäºãããšãã«ãåæ§ã®æ¹æ³ã䜿çšããŠãã¹ãã©ã¯ã¿ãåŒã³åºãæ¹ãå®å
šã§ãã
rtld_finiã¯ããªã³ã«é¢æ°_dl_finiãžã®ãã€ã³ã¿ã§ã ã ã¯ãããªã³ã«ãŒã¯glibcã©ã€ãã©ãªã®äžéšã§ãã _dl_fini颿°ã¯ãããŒãããããã¹ãŠã®ã©ã€ãã©ãªãŒã®åæåãè§£é€ããŠã¢ã³ããŒãããŸãã
__libc_csu_init
åã®ãã®ãšåãæ¹æ³ã§__libc_csu_init颿°ã«ã¢ã¯ã»ã¹ã§ããŸãã __libc_csu_initã¯ã _initããã³.init_arrayã»ã¯ã·ã§ã³ã«ãã颿°ãã€ã³ã¿ãŒãåŒã³åºããŸãã
_init
_init颿°ã¯ããã¹ãŠ.initã»ã¯ã·ã§ã³ã«ãããŸãã ãã®ã³ãŒãã¯2ã€ã®éšåã«åãããŠããŸãïŒ çŽ¹ä»ãšãšãããŒã° ã æŠèŠã¯ãããããŒã°ãš__gmon_start__颿°ã®åŒã³åºãã®è©Šè¡ã§æ§æãããŸãã
_init subq $0x8, %rsp leaq 0x105(%rip), %rax ; __gmon_start__ testq %rax, %rax je 0x5555555548a2 ; je to addq instruction callq *%rax addq $0x8, %rsp retq
_init颿°ã®äž»ãªç®çã¯ã gprofãããã¡ã€ã©ãŒãåæåããããšã§ãã åœä»€ã leaq 0x105(%rip), %rax
ãã¯ã颿°__gmon_start__-ãããã¡ã€ã©ãŒãåæåãã颿°ã®ã¢ãã¬ã¹ãåããŸãã ãããã¡ã€ã©ãŒãååšããªãå ŽåãïŒ
raxã«ã¯å€0ãå«ãŸããé·ç§»jeã¯æ©èœããŸãã subq $ 0x8ãïŒ
rspããã³addq $ 0x8ãïŒ
rspåœä»€ã¯ãã¹ã¿ãã¯ãæŽåããå
ã®ç¶æ
ã«æ»ããŸãã ãã®ã¢ã©ã€ã¡ã³ããå¿
èŠãªã®ã¯ã颿°ãåŒã³åºããšãã«ãx86-64ã¢ãŒããã¯ãã£ã§ã®ãµã€ãºã8ãã€ãã®æ»ãã¢ãã¬ã¹ãã¹ã¿ãã¯ã«é
眮ããããã§ãã
ã³ãŒãã®ç¬èªã®ã»ã¯ã·ã§ã³ã.initã»ã¯ã·ã§ã³ã«è¿œå ã§ããŸãã hello2.cppã®äŸãèããŠã¿ãŸãããã
#include <cstdio> extern "C" void my_init() { puts("Hello from init"); } __asm__( ".section .init\n" "call my_init" ); int main(){}
_initãæ¬¡ã®ããã«ãªã£ãŠããããšãèæ
®ããŠãã ããã
subq $0x8, %rsp movq 0x200835(%rip), %rax testq %rax, %rax je 0x5555555547ba callq *%rax callq 0x555555554990 ; ::my_init() addq $0x8, %rsp retq
ãªã¹ãããcallq 0x555555554990
ããã«ã callq 0x555555554990
åœä»€callq 0x555555554990
ãšã³ããªãšé¢æ°ã®ãšãããŒã°ã®écallq 0x555555554990
远å ããã my_initãåŒã³åºãã ãã§ãã _init颿°ã¯ãããã°ã©ã ã®äžéšã®ç¬èªã®åæåãç°¡åã«è¿œå ã§ããããã«å®è£
ãããŠããããã§ãã
è峿·±ãäºå® ïŒæ°é
ãã®ããèªè
ã¯ãhello2.cppã®åºåãputs颿°ãä»ããŠåºåãããŠããããšã«æ°ä»ããŠããã¯ãã§ãã cout
ãä»ããŠåºåããå Žåã libstdc ++ã©ã€ãã©ãªã§ã³ã³ãã€ã«ãããšãã»ã°ã¡ã³ããŒã·ã§ã³ãšã©ãŒãçºçãã libc ++ã©ã€ãã©ãªã䜿çšãããšãã¡ãã»ãŒãžãæ£åžžã«è¡šç€ºãããŸãã ããã¯äœã®ããã«èµ·ãã£ãŠããã®ã§ããïŒ å®éã libstdc ++ã§ã¯ã cout
éåžžã®ã°ããŒãã«ãªããžã§ã¯ããšããŠåæåãããã°ããŒãã«ãªããžã§ã¯ãã¯å°ãåŸã«åæåãããŸãã libc ++ã®å Žåã ld-linux-x86-64.so.2ã©ã€ãã©ãªãã_dl_init颿°ã®ã©ã€ãã©ãªãããŒããããšãã«åæåãè¡ãããŸã ã ãã®é¢æ°ã¯ã _start颿°ã«å¶åŸ¡ãæž¡ãçŽåã«ã _dl_start_userããåŒã³åºãããŸãã
åæ¹æ³ã«ã¯é·æãšçæããããŸãã libc ++ã©ã€ãã©ãªãæ¥ç¶ãããŠããå Žåã cout
ãããªæšæºã®c ++åºåããŒã«cout
䜿çšããcout
ããªããŠããã³ã³ã¹ãã©ã¯ã¿ã¯ãšã«ããåŒã³åºãããŸãã libstdc ++ã©ã€ãã©ãªã®å Žåãæé©åãã©ã°ãæå¹ã«ããŠãã iostreamããããŒãã¡ã€ã«ãæ¥ç¶ãããŠããåæ°ã ãã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºãããŸãã åœç¶ãã³ã³ã¹ãã©ã¯ã¿ãŒã¯ãè€æ°ååŒã³åºãããšãã§ããååæåãã¹ãããããããšããäºå®ãèæ
®ããŸãã ãã¡ãããããã¯ããã°ã©ã ã®åæåãããã»ã©é
ãããŸããããããã§ãäžå¿«ã§ãã ãã®çç±ãããå€ãã®é«æ§èœãããžã§ã¯ãã¯ãiostreamããããŒãã¡ã€ã«ã®äœ¿çšã䜿çšãããæšå¥šãããããã«ã¯çŠæ¢ãããã®çµæãå
¥åºåçšã®ç¬èªã®ã€ã³ã¿ãŒãã§ã€ã¹ãäœæããŸãã
.init_array
次ã«ããã€ã³ã¿ãŒã.init_arrayã»ã¯ã·ã§ã³ã«ãã颿°ãåŒã³åºãããŸãã
ã»ã¯ã·ã§ã³ã®å
容ã確èªããŸãã
objdump hello1.out -s -j .init_array
ç§ã®å Žåã .init_arrayã®å
å®¹ã¯æ¬¡ã®æå³ãæã£ãŠããŸãïŒ a00f0000 00000000
ãããã¯ãªãã«ãšã³ãã£ã¢ã³ã®ãã€ãé ã® 64ãããã·ã¹ãã äžã®ã¢ãã¬ã¹0x0fa0ãæå³ããŸãã ãã®ã¢ãã¬ã¹ã«ã¯frame_dummy颿°ããããŸãã
frame_dummy
è峿·±ãããšã«ã frame_dummyã¯gccã©ã€ãã©ãªã®äžéšã§ãã
gccã¯ãããšäœã®é¢ä¿ããããŸããïŒ clangã³ã³ãã€ã©ããããŸãïŒgccãããžã§ã¯ãã¯éåžžã«å€§ããããã§ã«Linuxãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã«æ ¹ã匵ã£ãŠããããšãå¿ããªãã§ãã ããã gccãããžã§ã¯ãã«ã¯ãã³ã³ãã€ã©ã ãã§ãªããã³ã³ãã€ã«ã«å¿
èŠãªãã¡ã€ã«ãå«ãŸããŠããŸãã ãããã£ãŠããªã³ã¯ã¯crtbeginS.oãcrtendS.oãªã©ã®crtãã¡ã€ã«ã䜿çšããŸãã
ãããã£ãŠãgccãããžã§ã¯ããå®å
šã«åé€ããããšã¯ã§ããŸãããå°ãªããšããè£å©crtãã¡ã€ã«ãæ®ãå¿
èŠããããŸãã ã¡ã€ã³ã®ããã«gccã³ã³ãã€ã©ã䜿çšããªãUnixãªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã
frame_dummyã¯æ¬¡ã®ããã«ãªããŸãã
pushq %rbp movq %rsp, %rbp popq %rbp jmp 0x555555554cc0 ; register_tm_clones nopw (%rax,%rax)
frame_dummyã®ã¿ã¹ã¯ã¯ãåŒæ°ãèšå®ãã register_tm_clones颿°ãå®è¡ããããšã§ãã ãã®å±€ã¯ãåŒæ°ãå
¬éããããã«ã®ã¿å¿
èŠã§ãã ãã®å ŽåãåŒæ°ã¯èšå®ãããŠããŸãããããœãŒã¹ã³ãŒããããããããã«ãã¢ãŒããã¯ãã£ã«ãã£ãŠã¯åžžã«ãããšã¯éããŸããã è峿·±ãããšã«ãæåã®2ã€ã®æç€ºã¯ããããŒã°ã§ããã3çªç®ã®æç€ºã¯ãšãããŒã°ã§ãã jmpåœä»€ã¯ã颿°åŒã³åºãã®ããŒã«æé©åã§ãã ãããŠããã€ãã®ããã«ãã¢ã©ã€ã¡ã³ãã®æåŸã«ã
register_tm_clones颿°ã¯ã ãã©ã³ã¶ã¯ã·ã§ã³ ã¡ã¢ãªãã¢ã¯ãã£ãã«ããããã«å¿
èŠã§ãã
ã°ããŒãã«ãªããžã§ã¯ãã®åæå
ã°ããŒãã«ãªããžã§ã¯ããããå Žåãããã§åæåãããŸãã
ã°ããŒãã«ãªããžã§ã¯ããããå Žåã颿°ã¢ãã¬ã¹_GLOBAL__sub_I_< >
.init_arrayã»ã¯ã·ã§ã³ã«è¿œå _GLOBAL__sub_I_< >
ã
ã°ããŒãã«å€æ°ãåæåããäŸãèããŠã¿ãŸãããã
global1.cpp ïŒ
int k = printf("Hello from .init_array");
倿°ã¯æ¬¡ã®ããã«åæåãããŸãã
push %rbp mov %rsp, %rbp lea 0xf59(%rip), %rdi ; + 4 mov $0x0, %al call 0x555555554e80 ; symbol stub for: printf mov %eax, 0x202130(%rip) ; k pop %rbp ret
æåã®2ã€ã®æç€ºã¯ããããŒã°ã§ãã æ¬¡ã«ã %rdi
è¡ã«ãã€ã³ã¿ãŒã眮ãã %al
ããŒãã«èšå®ããŠã printf颿°ãåŒã³åºãæºåãããŸãã ABI [2]ã«ãããšãå¯å€æ°ã®åŒæ°ãæã€é¢æ°ã«ã¯ããã¯ãã«ã¬ãžã¹ã¿ãŒã«å«ãŸããå¯å€åŒæ°ã®æ°ãæå³ãã%al
ã«æ ŒçŽãããé ããã©ã¡ãŒã¿ãŒãå«ãŸããŠããŸãã ã»ãšãã©ã®å Žåãããã€ãã®é¢æ°ãæé©åããå¿
èŠããããŸããã printfã¯ãã¯ãã«ã¬ãžã¹ã¿ããã¹ã¿ãã¯ã«ããŒã¿ãç§»åããããã«ãã®æ
å ±ã䜿çšããŸãã
printfãåŒã³åºããåŸã颿°ã®çµæã倿°kã®ã¡ã¢ãªé åã«é
眮ããããšãããŒã°ãåŒã³åºãããŸãã
global2.cpp ïŒ
ããã©ã«ãã§ã¯ãªãã³ã³ã¹ãã©ã¯ã¿ãšãã¹ãã©ã¯ã¿ãæã€ç¹å®ã®ã¯ã©ã¹Global
ããããšããŸãããïŒ
Global g;
次ã«ãåæåã¯æ¬¡ã®ããã«ãªããŸãã
push %rbp mov %rsp, %rbp sub $0x10, %rsp lea 0x202175(%rip), %rdi ; g call 0x5555555550e0 ; Global::Global() lea 0x1c5(%rip), %rdi ; Global::~Global() lea 0x202162(%rip), %rsi ; g lea 0x202147(%rip), %rdx ; __dso_handle call 0x555555554f10 ; symbol stub for: __cxa_atexit mov %eax, -0x4(%rbp) add $0x10, %rsp pop %rbp ret
ããã§ã¯ãã°ããŒãã«ã³ã³ã¹ãã©ã¯ã¿ãŒãåŒã³åºããåŸããã¹ãã©ã¯ã¿ã__cxa_atexitã䜿çšããŠç»é²ãããæ¹æ³ã確èªããŸãã Itanium ABI [8]ã«åŸã£ãŠå®è£
ãããŠããŸãã
颿°åŒã³åºãã®åæå
glibcãããåæåã¯æ¬¡ã®ããã«åŒã³åºãããŸãïŒ (*__init_array_start [i]) (argc, argv, envp);
mainã«äŒŒããã©ã¡ãŒã¿ãŒãåæå颿°ã«æž¡ãããããã䜿çšã§ããããšã«æ³šæããŠãã ããã gccããã³clangã³ã³ãã€ã©ã«ã¯constructor
屿§ãããããªããžã§ã¯ãã®åæåã¹ãããã®åã«é¢æ°ãåŒã³åºãããŸãã
ãããã®åŒæ°ãããã«æž¡ãããšãã§ããŸãã æ¬¡ã®ã°ããŒãã«é¢æ°ã䜿çšããŠãããã°ã©ã ã®åºåã確èªããŸãã
void __attribute__((constructor)) hello(int argc, char **argv, char **env) { printf("#args = %d\n", argc); printf("filename = %s\n", argv[0]); }
ããã¯ãããå®çšçãªç®çã«äœ¿çšã§ããŸãïŒhello3.cppïŒïŒ
#include <cstdio> class C { public: C(int i) { printf("Program has %d argument(s)\n", i); } }; int constructorArg; const C c(constructorArg); void __attribute__((constructor (65535))) hello(int argc, char ** argv, char **env){ constructorArg = argc; } int main(){}
constructor
屿§ãã©ã¡ãŒã¿ãŒã¯ãåŒã³åºãã®åªå
é äœã瀺ããŸãã
ããããæ¢ã«æšæž¬ããããã«ãããã°ã©ã ã¯æ£ããæ°ã®åŒæ°ãåºåããŸããæãè峿·±ãããšã«ã c
ãªããžã§ã¯ãã¯å®æ°ã§ãã ãã®ã¢ãããŒãã®äž»ãªæ¬ ç¹ã¯ãæšæºã®ãµããŒãã®æ¬ åŠã§ãããçµæãšããŠãã¯ãã¹ãã©ãããã©ãŒã ã®æ¬ åŠã§ãã ãŸãããã®ãããªã³ãŒãã¯ã䜿çšãããlibcã©ã€ãã©ãªã«å€§ããäŸåããŠããŸãã
int x = 1 + 2 * 3;
ãšãã圢åŒã®ã°ããŒãã«å€æ°ã远å ããããšæãint x = 1 + 2 * 3;
ãŸã£ããåæåãããããããã®å€ã¯æåã«ã³ã³ãã€ã©ã«ãã£ãŠã¡ã¢ãªã«æžã蟌ãŸããŸãã int s = sum(4, 5)
ãªã©ã®åçŽãªé¢æ°ã«ãã£ãŠåæåããã倿°ãåæåããå Žåã¯ãC ++ 11æšæºã®èå¥åconstexprãsum
颿°ã«è¿œå ããŸãã
ãã£ã³ã»ã«ãã€ã³ããäœæ
ãã£ã³ã»ã«ãã€ã³ãã¯ã setjmpãåŒã³åºããŠã°ããŒãã«å€æ°ãèšå®ããããšã«ããäœæãããŸãã
ã¡ã€ã³ã¹ããªãŒã ããã£ã³ã»ã«ããããšãã«ã å
ã«æ»ãããšãã§ããããã«ãå
ã«æ»ããããã¡ãèšå®ããã«ã¯ã setjmpã³ã³ããã¹ããä¿åããå¿
èŠããããŸãã
ã¡ã€ã³ã¹ã¬ããããã£ã³ã»ã«ããäŸãã¡ã€ã«cancel.cpp
#include <pthread.h> pthread_t g_thr = pthread_self(); void * thread_start(void *) { pthread_cancel(g_thr); return 0; } int main() { pthread_t thr; pthread_create(&thr, NULL, thread_start, NULL); pthread_detach(thr); while (1) { pthread_testcancel(); } }
cancel.cpp , , , exit . , , , , .
, , setjmp :
br set -n __libc_start_main -R 162
: , â .
setjmp __GI__setjmp . , . [7]. , , PLT .
main
.
std::cout << "Hello, world!" << std::endl;
, :
operator<<(std::cout, "Hello, World!").operator<<(std::endl);
ãŸãã¯
operator<<(std::cout, "Hello, World!"); std::cout.operator<<(std::endl);
C++ <<
. , , , , . , .
endl
libc++, libstdc++ : ostream& endl(ostream&);
ostream
, <<
, visitor .
. IFUNC-, __strlen_avx2 _strlen_sse2 . strlen .
stdout _IO_file_doallocate malloc , 1 . , setvbuf .
stdout , . flush
, stdout
.
, flush
, fwrite , __libc_write , syscall ( , ):
ssize_t __libc_write (int fd, const void *buf, size_t nbytes) { return ({ unsigned long int resultvar = ({ unsigned long int resultvar; long int __arg3 = (long int) (nbytes); long int __arg2 = (long int) (buf); long int __arg1 = (long int) (fd); register long int _a3 asm ("rdx") = __arg3; register long int _a2 asm ("rsi") = __arg2; register long int _a1 asm ("rdi") = __arg1; asm volatile ( "syscall\n\t" : "=a" (resultvar) : "0" (1) , "r" (_a1), "r" (_a2), "r" (_a3) : "memory", "cc", "r11", "cx"); (long int) resultvar; }); resultvar; }); }
statement expressions , gcc:
int l = ({int b = 4; int c = 8; c += b});
, c += b
l == 12
.
__libc_write ( __GI___libc_write , _setjmp ) syscall , syscall , C . rax
. =a
, rax , "0" (1)
, rax
1 ( sys_write ).
, , sys_write , .
, ABI [2], . : %rdi, %rsi, %rdx, %r10, %r8, %r9.
x86 x86-64 !
, , - , , . PIC ( 1 , 2 ).
exit
exit :
- __call_tls_dtors â thread local storage , .
- , atexit
- _dl_fini â ,
_start
r9
, . - ( ).
- __libc_atexit
- _exit â .
_exit 231 ( sys_exit_group ), %rdi . .
Linux sys_exit . , , sys_exit_group . , , , sys_exit , [6].
, , "Hello, World!!!", C/C++, glibc . : , , setjmp, atexit...
, dot

[1] â http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html
[2] â https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r252.pdf
[3] â https://github.com/hjl-tools/x86-psABI/wiki/intel386-psABI-1.1.pdf
[4] â https://habrahabr.ru/post/128111/
[5] â https://dev.gentoo.org/~vapier/crt.txt
[6] â http://syprog.blogspot.ru/2012/03/linux-threads-through-magnifier-local.html
[7] â https://sourceware.org/glibc/wiki/Style_and_Conventions#Double-underscore_names_for_public_API_functions
[8] â https://itanium-cxx-abi.imtqy.com/cxx-abi/abi.html#dso-dtor