使用者進程到系統調用

來源:互聯網
上載者:User


1.使用者進程使用如open();的C庫函數。

2從庫函數(open)中使用"int 0x80"或是syscall命令進入system_call。

glibc 中的部分源碼
//sysdeps/unix/sysv/linux/x86_64/sysdeps.h

INLINE_SYSCALL--->INTERNAL_SYSCALL--->INTERNAL_SYSCALL_NCS--->syscall.
# define INLINE_SYSCALL(name, nr, args...) \
  ({                                          \
    unsigned long int resultvar = INTERNAL_SYSCALL (name, , nr, args);          \
    if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (resultvar, ), 0))          \
      {                                          \
    __set_errno (INTERNAL_SYSCALL_ERRNO (resultvar, ));              \
    resultvar = (unsigned long int) -1;                      \
      }                                          \
    (long int) resultvar; })
    
# define INTERNAL_SYSCALL(name, err, nr, args...) \
  INTERNAL_SYSCALL_NCS (__NR_##name, err, nr, ##args)

  # define INTERNAL_SYSCALL_NCS(name, err, nr, args...) \
  ({                                          \
    unsigned long int resultvar;                          \
    LOAD_ARGS_##nr (args)                              \
    LOAD_REGS_##nr                                  \
    asm volatile (                                  \
    "syscall\n\t"                                  \//x86_64的關鍵指令syscall.
    : "=a" (resultvar)                                  \
    : "0" (name) ASM_ARGS_##nr : "memory", "cc", "r11", "cx");              \
    (long int) resultvar; })

有一個問題:在i386的CPU上,我們知道linux在初始化時為中斷號0x80準備了一個中斷處理函數(trap_init-->set_system_trap_gate(SYSCALL_VECTOR, &system_call);)。當發生int 0x80時,CPU通過一系列的動作(這個硬體動作,其它網文介紹很多),到達中斷處理函數。那麼在x86_64的CPU上,syscall指令能跳到哪去呢?CPU是如何處理這個指令的呢?需要OS為這個指令準備哪些資訊?還有它又是怎麼回來的?

3 CPU完成一系列切換的動作。

4.進入中斷處理函數,更準確的說法是進入核心。

在arch/x86/kernel/entry_64.S#455或是在arch/x86/kernel/entry_32.S#L498(在entry_32.s為例)

    

ENTRY(system_call)

 499        RING0_INT_FRAME                 # can't unwind into user space anyway

 500        pushl_cfi %eax                  # save orig_eax

 501        SAVE_ALL

 502        GET_THREAD_INFO(%ebp)

 503                                        # system call tracing in operation / emulation

 504        testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)

 505        jnz syscall_trace_entry

 506        cmpl $(nr_syscalls), %eax

 507        jae syscall_badsys

 508syscall_call:

 509        call *sys_call_table(,%eax,4)

 510        movl %eax,PT_EAX(%esp)          # store the return value

 511syscall_exit:

 512        LOCKDEP_SYS_EXIT

 513        DISABLE_INTERRUPTS(CLBR_ANY)    # make sure we don't miss an interrupt

 514                                        # setting need_resched or sigpending

 515                                        # between sampling and the iret

 516        TRACE_IRQS_OFF

 517        movl TI_flags(%ebp), %ecx

 518        testl $_TIF_ALLWORK_MASK, %ecx  # current->work

 519        jne syscall_exit_work

當進入了system_call之後。
SAVE_ALL:???
。。。。
進入sys_call_table.xxx 中。
sys_call_table的定義在哪裡,它的引用在哪裡?為什麼在核心和x86中的很多檔案中都有它????
sys_call_table的定義:(在  linux/arch/x86/kernel/syscall_table_32.S)。
    ENTRY(sys_call_table)

   2        .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */

   3        .long sys_exit

   4        .long ptregs_fork

   5        .long sys_read

   6        .long sys_write

   7        .long sys_open          /* 5 */

   8

這樣就可以找到核心定義的sys_function函數了。
5.運行各種各樣的系統調用的函數。 
那麼各種各樣的sys_function都是定義在哪裡呢?例:
SYSCALL_DEFINE3(semop, int, semid, struct sembuf __user *, tsops,unsigned, nsops)
{
函數實體。
。。。。。
。。。。。
}
在一些檔案中,我們可以找到以上這樣的語句。
在syscalls.h中定義如下:
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
它由一系列的宏,逐步定義的,如何做的??
這些宏的具體定義的內涵是什嗎?
SYSCALL_DEFINE3(semop,int,semid,......)這個宏,把"semop"的函數,定義成
sys_semop(int semid,struct sembuf __user* tsops,unsigned nsops);
這個sys_semop函數就是
sys_call_table中的一部分了。
這樣使用者進程在使用系統調用時,read,write,或是semget,semop時,就可以調用到相應的sys_xxxx函數了。
附:cond_syscall解釋/* * "Conditional" syscalls * * What we want is __attribute__((weak,alias("sys_ni_syscall"))), * but it doesn't work on all toolchains, so we just do it by hand */#ifndef cond_syscall#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")#endif

在sys_ni.c中:cond_syscall(sys_fanotify_mark);
cond_syscall定義如下:
/*
* "Conditional" syscalls
*
* What we want is __attribute__((weak,alias("sys_ni_syscall"))),
* but it doesn't work on all toolchains, so we just do it by hand */
#ifndef cond_syscall#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
#endif
asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")分析如下:以上嵌入式彙編翻譯成彙編代碼如下:
.weak    #x    .set   #x,sys_ni_syscall
以上的含義是:在編譯時間,告訴編譯器,當沒有符號x時,就用sys_ni_syscall這個符號來代替符號x.

 
在http://www.acsu.buffalo.edu/~charngda/cc.html中說明如下:
#pragma weak symbol1=symbol2     
Declare symbol1 as a weak alias of symbol2. Equivalently, one can use
#pragma weak symbol1=symbol2   定義 symbol1作為symbol2的弱別名,與如下代碼等效。
         __asm__(".weak symbol1"); //定義symbol1是弱符號。
        __asm__(".set symbol1,symbol2"); //把symbol1與symbol2聯絡起來。
A better way to achieve this is through the "weak, alias" function attributes.
還有一種更好的實現“弱,別名”函數屬性的方式。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.