国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Linux > 正文

淺析基于ARM的Linux下的系統(tǒng)調用的實現(xiàn)

2024-06-28 13:25:04
字體:
來源:轉載
供稿:網友
淺析基于ARM的linux下的系統(tǒng)調用的實現(xiàn)

在Linux下系統(tǒng)調用是用軟中斷實現(xiàn)的,下面以一個簡單的open例子簡要分析一下應用層的open是如何調用到內核中的sys_open的。

t8.c

   1:  #include <stdio.h>
   2:  #include <sys/types.h>
   3:  #include <sys/stat.h>
   4:  #include <fcntl.h>
   5:  
   6:  int main(int argc, const char *argv[])
   7:  {
   8:      int fd;
   9:  
  10:      fd = open(".", O_RDWR);
  11:  
  12:      close(fd);
  13:      return 0;
  14:  }

這里需要注意的是:open是C庫提供的庫函數(shù),并不是系統(tǒng)調用,系統(tǒng)調用時在內核空間的,應用空間無法直接調用。在《Linux內核設計與實現(xiàn)》中說:要訪問系統(tǒng)調用(在Linux中常稱作syscall),通常通過C庫中定義的函數(shù)調用來進行。

將t8.c進行靜態(tài)編譯,然后反匯編,看一下是如何調用open的?

   1:  arm-linux-gcc t8.c --static
   2:  arm-linux-objdump -D a.out >a.dis

