2016-01-31 13 views
6

मैं पिछले libc में syscall कॉल dissects:लिनक्स syscall, libc, VDSO और कार्यान्वयन विच्छेदन

git clone git://sourceware.org/git/glibc.git 

और मैं में sysdeps/यूनिक्स/SysV/linux/i386/sysdep.h इस कोड है:

# define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \ 
LOADREGS_##nr(args)       \ 
asm volatile (       \ 
"call *%%gs:%P2"       \ 
: "=a" (resultvar)       \ 
: "a" (__NR_##name), "i" (offsetof (tcbhead_t, sysinfo))  \ 
    ASMARGS_##nr(args) : "memory", "cc") 

अगर मैं अच्छी तरह से समझ इस कोड, LOADREGS _ ## एन.आर. (args) मैक्रो लोड रजिस्टरों EBX में तर्क, ECX, EDX, ईएसआई, EDX और ईबीपी।

sysdeps/यूनिक्स/SysV/linux/i386/sysdep.h

# define LOADREGS_0() 
# define ASMARGS_0() 
# define LOADREGS_1(arg1) \ 
    LOADREGS_0() 
# define ASMARGS_1(arg1) \ 
    ASMARGS_0(), "b" ((unsigned int) (arg1)) 
# define LOADREGS_2(arg1, arg2) \ 
    LOADREGS_1 (arg1) 
# define ASMARGS_2(arg1, arg2) \ 
    ASMARGS_1 (arg1), "c" ((unsigned int) (arg2)) 
# define LOADREGS_3(arg1, arg2, arg3) \ 
    LOADREGS_2 (arg1, arg2) 
# define ASMARGS_3(arg1, arg2, arg3) \ 
    ASMARGS_2 (arg1, arg2), "d" ((unsigned int) (arg3)) 
# define LOADREGS_4(arg1, arg2, arg3, arg4) \ 
    LOADREGS_3 (arg1, arg2, arg3) 
# define ASMARGS_4(arg1, arg2, arg3, arg4) \ 
    ASMARGS_3 (arg1, arg2, arg3), "S" ((unsigned int) (arg4)) 
# define LOADREGS_5(arg1, arg2, arg3, arg4, arg5) \ 
    LOADREGS_4 (arg1, arg2, arg3, arg4) 
# define ASMARGS_5(arg1, arg2, arg3, arg4, arg5) \ 
    ASMARGS_4 (arg1, arg2, arg3, arg4), "D" ((unsigned int) (arg5)) 
# define LOADREGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ 
    register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); \ 
    LOADREGS_5 (arg1, arg2, arg3, arg4, arg5) 
# define ASMARGS_6(arg1, arg2, arg3, arg4, arg5, arg6) \ 
    ASMARGS_5 (arg1, arg2, arg3, arg4, arg5), "r" (_a6) 
#endif /* GCC 5 */ 
    enter code here 

कहां है कोड है जो रजिस्टरों EBX, ECX, EDX, ईएसआई, EDX और ईबीपी में तर्क लोड? यह उपरोक्त कोड है? मैं कार्यान्वयन को समझ नहीं पा रहा हूं। निम्नलिखित कोड ईबीएक्स रजिस्टर में 6 वें तर्क को लोड करते हैं?

register unsigned int _a6 asm ("ebp") = (unsigned int) (arg6); 

क्या इस कोड को करता है:

ASMARGS_0(), "b" ((unsigned int) (arg1)) 

यह EBX में पहला तर्क रजिस्टर लोड करता है?

फिर "कॉल * %% जीएस:% पी 2" वीडीएसओ कोड पर जाएं? यह कोड "कॉल * जीएस: 0x10" से मेल खाता है?

हां, तो लिखने syscall के लिए इस निम्न आरेख, यह अच्छा है ?:

write(1, "A", 1) -----> LIBC -----> VDSO -----> KERNEL 
          load reg   ? 
         jump to vdso 
|---------------------------------------------------|--------------| 
     user land          kernel land 

मैं VDSO उपयोगिता नहीं समझती! vdso syscall विधि (sysenter या int 0x80) का चयन करें।

आपकी मदद के लिए अग्रिम धन्यवाद। और खेद है कि मेरी inglish बहुत बुरा है।

+0

ग्लिबक उनकी घुलनशील अमूर्त परत के कारण बेहद जटिल है। मैं आपको पहले एक सरल libc देखने के लिए सलाह देते हैं। – fuz

+0

एक सरल libc को समझना बहुत आसान है, syscall तर्क रजिस्टरों में स्टोर होते हैं और int 0x80 या sysenter निर्देश को कर्नेल मोड में बदलने के लिए निष्पादित किया जाता है। – tutuen

+0

@tutuen क्या आप किसी को वीडीएसओ या उस विधि को समझाने के लिए ढूंढ रहे हैं जिसके द्वारा ग्लिबक इसके साथ बातचीत करता है? यदि आप सिर्फ वीडीएसओ की व्याख्या चाहते हैं, तो यह प्रदान करना आसान होगा। –

उत्तर

2

ग्लिब के सिस्कोल में शामिल मैक्रोज़ एक्ज़िट सिस्कोल के उदाहरण के लिए निम्न की तरह कुछ विस्तारित होंगे।

LOADREGS_1(args) 
asm volatile (
"call *%%gs:%P2" 
: "=a" (resultvar) 
: "a" (__NR_exit), "i" (offsetof (tcbhead_t, sysinfo)) 
    ASMARGS_1(args) : "memory", "cc") 

LOADREGS_1(args)LOADREGS_0() करने का विस्तार होगा, जो कुछ भी नहीं करने के लिए विस्तार होगा - LOADREGS_*(...) केवल जब अधिक पैरामीटर प्रदान की जाती हैं रजिस्टरों को समायोजित करने की जरूरत है।

ASMARGS_1(args)ASMARGS_0(), "b" ((unsigned int) (arg1)) तक विस्तारित होगा, जो , "b" ((unsigned int) (arg1) तक विस्तारित होगा।

__NR_exit x86 पर 1 है।

जैसे, कोड की तरह कुछ करने के लिए विस्तार होगा:

asm volatile (
"call *%%gs:%P2" 
: "=a" (resultvar) 
: "a" (1), "i" (offsetof (tcbhead_t, sysinfo)) 
, "b" ((unsigned int) (arg1) : "memory", "cc") 

ASMARGS_* वास्तव में निष्पादित नहीं कोड से प्रति - वे सुनिश्चित करने के लिए gcc करने के लिए निर्देशों रहे हैं कि निश्चित मूल्यों (जैसे (unsigned int) (arg1) के रूप में) कुछ रजिस्टरों में हैं (जैसे b, उर्फ ​​ebx)। इस प्रकार, पैरामीटर का संयोजन asm volatile (जो निश्चित रूप से एक फ़ंक्शन नहीं है, लेकिन केवल एक जीसीसी निर्मित है) निर्दिष्ट करें कि gcc को सिस्कल के लिए तैयार होना चाहिए और सिस्कल पूर्ण होने के बाद इसे कैसे जारी रखना चाहिए।

अब, उत्पन्न विधानसभा कुछ इस तरह दिखेगा:

; set up other registers... 
movl $1, %eax 
call *%gs:0x10 
; tear down 

%gs एक खंड रजिस्टर कि संदर्भ धागे की स्थानीय भंडारण है - विशेष रूप से, glibc किसी सहेजे गए मूल्य कि VDSO, की ओर इशारा करता संदर्भित कर रहा है जो यह वहां संग्रहीत किया गया जब उसने पहली बार ईएलएफ शीर्षकों को पार्स किया जिसने उसे बताया कि वीडीएसओ कहाँ था।

कोड कोड VDSO में प्रवेश करने के बाद, हम नहीं जानते कि वास्तव में क्या होता है - यह कर्नेल संस्करण के आधार पर भिन्न होता है - लेकिन हम जानते हैं कि यह एक सिस्कोल चलाने के लिए सबसे कुशल उपलब्ध तंत्र का उपयोग करता है, जैसे sysenter निर्देश या int 0x80 निर्देश।

write(1, "A", 1) -----> LIBC -----> VDSO -----> KERNEL 
          load reg   ? 
         jump to vdso 
|---------------------------------------------------|--------------| 
     user land          kernel land 

यहाँ, विशेष रूप से एक पैरामीटर syscalls के लिए, VDSO में कॉल करने के लिए कोड का एक सरल उदाहरण है एक पुस्तकालय है कि मैं libsyscall कहा जाता है को बनाए रखने से:

तो, हाँ, अपने चित्र सटीक है

_lsc_syscall1: 
    xchgl 8(%esp), %ebx 
    movl 4(%esp), %eax 
    call *_lsc_vdso_ptr(,1) 
    movl 8(%esp), %ebx 
    # pass %eax out 
    ret 

यह बस स्टैक से पैरामीटर में पैरामीटर ले जाता है, वीडीएसओ में मेमोरी से लोड सूचक के माध्यम से कॉल करता है, अन्य रजिस्टरों को उनके पिछले राज्य में पुनर्स्थापित करता है, और सिस्कल का परिणाम देता है।

संबंधित मुद्दे