ããããããªã©ã§ ãã·ã¹ãã ã³ãŒã«ã«ã€ããŠå€ãã®ããšãèšãããŠããŸã ã ã·ã¹ãã ã³ãŒã«ã¯ãOSã®ã«ãŒãã«é¢æ°ãåŒã³åºãæ¹æ³ã§ããããšã¯æ¢ã«ãåãã§ãããã ããããx86-64ã¢ãŒããã¯ãã£ã®äŸã䜿çšããŠããã®ã·ã¹ãã ã³ãŒã«ã®ç¹å¥ãªç¹ãååšããå®è£
ãããã³ãã®ããã©ãŒãã³ã¹ãããã«æ·±ãæãäžããããšæããŸããã ãããã®è³ªåãžã®åçã«ãèå³ãããå Žåã¯ãcatãžããããã
ã·ã¹ãã ã³ãŒã«
ã¢ãã¿ãŒã«äœãã衚瀺ããããããã€ã¹ã«æžã蟌ãã ãããã¡ã€ã«ããèªã¿åã£ãããããã³ã«ãOSã®ã«ãŒãã«ã䜿çšããå¿
èŠããããŸãã ããŒããŠã§ã¢ãšã®éä¿¡ãæ
åœããã®ã¯OSã«ãŒãã«ã§ãããå²ã蟌ã¿ãããã»ããµã¢ãŒããã¿ã¹ã¯ã¹ã€ããã³ã°ã§åäœãããããããã°ã©ã ãŠãŒã¶ãŒããªãã¬ãŒãã£ã³ã°ã·ã¹ãã å
šäœã®åäœãå§åã§ããªãããã«ãã¡ã¢ãªç©ºéããŠãŒã¶ãŒç©ºé ïŒãŠãŒã¶ãŒãå®è¡ããããã«èšèšãããã¡ã¢ãªé åïŒã«åå²ããããšã決å®ãããŸããããã°ã©ã ïŒããã³ã«ãŒãã«ã¹ããŒã¹ãOSã«ãŒãã«ã¡ã¢ãªãžã®ãŠãŒã¶ãŒã¢ã¯ã»ã¹ãæåŠããŸãã ãã®åé¢ã¯ã ã»ã°ã¡ã³ãåã¡ã¢ãªä¿è·ã䜿çšããããŒããŠã§ã¢ã®x86ãã¡ããªã§å®è£
ãããŸã ã ãããããŠãŒã¶ãŒããã°ã©ã ã¯äœããã®åœ¢ã§ã«ãŒãã«ãšéä¿¡ããå¿
èŠããããŸãããã®ããã ã·ã¹ãã ã³ãŒã«ã®æŠå¿µãçºæãããŸããã
ã·ã¹ãã ã³ãŒã«ã¯ããŠãŒã¶ãŒç©ºéããã°ã©ã ãã«ãŒãã«ç©ºéã«åŒã³åºãæ¹æ³ã§ãã å€éšããèŠããšãããã¯ç¬èªã®åŒã³åºãèŠçŽãæã€éåžžã®é¢æ°ã®åŒã³åºãã®ããã«èŠãããããããŸããããå®éã«ã¯ãããã»ããµã¯åŒã³åºãåœä»€ã§é¢æ°ãåŒã³åºããããšããããå°ãå€ãã®ã¢ã¯ã·ã§ã³ãå®è¡ããŸãã ããšãã°ãx86ã¢ãŒããã¯ãã£ã§ã¯ãã·ã¹ãã ã³ãŒã«äžã«å°ãªããšãç¹æš©ã¬ãã«ã®å¢å ãçºçãããŠãŒã¶ãŒã»ã°ã¡ã³ããã«ãŒãã«ã»ã°ã¡ã³ãã«çœ®ãæããããIPã¬ãžã¹ã¿ãã·ã¹ãã ã³ãŒã«ãã³ãã©ãŒã«èšå®ãããŸãã
ã·ã¹ãã ã³ãŒã«ã¯é¢æ°ã§ã©ãããããLinuxã®libc.soãWindowsã®ntdll.dllãªã©ãã¢ããªã±ãŒã·ã§ã³éçºè
ã察話ããããŸããŸãªã©ã€ãã©ãªã«é ãããŠãããããããã°ã©ãã¯éåžžãã·ã¹ãã ã³ãŒã«ãçŽæ¥æäœããŸããã
çè«çã«ã¯ã0ã§é€ç®ããŠããäŸå€ã䜿çšããŠã·ã¹ãã ã³ãŒã«ãå®è£
ã§ããŸããäž»ãªããšã¯ãå¶åŸ¡ãã«ãŒãã«ã«è»¢éããããšã§ãã äŸå€ã®å®è£
ã®å®éã®äŸãæ€èšããŠãã ããã
ã·ã¹ãã ã³ãŒã«ãå®è£
ããæ¹æ³
ç¡å¹ãªåœä»€å®è¡ã
以åã80386ã«æ»ããšãã·ã¹ãã ã³ãŒã«ãè¡ãæéã®æ¹æ³ã§ããã ãã®ãããéåžžã¯æå³ã®ãªã誀ã£ãLOCK NOPåœä»€ã䜿çšããããã®åŸãããã»ããµãç¡å¹ãªåœä»€ãã³ãã©ãåŒã³åºããŸããã ããã¯20幎以äžåã§ããã圌ãã¯ããã®æ¹æ³ã¯Microsoft Corporationã§ã·ã¹ãã ã³ãŒã«ãåŠçãããšèšããŸãã 誀ã£ãåœä»€ã®ãã³ãã©ãŒã¯ãæå³ããç®çã«äœ¿çšãããããã«ãªããŸããã
ç°ãªãç¹æš©ã¬ãã«ã®ã³ãŒãã»ã°ã¡ã³ãã«ã¢ã¯ã»ã¹ããããã«ãã€ã³ãã«ã¯ã²ãŒãèšè¿°åãšåŒã°ããç¹æ®ãªèšè¿°åã»ãããéçºããŸããã ãã®ãããªèšè¿°åã«ã¯4ã€ã®ã¿ã€ãããããŸãã
- ã³ãŒã«ã²ãŒã
- ãã©ããã²ãŒãïŒ int 3ãªã© ãã³ãŒãã®å®è¡ãå¿
èŠãªäŸå€ã®å ŽåïŒ
- å²ã蟌ã¿ã²ãŒãïŒãã©ããã²ãŒãã«äŒŒãŠããŸãããããã€ãã®éãããããŸã ïŒ
- ã¿ã¹ã¯ã²ãŒãïŒã¿ã¹ã¯ã®åãæ¿ãã«äœ¿çšããããšæ³å®ïŒ
x86ã§ã·ã¹ãã ã³ãŒã«ãå®è£
ããããšãèšç»ãããã®ã¯ã³ãŒã«ã²ãŒãã§ãã£ããããã³ãŒã«ã²ãŒãã«ã®ã¿èå³ããããŸãã
ã³ãŒã«ã²ãŒãã¯ã call farãŸãã¯jmp faråœä»€ã䜿çšããŠå®è£
ãããOSã«ãŒãã«ã«ãã£ãŠæ§æãããã³ãŒã«ã²ãŒãèšè¿°åããã©ã¡ãŒã¿ãŒãšããŠåãåããŸãã ä¿è·ãªã³ã°ã®ä»»æã®ã¬ãã«ãš16ãããã³ãŒãã«åãæ¿ããããšãã§ãããããããã¯ããªãæè»ãªã¡ã«ããºã ã§ãã ã³ãŒã«ã²ãŒãã¯ãå²ã蟌ã¿ãããçç£æ§ãé«ããšèããããŠããŸãã ãã®æ¹æ³ã¯ãOS / 2ããã³Windows 95 ã§äœ¿çšãããŠããŸãã ãLinux ã䜿çšããäžäŸ¿ãã®ããããã®ã¡ã«ããºã ã¯å®è£
ãããŸããã§ããã æéãçµã€ã«ã€ããŠãã·ã¹ãã ã³ãŒã«ïŒsysenter / sysexitïŒã®å®è£
ãããçç£çã§äœ¿ãããããªã£ãããã䜿çšãå®å
šã«äžæ¢ãããŸããã
Linuxã·ã¹ãã ã³ãŒã«
Linux OSã®x86-64ã¢ãŒããã¯ãã£ã§ã·ã¹ãã ã³ãŒã«ãè¡ãæ¹æ³ã¯ããã€ããããŸãã
- int 80h
- sysenter / sysexit
- syscall / sysret
- vsyscall
- vDSO
åã·ã¹ãã ã³ãŒã«ã®å®è£
ã«ã¯ç¬èªã®ç¹æ§ããããŸãããäžè¬çã«ãLinuxãã³ãã©ãŒã¯ã»ãŒåãæ§é ãæã£ãŠããŸãã
- ãŠãŒã¶ãŒã¹ããŒã¹ã³ãŒãã®èªã¿åã/æžã蟌ã¿/å®è¡ã«å¯Ÿããä¿è·ãæå¹ã«ãªã£ãŠããŸãã
- ãŠãŒã¶ãŒã¹ã¿ãã¯ãã«ãŒãã«ã¹ã¿ãã¯ã«çœ®ãæããããåŒã³åºãå
ãä¿åããã¬ãžã¹ã¿ãä¿åãããŸãã
- é²è¡äžã®ã·ã¹ãã ã³ãŒã«åŠç
- ã¹ã¿ãã¯ãã¬ãžã¹ã¿ãŒã®å埩
- ä¿è·ãç¡å¹ã«ãã
- ã·ã¹ãã ã³ãŒã«ãçµäºãã
åã·ã¹ãã ã³ãŒã«ã詳ããèŠãŠã¿ãŸãããã
int 80h
æåãx86ã¢ãŒããã¯ãã£ã§ã¯ãLinuxã¯ãœãããŠã§ã¢å²ã蟌ã¿128ã䜿çšããŠã·ã¹ãã ã³ãŒã«ãè¡ããŸããã ã·ã¹ãã ã³ãŒã«çªå·ã瀺ãããã«ããŠãŒã¶ãŒã¯ã·ã¹ãã ã³ãŒã«çªå·ãeaxã«èšå®ãããã®ãã©ã¡ãŒã¿ãŒã¯ã¬ãžã¹ã¿ebx ã ecx ã edx ã esi ã edi ã ebpã«é çªã«é
眮ãããŸãã 次ã«ã int 80håœä»€ãåŒã³åºãã ãããã°ã©ã ã«ãã£ãŠå²ã蟌ã¿ãçºçããŸãã ããã»ããµãŒã¯ãã«ãŒãã«ã®åæåäžã«Linuxã«ãŒãã«ã«ãã£ãŠã€ã³ã¹ããŒã«ãããå²ã蟌ã¿ãã³ãã©ãŒãåŒã³åºããŸãã x86-64ã§ã¯ãå²ã蟌ã¿åŒã³åºãã¯äžäœäºææ§ã®ããã«x32ã¢ãŒããšãã¥ã¬ãŒã·ã§ã³äžã«ã®ã¿äœ¿çšãããŸãã
ååãšããŠã é«åºŠãªã¢ãŒãã§åœä»€ã䜿çšããããšãçŠæ¢ãã人ã¯ããŸããã ãã ãã32ãããã³ãŒã«ããŒãã«ã䜿çšãã ã 䜿çšããããã¹ãŠã®ã¢ãã¬ã¹ã¯32ãããã¢ãã¬ã¹ç©ºéã«é
眮ããå¿
èŠãããããšãç解ããå¿
èŠããããŸãã SYSTEM V ABI [4]§3.5.1ã«ããã°ãä»®æ³ã¢ãã¬ã¹ããªã³ã¯æ®µéã§æ¢ç¥ã§ããã2GBã«é
眮ãããŠããããã°ã©ã ã§ã¯ ãããã©ã«ãã§å°ããªã¡ã¢ãªã¢ãã«ã䜿çšãããæ¢ç¥ã®æåã¯ãã¹ãŠ32ãããã¢ãã¬ã¹ç©ºéã«ãããŸãã éçã«ã³ã³ãã€ã«ãããããã°ã©ã ã¯ãã®å®çŸ©ã«é©ããŠããã int 80hã䜿çšã§ããŸãã 段éçãªå²ã蟌ã¿æäœã«ã€ããŠã¯ã stackoverflowã§è©³ãã説æããŠããŸãã
ã«ãŒãã«ã§ã¯ããã®å²ã蟌ã¿ã®ãã³ãã©ãŒã¯entry_INT80_compaté¢æ°ã§ããã arch / x86 / entry / entry_64_compat.Sã«ãããŸã
int 80hã®åŒã³åºãäŸsection .text global _start _start: mov edx,len mov ecx,msg mov ebx,1 ; file descriptor (stdout) mov eax,4 ; system call number (sys_write) int 0x80 ; call kernel mov eax,1 ; system call number (sys_exit) int 0x80 ; call kernel section .data msg db 'Hello, world!',0xa len equ $ - msg
ã³ã³ãã€ã«ïŒ
nasm -f elf main.s -o main32.o ld -melf_i386 main32.o -o a32.out
ãŸãã¯æ¡åŒµã¢ãŒãã§ïŒããã°ã©ã ã¯éçã«ã³ã³ãã€ã«ãããããã«åäœããŸãïŒ
nasm -f elf64 main.s -o main.o ld main.o -o a.out
sysenter / sysexit
ãã°ããããŠãx86-64ããªãã£ãå Žåã§ããIntelã¯ç¹å¥ãªã·ã¹ãã ã³ãŒã«åœä»€ãäœæããããšã§ã·ã¹ãã ã³ãŒã«ãé«éåã§ãããããå²ã蟌ã¿ã³ã¹ãã®äžéšãåé¿ã§ããããšã«æ°ä»ããŸããã ãã®ãããããã€ãã®sysenter / sysexitåœä»€ãç»å ŽããŸãã ã ããŒããŠã§ã¢ã¬ãã«ã§ã¯ãsysenteråœä»€ãå®è¡ãããšãã«ãèšè¿°åã®æå¹æ§ã®å€ãã®ãã§ãã¯ãçç¥ãããç¹æš©ã®ã¬ãã«ã«å¿ãããã§ãã¯ãè¡ããããããå éãéæãããŸã[3]§6.1ã åœä»€ã¯ããããåŒã³åºãããã°ã©ã ããã©ããã¡ã¢ãªã¢ãã«ã䜿çšãããšããäºå®ã«ãäŸåããŠããŸãã Intelã¢ãŒããã¯ãã£ã§ã¯ãåœä»€ã¯äºæã¢ãŒããšæ¡åŒµã¢ãŒãã®äž¡æ¹ã§æå¹ã§ãããAMDã®å Žåããã®æ¡åŒµã¢ãŒãã®åœä»€ã¯äžæãªãªãã³ãŒããé€å€ããŸã[3]ã ãããã£ãŠã sysenter / sysexitã®ãã¢ã¯çŸåšãäºæã¢ãŒãã§ã®ã¿äœ¿çšãããŸãã
ã«ãŒãã«ã§ã¯ããã®åœä»€ã®ãã³ãã©ãŒã¯entry_SYSENTER_compaté¢æ°ã§ããã arch / x86 / entry / entry_64_compat.Sã«ãããŸã
Sysenterã³ãŒã«ã®äŸ section .text global _start _start: mov edx,len ;message length mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) push continue_l push ecx push edx push ebp mov ebp,esp sysenter hlt ; dumb instructions that is going to be skipped continue_l: mov eax,1 ;system call number (sys_exit) mov ebx,0 push ecx push edx push ebp mov ebp,esp sysenter section .data msg db 'Hello, world!',0xa len equ $ - msg
ã³ã³ãã€ã«ïŒ
nasm -f elf main.s -o main.o ld main.o -melf_i386 -o a.out
åœä»€ã¯ã€ã³ãã«ã®ã¢ãŒããã¯ãã£ã®å®è£
ã§æå¹ã§ãããšããäºå®ã«ãããããããé«åºŠãªã¢ãŒãã§ã¯ããã®ã·ã¹ãã ã³ãŒã«ã¯ã»ãšãã©åäœããŸããã ããã¯ãçŸåšã®ã¹ã¿ãã¯å€ãebpã¬ãžã¹ã¿ã«æ ŒçŽãããŠãããã¡ã¢ãªã¢ãã«ã«é¢ä¿ãªãããããã¢ãã¬ã¹ã32ãããã¢ãã¬ã¹ç©ºéã®å€åŽã«ããããã§ãã ããã¯ãLinuxãã¹ã¿ãã¯ãã¹ããŒã¹ã®æ£èŠã¢ãã¬ã¹ã®äžååã®æåŸã«ãããããããã§ãã
Linuxã«ãŒãã«éçºè
ã¯ãã·ã¹ãã ã³ãŒã«ABIãå€æŽãããå¯èœæ§ããããããããŒãã·ã¹ãã ããã°ã©ãã³ã°ã«å¯ŸããŠãŠãŒã¶ãŒã«èŠåããŸãã Androidã¯ãã®ã¢ããã€ã¹ã«åŸããªãã£ããããLinuxã¯äžäœäºææ§ãç¶æããããã«ããããããŒã«ããã¯ããå¿
èŠããããŸããã vDSOã䜿çšããŠã·ã¹ãã ã³ãŒã«ãæ£ããå®è£
ããŸããããã«ã€ããŠã¯åŸã§èª¬æããŸãã
syscall / sysret
AMDã¯AMD64ãšåŒã°ããx86-64ã¢ãŒããã¯ãã£ãéçºãããããç¬èªã®ã·ã¹ãã ã³ãŒã«ãäœæããããšã«ããŸããã ãã®åœä»€ã¯ãIA-32ã¢ãŒããã¯ãã£çšã®sysenter / sysexitã®é¡äŒŒç©ãšããŠãAMDã«ãã£ãŠéçºãããŸããã AMDã¯ãåœä»€ãã¢ããã³ã¹ãã¢ãŒããšäºæã¢ãŒãã®äž¡æ¹ã§å®è£
ãããŠããããšã確èªããŸããããIntelã¯äºæã¢ãŒãã§ãã®åœä»€ããµããŒãããªãããšã«ããŸããã ããã«ãé¢ããããLinuxã«ã¯ãx32ããã³x64ã®åã¢ãŒãã«å¯ŸããŠ2ã€ã®ãã³ãã©ãŒããããŸãã ãã®åœä»€ã®ãã³ãã©ãŒã¯ãx64ã®entry_SYSCALL_64ããã³x32ã®entry_SYSCALL_compaté¢æ°ã§ãããããããarch / x86 / entry / entry_64.Sããã³arch / x86 / entry / entry_64_compat.Sã«ãããŸãã
ã·ã¹ãã ã³ãŒã«ã®æé ããã詳现ã«ç解ããããšã«èå³ããã人ã®ããã«ãIntelæ¬äŒŒã³ãŒãã¯Intelããã¥ã¢ã«[0]ïŒ4.3ïŒã«èšèŒãããŠããŸãã
ã·ã¹ã³ãŒã«ã³ãŒã«ã®äŸ section .text global _start _start: mov rdx,len ;message length mov rsi,msg ;message to write mov rdi,1 ;file descriptor (stdout) mov rax,1 ;system call number (sys_write) syscall mov rax,60 ;system call number (sys_exit) syscall section .data msg db 'Hello, world!',0xa len equ $ - msg
ç·šé
nasm -f elf64 main.s -o main.o ld main.o -o a.out
32ãããã·ã¹ãã ã³ãŒã«ã®åŒã³åºãäŸæ¬¡ã®äŸããã¹ãããã«ã¯ãæ§æCONFIG_IA32_EMULATION = yã®ã«ãŒãã«ãšAMDã³ã³ãã¥ãŒã¿ãŒãå¿
èŠã§ãã Intelã³ã³ãã¥ãŒã¿ãŒãããå Žåã¯ãä»®æ³ãã·ã³ã§äŸãå®è¡ã§ããŸãã Linuxã¯èŠåãªãã§ãã®ã·ã¹ãã ã³ãŒã«ã®ABIãå€æŽã§ãããããå床ãç¥ããããŸããvDSOãä»ããŠäºæã¢ãŒãã§ã·ã¹ãã ã³ãŒã«ãå®è¡ããæ¹ãããé©åã§ãã
section .text global _start _start: mov edx,len ;message length mov ebp,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) push continue_l push ecx push edx push ebp syscall hlt continue_l: mov eax,1 ;system call number (sys_exit) mov ebx,0 push ecx push edx push ebp syscall section .data msg db 'Hello, world!',0xa len equ $ - msg
ã³ã³ãã€ã«ïŒ
nasm -f elf main.s -o main.o ld main.o -melf_i386 -o a.out
AMDãIntel sysenteråœä»€ãx86-64ã¢ãŒããã¯ãã£ã«æ¡åŒµãã代ããã«åœä»€ãéçºããããšã«ããçç±ã¯æããã§ã¯ãããŸããã
vsyscall
ãŠãŒã¶ãŒç©ºéããã«ãŒãã«ç©ºéã«åãæ¿ãããšãã³ã³ããã¹ããåãæ¿ãããŸãããããã¯æãå®äŸ¡ãªæäœã§ã¯ãããŸããã ãããã£ãŠãã·ã¹ãã ã³ãŒã«ã®ããã©ãŒãã³ã¹ãåäžãããããã«ããŠãŒã¶ãŒç©ºéã§ããããåŠçããããšã決å®ãããŸããã ãã®ãããã«ãŒãã«ã¹ããŒã¹ããŠãŒã¶ãŒã¹ããŒã¹ã«ãããã³ã°ããããã«8 MBã®ã¡ã¢ãªãäºçŽãããŸããã x86ã¢ãŒããã¯ãã£åãã«ãäžè¬çã«äœ¿çšãããèªã¿åãå°çšåŒã³åºãã®3ã€ã®å®è£
ããã®ã¡ã¢ãªã«é
眮ãããŸããïŒgettimeofdayãtimeãgetcpuã
æéã®çµéãšãšãã«ã vsyscallã«ã¯é倧ãªæ¬ ç¹ãããããšãæããã«ãªããŸããã ã¢ãã¬ã¹ç©ºéã®åºå®äœçœ®ã¯ã»ãã¥ãªãã£äžã®è匱æ§ã§ãããå²ãåœãŠãããã¡ã¢ãªã®éã«æè»æ§ããªããããã«ãŒãã«ã®è¡šç€ºé åã®æ¡å€§ã«æªåœ±é¿ãäžããå¯èœæ§ããããŸãã
äŸãæ©èœããããã«ã¯ãã«ãŒãã«ãvsyscallããµããŒãããŠããå¿
èŠããããŸãïŒ CONFIG_X86_VSYSCALL_EMULATION = y
VsyscallåŒã³åºãã®äŸ #include <sys/time.h> #include <stdio.h> #define VSYSCALL_ADDR 0xffffffffff600000UL int main() { // Offsets in x86-64 // 0: gettimeofday // 1024: time // 2048: getcpu int (*f)(struct timeval *, struct timezone *); struct timeval tm; unsigned long addrOffset = 0; f = (void*)VSYSCALL_ADDR + addrOffset; f(&tm, NULL); printf("%d:%d\n", tm.tv_sec, tm.tv_usec); }
ã³ã³ãã€ã«ïŒ
gcc main.c
Linuxã¯äºæã¢ãŒãã§vsyscallã衚瀺ããŸããã
çŸæç¹ã§ã¯ãäžäœäºææ§ãç¶æããããã«ãLinuxã«ãŒãã«ã¯vsyscallãšãã¥ã¬ãŒã·ã§ã³ãæäŸããŠããŸãã ãšãã¥ã¬ãŒã·ã§ã³ã¯ãã»ãã¥ãªãã£ããŒã«ã«ããããåœãŠãŠããã©ãŒãã³ã¹ãäœäžãããããã«èšèšãããŠããŸãã
ãšãã¥ã¬ãŒã·ã§ã³ã¯2ã€ã®æ¹æ³ã§å®è£
ã§ããŸãã
æåã®æ¹æ³ã¯ãé¢æ°ã¢ãã¬ã¹ãsyscallã·ã¹ãã ã³ãŒã«ã«çœ®ãæããããšã§ãã ãã®å Žåãx86-64ã§ã®gettimeofdayé¢æ°ã®ä»®æ³ã·ã¹ãã ã³ãŒã«ã¯æ¬¡ã®ãšããã§ãã
movq $0x60, %rax syscall ret
0x60ã¯gettimeofdayã·ã¹ãã ã³ãŒã«ã®ã³ãŒãã§ãã
2çªç®ã®æ¹æ³ã¯ããå°ãèå³æ·±ãã§ãã vsyscallé¢æ°ãåŒã³åºããããšã ããŒãžãã©ãŒã«ãäŸå€ãã¹ããŒãããŸããããã¯Linuxã«ãã£ãŠåŠçãããŸãã OSã¯ã vsyscallã§ã®åœä»€ã®å®è¡ãåå ã§ãšã©ãŒãçºçããããšãèªèãã emulate_vsyscallä»®æ³ã·ã¹ãã ã³ãŒã«ãã³ãã©ãŒ ïŒarch / x86 / entry / vsyscall / vsyscall_64.cïŒã«å¶åŸ¡ãæž¡ããŸãã
vsyscallã®å®è£
ã¯ã vsyscallã«ãŒãã«ãã©ã¡ãŒã¿ãŒã䜿çšããŠå¶åŸ¡ã§ããŸã ã vsyscall=none
ãã©ã¡ãŒã¿ãŒã䜿çšããŠä»®æ³ã·ã¹ãã ã³ãŒã«ãç¡å¹ã«ããããsyscall syscall=native
åœä»€ã䜿çšããŠå®è£
ãæå®ãããã Page fault vsyscall=emulate
ã䜿çšããŸãã
vDSOïŒä»®æ³åçå
±æãªããžã§ã¯ãïŒ
vsyscallã®äž»ãªæ¬ ç¹ãä¿®æ£ããããã«ãåçã«æ¥ç¶ãããã©ã€ãã©ãªã®è¡šç€ºãšãã圢ã§ã·ã¹ãã ã³ãŒã«ãå®è£
ãã ASLRãã¯ãããžãé©çšããããšãææ¡ãããŸããã ãlongãã¢ãŒãã§ã¯ãã©ã€ãã©ãªã¯linux-vdso.so.1ãšåŒã°ããäºæã¢ãŒãã§ã¯ã linux-gate.so.1ãšåŒã°ããŸãã ã©ã€ãã©ãªã¯ãéçã«ã³ã³ãã€ã«ãããå Žåã§ããããã»ã¹ããšã«èªåçã«ããŒããããŸãã libcã©ã€ãã©ãªã®åçãªã³ã¯ã®å Žåã¯ã ldd
ãŠãŒãã£ãªãã£ã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³ã®äŸåé¢ä¿ã確èªã§ããŸãã
ãŸããvDSOã¯ãäºæã¢ãŒããªã©ã§æãå¹ççãªã·ã¹ãã ã³ãŒã«ã¡ãœããã®éžæãšããŠäœ¿çšãããŸãã
å
±ææ©èœã®ãªã¹ãã¯ã ããã¥ã¢ã«ã«èšèŒãããŠããŸã ã
VDSOåŒã³åºãã®äŸ #include <sys/time.h> #include <dlfcn.h> #include <stdio.h> #include <assert.h> #if defined __x86_64__ #define VDSO_NAME "linux-vdso.so.1" #else #define VDSO_NAME "linux-gate.so.1" #endif int main() { int (*f)(struct timeval *, struct timezone *); struct timeval tm = {0}; void *vdso = dlopen(VDSO_NAME, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); assert(vdso && "vdso not found"); f = dlsym(vdso, "__vdso_gettimeofday"); assert(f); f(&tm, NULL); printf("%d:%d\n", tm.tv_sec, tm.tv_usec); }
ã³ã³ãã€ã«ïŒ
gcc -ldl main.c
äºæã¢ãŒãã®å ŽåïŒ
gcc -ldl -m32 main.c -o a32.elf
è£å©ãã¯ãã«AT_SYSINFO_EHDRããã©ã€ãã©ãªã¢ãã¬ã¹ãæœåºããå
±æãªããžã§ã¯ãã解æããããšã«ãããvDSOé¢æ°ãæ¢ãã®ãæé©ã§ãã è£å©ãã¯ãã«ããvDSOã解æããäŸã¯ãã«ãŒãã«ãœãŒã¹ã³ãŒãã«ãããŸãïŒtools / testing / selftests / vDSO / parse_vdso.c
ãŸãã¯ãèå³ãããå Žåã¯ãæãäžããŠãglibcã§vDSOãã©ã®ããã«è§£æããããã確èªã§ããŸãã
- ãã«ããŒãã¯ãã«ã®è§£æïŒelf / dl-sysdep.c
- å
±æã©ã€ãã©ãªè§£æïŒelf / setup-vdso.h
- é¢æ°å€ã®èšå®ïŒsysdeps / unix / sysv / linux / x86_64 / init-first.cãsysdeps / unix / sysv / linux / x86 / gettimeofday.cãsysdeps / unix / sysv / linux / x86 / time.c
System V ABI AMD64 [4]ã«ããã°ã syscallåœä»€ã䜿çšããŠåŒã³åºããè¡ãå¿
èŠããããŸã ã å®éã«ã¯ãvDSOãä»ããåŒã³åºãããã®åœä»€ã«è¿œå ãããŸãã int 80hããã³vsyscallã®åœ¢åŒã®ã·ã¹ãã ã³ãŒã«ã®ãµããŒãã¯ãåŸæ¹äºææ§ã®ããã«æ®ããŸããã
ã·ã¹ãã ã³ãŒã«ããã©ãŒãã³ã¹ã®æ¯èŒ
ã·ã¹ãã ã³ãŒã«ã®é床ããã¹ããããšããã¹ãŠããããŸãã«ãªããŸãã x86ã¢ãŒããã¯ãã£ã§ã¯ãåäžã®åœä»€ã®å®è¡ã¯ããã£ãã·ã¥å
ã®åœä»€ã®ååšããââã€ãã©ã€ã³ã®è² è·ããã®ã¢ãŒããã¯ãã£ã®é
延ããŒãã«ãªã©ãå€ãã®èŠå ã®åœ±é¿ãåããŸã[2]ã ãããã£ãŠãã³ãŒãã»ã¯ã·ã§ã³ã®å®è¡é床ãå€æããããšã¯éåžžã«å°é£ã§ãã Intelã«ã¯ãã³ãŒãã»ã°ã¡ã³ãçšã®ç¹å¥ãªæé枬å®ã¬ã€ããããããŸã[1]ã ããããåé¡ã¯ããŠãŒã¶ãŒç©ºéããã«ãŒãã«ãªããžã§ã¯ããåŒã³åºãå¿
èŠããããããããã¥ã¡ã³ãã«åŸã£ãŠæéã枬å®ã§ããªãããšã§ãã
ãããã£ãŠã clock_gettimeã䜿çšããŠæéã枬å®ãã gettimeofdayåŒã³åºãã®ããã©ãŒãã³ã¹ããã¹ãããããšã決å®ãããŸãããããã¯ãã·ã¹ãã åŒã³åºãã®ãã¹ãŠã®å®è£
ã«å«ãŸããŠããããã§ãã ç°ãªãããã»ããµã§ã¯ãæéãç°ãªãå ŽåããããŸãããäžè¬ã«ãçžå¯Ÿçãªçµæã¯äŒŒãŠããã¯ãã§ãã
ããã°ã©ã ã¯æ°åèµ·åããããã®çµæãæå°å®è¡æéãåãããŸããã
int 80h ã sysenterããã³vDSO-32ã®ãã¹ãã¯äºæã¢ãŒãã§å®è¡ãããŸããã
ãã¹ãããã°ã©ã #include <sys/time.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <syscall.h> #include <dlfcn.h> #include <limits.h> #define min(a,b) ((a) < (b)) ? (a) : (b) #define GIGA 1000000000 #define difftime(start, end) (end.tv_sec - start.tv_sec) * GIGA + end.tv_nsec - start.tv_nsec static struct timeval g_timespec; #if defined __x86_64__ static inline int test_syscall() { register long int result asm ("rax"); asm volatile ( "lea %[p0], %%rdi \n\t" "mov $0, %%rsi \n\t" "mov %[sysnum], %%rax \n\t" "syscall \n\t" : "=r"(result) : [sysnum] "i" (SYS_gettimeofday), [p0] "m" (g_timespec) : "rcx", "rsi"); return result; } #endif static inline int test_int80h() { register int result asm ("eax"); asm volatile ( "lea %[p0], %%ebx \n\t" "mov $0, %%ecx \n\t" "mov %[sysnum], %%eax \n\t" "int $0x80 \n\t" : "=r"(result) : [sysnum] "i" (SYS_gettimeofday), [p0] "m" (g_timespec) : "ebx", "ecx"); return result; } int (*g_f)(struct timeval *, struct timezone *); static void prepare_vdso() { void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); if (!vdso) { vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); } assert(vdso && "vdso not found"); g_f = dlsym(vdso, "__vdso_gettimeofday"); } static int test_g_f() { return g_f(&g_timespec, 0); } #define VSYSCALL_ADDR 0xffffffffff600000UL static void prepare_vsyscall() { g_f = (void*)VSYSCALL_ADDR; } static inline int test_sysenter() { register int result asm ("eax"); asm volatile ( "lea %[p0], %%ebx \n\t" "mov $0, %%ecx \n\t" "mov %[sysnum], %%eax \n\t" "push $cont_label%=\n\t" "push %%ecx \n\t" "push %%edx \n\t" "push %%ebp \n\t" "mov %%esp, %%ebp \n\t" "sysenter \n\t" "cont_label%=: \n\t" : "=r"(result) : [sysnum] "i" (SYS_gettimeofday), [p0] "m" (g_timespec) : "ebx", "esp"); return result; } #ifdef TEST_SYSCALL #define TEST_PREPARE() #define TEST_PROC_CALL() test_syscall() #elif defined TEST_VDSO #define TEST_PREPARE() prepare_vdso() #define TEST_PROC_CALL() test_g_f() #elif defined TEST_VSYSCALL #define TEST_PREPARE() prepare_vsyscall() #define TEST_PROC_CALL() test_g_f() #elif defined TEST_INT80H #define TEST_PREPARE() #define TEST_PROC_CALL() test_int80h() #elif defined TEST_SYSENTER #define TEST_PREPARE() #define TEST_PROC_CALL() test_sysenter() #else #error Choose test #endif static inline unsigned long test() { unsigned long result = ULONG_MAX; struct timespec start = {0}, end = {0}; int rt, rt2, rt3; for (int i = 0; i < 1000; ++i) { rt = clock_gettime(CLOCK_MONOTONIC, &start); rt3 = TEST_PROC_CALL(); rt2 = clock_gettime(CLOCK_MONOTONIC, &end); assert(rt == 0); assert(rt2 == 0); assert(rt3 == 0); result = min(difftime(start, end), result); } return result; } int main() { TEST_PREPARE(); // prepare calls int a = TEST_PROC_CALL(); assert(a == 0); a = TEST_PROC_CALL(); assert(a == 0); a = TEST_PROC_CALL(); assert(a == 0); unsigned long result = test(); printf("%lu\n", result); }
ã³ã³ãã€ã«ïŒ
gcc -O2 -DTEST_SYSCALL time_test.c -o test_syscall gcc -O2 -DTEST_VDSO -ldl time_test.c -o test_vdso gcc -O2 -DTEST_VSYSCALL time_test.c -o test_vsyscall #m32 gcc -O2 -DTEST_VDSO -ldl -m32 time_test.c -o test_vdso_32 gcc -O2 -DTEST_INT80H -m32 time_test.c -o test_int80 gcc -O2 -DTEST_SYSENTER -m32 time_test.c -o test_sysenter
ã·ã¹ãã ã«ã€ããŠ
cat /proc/cpuinfo | grep "model name" -m 1
cat /proc/cpuinfo | grep "model name" -m 1
-Intel®CoreïŒTMïŒi7-5500U CPU @ 2.40GHz
uname -r
-4.14.13-1-ARCH
çµæè¡š
å®è£
| æéïŒnsïŒ |
---|
int 80h | 498 |
sysenter | 338 |
ã·ã¹ã³ãŒã« | 278 |
vsyscallãšãã¥ã¬ãŒã | 692 |
vsyscallãã€ãã£ã | 278 |
vDSO | 37 |
vDSO-32 | 51 |
ã芧ã®ãšãããã·ã¹ãã ã³ãŒã«ã®æ°ããå®è£
ã¯ããããã以åã®å®è£
ãããçç£æ§ãé«ããvsysvallã¯ã«ãŠã³ããããŸãããããã¯ãšãã¥ã¬ãŒã·ã§ã³ã§ããããã§ãã ããããæ¢ã«æšæž¬ããããã«ãvsyscallãæå³ãããã®ã§ããå ŽåãåŒã³åºãæéã¯vDSOã«äŒŒãŠããŸãã
çŸåšã®ãã¹ãŠã®ããã©ãŒãã³ã¹æ¯èŒã¯ãã¡ã«ãããŠã³ã®è匱æ§ãä¿®æ£ããKPTIãããã§è¡ãããŠããŸãã
KPTIãããã¯ãã¡ã«ãããŠã³ã®è匱æ§ãä¿®æ£ããããã«ç¹å¥ã«éçºãããŸããã ãåç¥ã®ããã«ããã®ãããã¯OSã®ããã©ãŒãã³ã¹ãäœäžãããŸãã KPTIããªãïŒpti =ãªãïŒã«ããŠããã©ãŒãã³ã¹ããã§ãã¯ããŸãããã
ãããããªãã«ããçµæã®è¡š
å®è£
| æéïŒnsïŒ | ãããåŸã®å®è¡æéãå¢ããïŒnsïŒ | ãããåŸã®ããã©ãŒãã³ã¹äœäž(t1 - t0) / t0 * 100% |
---|
int 80h | 317 | 181 | 57ïŒ
|
sysenter | 150 | 188 | 125ïŒ
|
ã·ã¹ã³ãŒã« | 103 | 175 | 170ïŒ
|
vsyscallãšãã¥ã¬ãŒã | 496 | 196 | 40ïŒ
|
vsyscallãã€ãã£ã | 103 | 175 | 170ïŒ
|
vDSO | 37 | 0 | 0ïŒ
|
vDSO-32 | 51 | 0 | 0ïŒ
|
ããããçŽ180 nsãããå§ããåŸãå¹³åããŠã«ãŒãã«ã¢ãŒããžã®ç§»è¡ãšãã®éã®ç§»è¡ã ããå€ãã®æéãæããã«ããã¯TLBãã£ãã·ã¥ããã©ãã·ã¥ããäŸ¡æ Œã§ãã
ãã®ã¿ã€ãã®åŒã³åºãã§ã¯ã«ãŒãã«ã¢ãŒããžã®ç§»è¡ããªããããvDSOãä»ããã·ã¹ãã ã³ãŒã«ã®ããã©ãŒãã³ã¹ã¯äœäžããŠããŸããããããã£ãŠãTLBãã£ãã·ã¥ããã©ãã·ã¥ããçç±ã¯ãããŸããã
ããã«èªãããã«
Linux ( , ): https://0xax.gitbooks.io/linux-insides/content/SysCall/syscall-3.html Linux: https://www.win.tue.nl/~aeb/linux/lk/lk-4.html , 1: https://lwn.net/Articles/604287/ , 2: https://lwn.net/Articles/604515/
åç
§è³æ
[0] Intel 64ããã³IA-32ã¢ãŒããã¯ãã£éçºè
ããã¥ã¢ã«ïŒVolã 2B
[1] ã³ãŒãå®è¡æéã®ãã³ãããŒã¯æ¹æ³...
[2] AMDããã³Intel x86ããã»ããµãŒã®åœä»€ã¬ã€ãã³ã·ãŒãšã¹ã«ãŒããã
[3] AMD64 Architecture Programmer's Manual Volume 2ïŒã·ã¹ãã ããã°ã©ãã³ã°
[4] System V ABI AMD64