下面我們截取a.dis中的一部分進行說明:

   1:  ......
   2:  00008228 <main>:
   3:      8228:   e92d4800    push    {fp, lr}
   4:      822c:   e28db004    add fp, sp, #4  ; 0x4
   5:      8230:   e24dd010    sub sp, sp, #16 ; 0x10
   6:      8234:   e50b0010    str r0, [fp, #-16]
   7:      8238:   e50b1014    str r1, [fp, #-20]
   8:      823c:   e59f0028    ldr r0, [pc, #40]   ; 826c <main+0x44>
   9:      8240:   e3a01002    mov r1, #2  ; 0x2   ;  #define  O_RDWR  00000002 
  10:      8244:   eb002e7d    bl  13c40 <__libc_open>
  11:      8248:   e1a03000    mov r3, r0
  12:      824c:   e50b3008    str r3, [fp, #-8]
  13:      8250:   e51b0008    ldr r0, [fp, #-8]
  14:      8254:   eb002e9d    bl  13cd0 <__libc_close>
  15:      8258:   e3a03000    mov r3, #0  ; 0x0
  16:      825c:   e1a00003    mov r0, r3
  17:      8260:   e24bd004    sub sp, fp, #4  ; 0x4
  18:      8264:   e8bd4800    pop {fp, lr}
  19:      8268:   e12fff1e    bx  lr
  20:      826c:   00064b8c    .Word   0x00064b8c
  21:  ......
  22:  00013c40 <__libc_open>:
  23:     13c40:   e51fc028    ldr ip, [pc, #-40]  ; 13c20 <___fxstat64+0x50>
  24:     13c44:   e79fc00c    ldr ip, [pc, ip]
  25:     13c48:   e33c0000    teq ip, #0  ; 0x0
  26:     13c4c:   1a000006    bne 13c6c <__libc_open+0x2c>
  27:     13c50:   e1a0c007    mov ip, r7
  28:     13c54:   e3a07005    mov r7, #5  ; 0x5   
  #在arch/arm/include/asm/unistd.h中:#define __NR_open  (__NR_SYSCALL_BASE+5)
                    其中,__NR_OABI_SYSCALL_BASE是0
  29:     
13c58: ef000000 svc 0x00000000 #產生軟中斷
  30:     13c5c:   e1a0700c    mov r7, ip
  31:     13c60:   e3700a01    cmn r0, #4096   ; 0x1000
  32:     13c64:   312fff1e    bxcc    lr
  33:     13c68:   ea0008d4    b   15fc0 <__syscall_error>
  34:  ......

通過上面的代碼注釋,可以看到,系統(tǒng)調用sys_open的系統(tǒng)調用號是5,將系統(tǒng)調用號存放到寄存器R7當中,然后應用程序通過svc 0x00000000產生軟中斷,陷入內核空間。

也許會好奇,ARM軟中斷不是用SWI嗎,這里怎么變成了SVC了,請看下面一段話,是從ARM官網copy的:

SVC

超級用戶調用。 語法

SVC{cond} #immed

其中:

cond

是一個可選的條件代碼(請參閱條件執(zhí)行)。 immed

是一個表達式,其取值為以下范圍內的一個整數(shù):

在 ARM 指令中為 0 到 224–1(24 位值)

在 16 位 Thumb 指令中為 0-255(8 位值)。

用法

SVC 指令會引發(fā)一個異常。 這意味著處理器模式會更改為超級用戶模式,CPSR 會保存到超級用戶模式 SPSR,并且執(zhí)行會跳轉到 SVC 向量(請參閱《開發(fā)指南》中的第 6 章 處理處理器異常)。

處理器會忽略 immed。 但異常處理程序會獲取它,借以確定所請求的服務。 Note

作為 ARM 匯編語言開發(fā)成果的一部分,SWI 指令已重命名為 SVC。 在此版本的 RVCT 中,SWI 指令反匯編為 SVC,并提供注釋以指明這是以前的 SWI。 條件標記

此指令不更改標記。 體系結構

此 ARM 指令可用于所有版本的 ARM 體系結構。

在基于ARM的Linux中,異常向量表已經被放置在了0xFFFF0000這個位置。這個過程的完成:

start_kernel ---> setup_arch ---> early_trap_init

   1:  void __init early_trap_init(void)
   2:  {
   3:      unsigned long vectors = CONFIG_VECTORS_BASE; // 就是0xFFFF0000
   4:      extern char __stubs_start[], __stubs_end[];
   5:      extern char __vectors_start[], __vectors_end[];
   6:      extern char __kuser_helper_start[], __kuser_helper_end[];
   7:      int kuser_sz = __kuser_helper_end - __kuser_helper_start;
   8:  
   9:      /*
  10:       * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
  11:       * into the vector page, mapped at 0xffff0000, and ensure these
  12:       * are visible to the instruction stream.
  13:       */
  14:      memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
  15:      memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
  16:      memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
  17:  
  18:      /*
  19:       * Copy signal return handlers into the vector page, and
  20:       * set sigreturn to be a pointer to these.
  21:       */
  22:      memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,
  23:             sizeof(sigreturn_codes));
  24:  
  25:      flush_icache_range(vectors, vectors + PAGE_SIZE);
  26:      modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
  27:  }

關于上面這個函數(shù)的詳細解釋,參見:

http://www.CUOXin.com/pengdonglin137/p/3603549.html

把異常中斷向量表的位置設置為0xffff0000的話,需要修改協(xié)處理器CP15的寄存器C1的第13位,將其設置為1。以Tq2440的提供的內核2.6.30.4為例看一下:

arch/arm/kernel/head.S

   1:      adr    lr, __enable_mmu        @ return (PIC) address
   2:      add    pc, r10, #PROCINFO_INITFUNC

其中,PROCINFO_INITFUNC的值是16,r10的值是__arm920_proc_info的地址:

   1:  __arm920_proc_info:
   2:      .long    0x41009200
   3:      .long    0xff00fff0
   4:      .long   PMD_TYPE_SECT | /
   5:          PMD_SECT_BUFFERABLE | /
   6:          PMD_SECT_CACHEABLE | /
   7:          PMD_BIT4 | /
   8:          PMD_SECT_AP_WRITE | /
   9:          PMD_SECT_AP_READ
  10:      .long   PMD_TYPE_SECT | /
  11:          PMD_BIT4 | /
  12:          PMD_SECT_AP_WRITE | /
  13:          PMD_SECT_AP_READ
  14:      b    __arm920_setup
  15:      .long    cpu_arch_name
  16:      .long    cpu_elf_name
  17:       ......
  18:      .size    __arm920_proc_info, . - __arm920_proc_info

看一下__arm920_setup的實現(xiàn)(proc-arm920.S (arch/arm/mm)):

   1:      .type    __arm920_setup, #function
   2:  __arm920_setup:
   3:      mov    r0, #0
   4:      mcr    p15, 0, r0, c7, c7        @ invalidate I,D caches on v4
   5:      mcr    p15, 0, r0, c7, c10, 4        @ drain write buffer on v4
   6:  #ifdef CONFIG_MMU
   7:      mcr    p15, 0, r0, c8, c7        @ invalidate I,D TLBs on v4
   8:  #endif
   9:      adr    r5, arm920_crval
  10:      ldmia    r5, {r5, r6}            @ 參看以下下面的arm920_crval的實現(xiàn),本句話執(zhí)行完后r5和r6分別為:0x3f3f和0x3135
  11:      mrc    p15, 0, r0, c1, c0        @ get control register v4   獲取協(xié)處理器p15的寄存器才c1
  12:      
bic r0, r0, r5
  13:      
orr r0, r0, r6 @ 我們只關注第13位,這里將r0的第13位設置為了1
  14:      
mov pc, lr
  15:      .size    __arm920_setup, . - __arm920_setup
  16:  
  17:      /*
  18:       *  R
  19:       * .RVI ZFRS BLDP WCAM
  20:       * ..11 0001 ..11 0101
  21:       * 
  22:       */
  23:      .type    arm920_crval, #object
  24:  arm920_crval:
  25:      crval    clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130

在看一下crval的實現(xiàn)(proc-macros.S (arch/arm/mm)):

   1:      .macro    crval, clear, mmuset, ucset
   2:  #ifdef CONFIG_MMU
   3:      .word    /clear
   4:      .word    /mmuset
   5:  #else
   6:      .word    /clear
   7:      .word    /ucset
   8:  #endif
   9:      .endm

在__arm920_setup中執(zhí)行完 mov pc, lr后,便跳入了下面的語句:

   1:  __enable_mmu:
   2:  #ifdef CONFIG_ALIGNMENT_TRAP
   3:      orr    r0, r0, #CR_A
   4:  #else
   5:      bic    r0, r0, #CR_A
   6:  #endif
   7:  #ifdef CONFIG_CPU_DCACHE_DISABLE
   8:      bic    r0, r0, #CR_C
   9:  #endif
  10:  #ifdef CONFIG_CPU_BPREDICT_DISABLE
  11:      bic    r0, r0, #CR_Z
  12:  #endif
  13:  #ifdef CONFIG_CPU_ICACHE_DISABLE
  14:      bic    r0, r0, #CR_I
  15:  #endif
  16:      mov    r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | /
  17:                domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | /
  18:                domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | /
  19:                domain_val(DOMAIN_IO, DOMAIN_CLIENT))
  20:      mcr    p15, 0, r5, c3, c0, 0        @ load domain access register
  21:      mcr    p15, 0, r4, c2, c0, 0        @ load page table pointer
  22:      b    __turn_mmu_on
  23:  ENDPROC(__enable_mmu)

看一下__turn_mmu_on的實現(xiàn)(head.S (arch/arm/kernel)):

   1:      .align    5
   2:  __turn_mmu_on:
   3:      mov    r0, r0
   4:      mcr    p15, 0, r0, c1, c0, 0        @ write control reg
   5:      mrc    p15, 0, r3, c0, c0, 0        @ read id reg
   6:      mov    r3, r3
   7:      mov    r3, r3
   8:      mov    pc, r13
   9:  ENDPROC(__turn_mmu_on)

在__turn_mmu_on中,將寄存器r0的值寫到了cp15協(xié)處理器的寄存器C1中。到這里便完成了將異常中斷向量表的位置放到了0xffff0000.

說完異常向量表的位置,接下來看看軟中斷的實現(xiàn)。

ARM提供的中斷類型:

image

ARM的異常處理模型:

image

entry-armv.S (arch/arm/kernel)

   1:  .LCvswi:
   2:     
.word vector_swi
   3:  
   4:      .globl    __stubs_end
   5:  __stubs_end:
   6:  
   7:      .equ    stubs_offset, __vectors_start + 0x200 - __stubs_start
   8:  
   9:      .globl    __vectors_start
  10:  __vectors_start:
  11:      swi    SYS_ERROR0
  12:      b    vector_und + stubs_offset
  13:      ldr    pc, .LCvswi + stubs_offset     @發(fā)生軟中斷后先跳到這里
  14:      b    vector_pabt + stubs_offset
  15:      b    vector_dabt + stubs_offset
  16:      b    vector_addrexcptn + stubs_offset
  17:      b    vector_irq + stubs_offset
  18:      b    vector_fiq + stubs_offset
  19:  
  20:      .globl    __vectors_end
  21:  __vectors_end:
  22:  
  23:      .data
  24:  
  25:      .globl    cr_alignment
  26:      .globl    cr_no_alignment
  27:  cr_alignment:
  28:      .space    4
  29:  cr_no_alignment:
  30:      .space    4

接下來看一下vector_swi的實現(xiàn),根據(jù)實際的宏定義進行了簡化

   1:  ENTRY(vector_swi)
   2:      sub    sp, sp, #S_FRAME_SIZE
   3:      stmia    sp, {r0 - r12}            @ Calling r0 - r12
   4:      add    r8, sp, #S_PC
   5:      stmdb    r8, {sp, lr}^            @ Calling sp, lr
   6:      mrs    r8, spsr            @ called from non-FIQ mode, so ok.
   7:      str    lr, [sp, #S_PC]            @ Save calling PC
   8:      str    r8, [sp, #S_PSR]        @ Save CPSR
   9:      str    r0, [sp, #S_OLD_R0]        @ Save OLD_R0
  10:      zero_fp
  11:  
  12:      /*
  13:       * Get the system call number.
  14:       */
  15:  
  16:      /*
  17:       * If we have CONFIG_OABI_COMPAT then we need to look at the swi
  18:       * value to determine if it is an EABI or an old ABI call.
  19:       */
  20:      ldr    r10, [lr, #-4]   
            @ get SWI instruction  r10中存放的就是引起軟中斷的那條指令的機器碼
              發(fā)生軟中斷的時候,系統(tǒng)自動將PC-4存放到了lr寄存器,由于是三級流水,
              并且是ARM狀態(tài),還需要減4才能得到發(fā)生軟中斷的那條指令的機器碼所在的地址
  21:    A710(    and    ip, r10, #0x0f000000        @ check for SWI        )
  22:    A710(    teq    ip, #0x0f000000                        )
  23:    A710(    bne    .Larm710bug                        )
  24:  
  25:      ldr    ip, __cr_alignment
  26:      ldr    ip, [ip]
  27:      mcr    p15, 0, ip, c1, c0        @ update control register
  28:      enable_irq   @在發(fā)生中斷的時候,相應的中斷線在在所有CPU上都會被屏蔽掉
  29:  
  30:      
get_thread_info tsk @ 參看下面的介紹

31: adr tbl, sys_call_table

@ load syscall table pointer 此時tbl(r8)中存放的就是sys_call_table的起始地址

  32:      ldr    ip, [tsk, #TI_FLAGS]        @ check for syscall tracing
  33:  
  34:      /*
  35:       * If the swi argument is zero, this is an EABI call and we do nothing.
  36:       *
  37:       * If this is an old ABI call, get the syscall number into scno and
  38:       * get the old ABI syscall table address.
  39:       */
  40:      bics    r10, r10, #0xff000000
  41:      eorne    scno, r10, #__NR_OABI_SYSCALL_BASE
  42:      ldr
ne
    tbl, =sys_oabi_call_table
  43:  
  44:      stmdb    sp!, {r4, r5}            @ push fifth and sixth args
  45:      tst    ip, #_TIF_SYSCALL_TRACE        @ are we tracing syscalls?
  46:      bne    __sys_trace
  47:  
  48:      cmp    scno, #NR_syscalls        @ check upper syscall limit
  49:      adr    lr, ret_fast_syscall        @ return address
  50:      
ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
  51:  
  52:      add    r1, sp, #S_OFF
  53:  2:    mov    why, #0                @ no longer a real syscall
  54:      cmp    scno, #(__ARM_NR_BASE - __NR_SYSCALL_BASE)
  55:      eor    r0, scno, #__NR_SYSCALL_BASE    @ put OS number back
  56:      bcs    arm_syscall
  57:      b    sys_ni_syscall            @ not private func
  58:  ENDPROC(vector_swi)

entry-common.S (arch/arm/kernel下面是entry-header.S (arch/arm/kernel)的部分內容:

   1:  /*
   2:   * These are the registers used in the syscall handler, and allow us to
   3:   * have in theory up to 7 arguments to a function - r0 to r6.
   4:   *
   5:   * r7 is reserved for the system call number for thumb mode.
   6:   *
   7:   * Note that tbl == why is intentional.
   8:   *
   9:   * We must set at least "tsk" and "why" when calling ret_with_reschedule.
  10:   */
  11:  scno    .req    r7        @ syscall number
  12:  tbl    .req    r8        @ syscall table pointer
  13:  why    .req    r8        @ Linux syscall (!= 0)
  14:  tsk    .req    r9        @ current thread_info

.req 是偽匯編,以 scno .req r7 為例,表示scno是寄存器r7的別名。

  • get_thread_info tsk

其中,tsk是寄存器r9的別名,get_thread_info是一個宏定義,如下:

   1:      .macro    get_thread_info, rd
   2:      mov    /rd, sp, lsr #13
   3:      mov    /rd, /rd, lsl #13
   4:      .endm

即:將sp進行8KB對齊后的值賦給寄存器r9,什么意思?

這個就涉及到Linux的內核棧了。Linux為每個進程都分配了一個8KB的內核棧,在內核棧的尾端存放有關于這個進程的struct therad_info結構:

   1:  struct thread_info {
   2:      unsigned long        flags;        /* low level flags */
   3:      int            preempt_count;    /* 0 => preemptable, <0 => bug */
   4:      mm_segment_t        addr_limit;    /* address limit */
   5:      struct task_struct    *task;        /* main task structure */
   6:      struct exec_domain    *exec_domain;    /* execution domain */
   7:      __u32            cpu;        /* cpu */
   8:      __u32            cpu_domain;    /* cpu domain */
   9:      struct cpu_context_save    cpu_context;    /* cpu context */
  10:      __u32            syscall;    /* syscall number */
  11:      __u8            used_cp[16];    /* thread used copro */
  12:      unsigned long        tp_value;
  13:      struct crunch_state    crunchstate;
  14:      union fp_state        fpstate __attribute__((aligned(8)));
  15:      union vfp_state        vfpstate;
  16:  #ifdef CONFIG_ARM_THUMBEE
  17:      unsigned long        thumbee_state;    /* ThumbEE Handler Base register */
  18:  #endif
  19:      struct restart_block    restart_block;
  20:  };

通過上面的操作,寄存器r9中就是這個進程的thread_info結構的起始地址。

  • sys_call_table

entry-common.S (arch/arm/kernel)

   1:      .type    sys_call_table, #object
   2:  ENTRY(sys_call_table)
   3:  #include "calls.S"
   4:  #undef ABI
   5:  #undef OBSOLETE

其中,calls.S的內容如下:

   1:  /*
   2:   *  linux/arch/arm/kernel/calls.S
   3:   *
   4:   *  Copyright (C) 1995-2005 Russell King
   5:   *
   6:   * This program is free software; you can redistribute it and/or modify
   7:   * it under the terms of the GNU General Public License version 2 as
   8:   * published by the Free Software Foundation.
   9:   *
  10:   *  This file is included thrice in entry-common.S
  11:   */
  12:  /* 0 */        CALL(sys_restart_syscall)
  13:          CALL(sys_exit)
  14:          CALL(sys_fork_wrapper)
  15:          CALL(sys_read)
  16:          CALL(sys_write)
  17:  /* 5 */        CALL(sys_open)
  18:          CALL(sys_close)
  19:          CALL(sys_ni_syscall)        /* was sys_waitpid */
  20:          CALL(sys_creat)
  21:          CALL(sys_link)
  22:  /* 10 */    CALL(sys_unlink)
  23:          CALL(sys_execve_wrapper)
  24:          CALL(sys_chdir)
  25:          CALL(OBSOLETE(sys_time))    /* used by libc4 */
  26:          CALL(sys_mknod)
  27:  ......
  28:  /* 355 */    CALL(sys_signalfd4)
  29:          CALL(sys_eventfd2)
  30:          CALL(sys_epoll_create1)
  31:          CALL(sys_dup3)
  32:          CALL(sys_pipe2)
  33:  /* 360 */    CALL(sys_inotify_init1)
  34:          CALL(sys_preadv)
  35:          CALL(sys_pwritev)
  36:  #ifndef syscalls_counted
  37:  .equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
  38:  #define syscalls_counted
  39:  #endif
  40:  .rept syscalls_padding
  41:          CALL(sys_ni_syscall)
  42:  .endr

關于這個部分的更多介紹參見:

http://www.CUOXin.com/pengdonglin137/p/3714981.html

  • bics r10, r10, #0xff000000

執(zhí)行這個操作的時候,r10中存放的是SWI instruction,在我們的例子中就是(a.dis):

image

即:r10 為 0xEF000000

顯然,bics這條指令下面的兩個語句由于條件不成立,無法獲得執(zhí)行。這條指令的作用是獲得系統(tǒng)調用號

可以參考這個手冊,看一下svc執(zhí)行的格式:

http://files.CUOXin.com/pengdonglin137/DUI0203IC_rvct_developer_guide.pdf

image

可以看到,[23:0]存放的就是svc指令后面的那個立即數(shù),也即系統(tǒng)調用號。

不過需要注意的是:我們這里并沒有這樣做,我們的做法是(a.dis中可以看到):

image

使用的是svc 0,后面跟的并不是系統(tǒng)調用號,而是0,這里把系統(tǒng)調用號存放在了寄存器r7中(a.dis中):

image

可以看到,由于使用的sys_open系統(tǒng)調用,所以把它的系統(tǒng)調用號5存放到了寄存器r7當中

  • ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine

這里的scno是就是寄存器r7的別名,它的值是sys_open的系統(tǒng)調用號5,由于在calls.S中每個系統(tǒng)調用標號占用4個字節(jié),所以這個將scno的值乘以4然后再加上tbl,tbl是系統(tǒng)調用表sys_call_table的基地址。然后就跳入開始執(zhí)行sys_open了。

asmlinkage long sys_open(const char __user *filename,                int flags, int mode);

那么sys_open在哪呢?在內核源碼中直接搜索sys_open,無法搜到它的實現(xiàn)代碼,實際上它是在fs/open.c中實現(xiàn)的:

   1:  SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, int, mode)
   2:  {
   3:      long ret;
   4:  
   5:      if (force_o_largefile())
   6:          flags |= O_LARGEFILE;
   7:  
   8:      ret = do_sys_open(AT_FDCWD, filename, flags, mode);
   9:      /* avoid REGPARM breakage on x86: */
  10:      asmlinkage_protect(3, ret, filename, flags, mode);
  11:      return ret;
  12:  }

其中SYSCALL_DEFINE3是一個宏:

syscalls.h (include/linux)

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

SYSCALL_DEFINEx也是一個宏:

syscalls.h (include/linux)

#define SYSCALL_DEFINEx(x, sname, ...)                /    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

__SYSCALL_DEFINEx仍然是個宏:

syscalls.h (include/linux)

#define __SYSCALL_DEFINEx(x, name, ...)                    /    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

所以展開后的結果就是:

asmlinkage long sys_open(__SC_DECL3(__VA_ARGS__))

其中,__SC_DECL3定義如下:

syscalls.h (include/linux)

   1:  #define __SC_DECL1(t1, a1)    t1 a1
   2:  #define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
   3:  #define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)

所以最終的結果如下:

   1:  asmlinkage long sys_open(const char __user *filename, int flags, int mode)
   2:  {
   3:      long ret;
   4:  
   5:      if (force_o_largefile())
   6:          flags |= O_LARGEFILE;
   7:  
   8:      ret = do_sys_open(AT_FDCWD, filename, flags, mode);
   9:      /* avoid REGPARM breakage on x86: */
  10:      asmlinkage_protect(3, ret, filename, flags, mode);
  11:      return ret;
  12:  
  13:  }

關于sys_open本身的實現(xiàn)這里就不深入分析了。

接下來看一下返回。

  • adr lr, ret_fast_syscall @ return address

當sys_open中return后,便跳入ret_fast_syscall處開始執(zhí)行:

   1:  /*
   2:   * This is the fast syscall return path.  We do as little as
   3:   * possible here, and this includes saving r0 back into the SVC
   4:   * stack.
   5:   */
   6:  ret_fast_syscall:
   7:   UNWIND(.fnstart    )
   8:   UNWIND(.cantunwind    )
   9:      disable_irq                @ disable interrupts
  10:      
ldr r1, [tsk, #TI_FLAGS] @將thread_info中的flags成員存放到r1中
  11:      tst    r1, #_TIF_WORK_MASK
  12:      bne    fast_work_pending  
  13:  
  14:      /* perform architecture specific actions before user return */
  15:      arch_ret_to_user r1, lr
  16:  
  17:      @ fast_restore_user_regs
  18:      ldr    r1, [sp, #S_OFF + S_PSR]    @ get calling cpsr
  19:      ldr    lr, [sp, #S_OFF + S_PC]!    @ get pc
  20:      msr    spsr_cxsf, r1            @ save in spsr_svc
  21:      ldmdb    sp, {r1 - lr}^            @ get calling r1 - lr
  22:      mov    r0, r0
  23:      add    sp, sp, #S_FRAME_SIZE - S_PC
  24:      movs    pc, lr                @ return & move spsr_svc into cpsr
  25:   UNWIND(.fnend        )
  26:  
  27:  /*
  28:   * Ok, we need to do extra processing, enter the slow path.
  29:   */
  30:  fast_work_pending:
  31:      str    r0, [sp, #S_R0+S_OFF]!        @ returned r0
  32:  work_pending:
  33:      tst    r1, #_TIF_NEED_RESCHED @判斷是否需要進行進程調度
  34:      bne    work_resched
  35:      tst    r1, #_TIF_SIGPENDING
  36:      beq    no_work_pending
  37:      mov    r0, sp                @ 'regs'
  38:      mov    r2, why                @ 'syscall'
  39:      bl    do_notify_resume
  40:      b    ret_slow_syscall        @ Check work again
  41:  
  42:  
work_resched:
  43:      bl    schedule
  44:  /*
  45:   * "slow" syscall return path.  "why" tells us if this was a real syscall.
  46:   */
  47:  ENTRY(ret_to_user)
  48:  ret_slow_syscall:
  49:      disable_irq                @ disable interrupts
  50:      ldr    r1, [tsk, #TI_FLAGS]
  51:      tst    r1, #_TIF_WORK_MASK
  52:      bne    work_pending
  53:  no_work_pending:
  54:      /* perform architecture specific actions before user return */
  55:      arch_ret_to_user r1, lr
  56:  
  57:      @ slow_restore_user_regs
  58:      ldr    r1, [sp, #S_PSR]        @ get calling cpsr
  59:      ldr    lr, [sp, #S_PC]!        @ get pc
  60:      msr    spsr_cxsf, r1            @ save in spsr_svc
  61:      ldmdb    sp, {r0 - lr}^            @ get calling r0 - lr
  62:      mov    r0, r0
  63:      add    sp, sp, #S_FRAME_SIZE - S_PC
  64:      movs    pc, lr                @ return & move spsr_svc into cpsr
  65:  ENDPROC(ret_to_user)

在返回的時候要看是否要進行進程調用。

image

先分析到這里。


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 沂水县| 临湘市| 陈巴尔虎旗| 石阡县| 双城市| 建水县| 体育| 封丘县| 吉林省| 永清县| 平潭县| 淄博市| 高要市| 新安县| 仁寿县| 忻城县| 沾化县| 阿拉善右旗| 舟山市| 天祝| 琼结县| 施甸县| 友谊县| 旌德县| 天全县| 丰宁| 贵德县| 肃北| 玛沁县| 武鸣县| 山西省| 来宾市| 双城市| 故城县| 深水埗区| 广西| 泰和县| 仪陇县| 奈曼旗| 虎林市| 静乐县|