详解Linux的系统调用(下)

一起学嵌入式 2023-12-19 08:48

扫描关注一起学嵌入式,一起学习,一起成长

大家好,今天分享Linux系统调用相关的知识,由于文章篇幅较长,《详解 Linux 的系统调用》分为上下两篇,本文为下篇。

上篇链接:详解 Linux 的系统调用 (上)

1.LINUX系统调用实现

linux系统调用分为3个部分:调用请求 ,响应请求 ,功能实现。

linux系统调用流程图如下:

系统调用提供给应用程序的调用请求接口,调用请求中执行了软中断的指令,应用程序使用调用请求后,处理器会产生一个中断,中断服务得到执行,中断服务根据调用号执行特定的功能实现函数。

2.调用请求

linux系统调用的第一部分是调用请求,调用请求作为系统调用提供给应用程序的接口,在linux系统调用的3部分中,应用程序只有使用调用请求的权限(其它两部分应用程序无法接触到),调用请求需要完成以下两个基本功能:

2.1接口函数

linux系统调用有四种调用请求方式:
1、使用 glibc 库函数。
2、使用 syscall函数。
3、通过linux系统调用宏。
4、使用软中断陷入。

以上这4种方法,每种方法的底层都会用到触发软中断指令。

1、使用 glibc 库函数

glibc是GNU 发布的开源的标准 C 库,glibc 为程序员提供丰富的 API(Application Programming Interface),除了字符串处理、数学运算等用户态服务之外,重要的是封装了操作系统提供的系统服务,即系统调用的封装(本质上还是执行的系统调用)。

系统调用和glibc提供的API的对应关系如下:
情形一:每一个系统调用对应了一个 glibc 库函数,如系统提供的打开文件系统调用 sys_open 对应的是 glibc 中的 open 函数。

情形二:单独的一个glibc 库函数 可能调用多个系统调用,如 glibc 提供的 printf 函数就会调用如 sys_open、sys_mmap、sys_write、sys_close 等等系统调用。

情形三:多个glibc 库函数 也可能只对应同一个系统调用,如glibc 下实现的 malloc、calloc、free 等函数用来分配和释放内存,都利用了内核的 sys_brk 的系统调用。

例如应用程序通过glibc 提供的chmod函数来改变文件的属性,示例代码如下:

#include
int main()
{
    int rc=chmod("./weiwei",0666);
    if(rc==-1)
        perror("chmod fail\n");
    else
        printf("chmod succeed\n");
    return 0;
}

chmod函数用于改变文件weiwei的属性,编译程序得到chmod.o执行文件,运行chmod.o后观察weiwei文件的属性,结果如下:

2、使用 syscall

使用glibc的方法有很多好处,glibc封装了操作系统提供的系统服务,程序员无需知道细节,如 chmod 系统调用号,程序员只需知道 glibc 提供的 API 的原型。其次使用glibc的方法具有更好的移植性,可以很轻松地植到其他平台

任何事物都有两面性,如果 glibc 没有封装某个内核提供的系统调用时,我们就没办法通过使用glibc的方法来调用该系统调用。假设我们自己通过编译内核增加了一个系统调用,这时 glibc 不可能有我们自己新增系统调用的封装 API。

在这种情况下,可以利用 glibc 提供的syscall 库函数直接调用。syscall是一个通过特定子功能号和特定参数调用汇编语言接口的库函数。该函数定义在 unistd.h 头文件中,函数原型如下:

long int syscall (long int sysno, ...)

sysno :为系统调用号,每个系统调用都有唯一的系统调用号来标识。
:可变长的参数,为系统调用所带的参数,不同的系统调用可带0~5个不等的参数。
返回值:该函数返回值为特定系统调用的返回值,如果系统调用失败则返回 -1。

例如应用程序通过 syscall函数来改变文件的属性,示例代码如下:

#include
#include
//syscall接口函数声明在头文件unistd.h中
#include
//SYS_chmod在头文件syscall.h中
int main()
{
    int rc=syscall(SYS_chmod,"./weiwei",0777);
    if(rc==-1)
        perror("SYS_chmod chmod fail\n");
    else
        printf("SYS_chmod chmod succeed\n");
    return 0;
}

syscall(SYS_chmod,“./weiwei”,0777)函数用于改变文件weiwei的属性,编译得到syschmod.o执行文件,运行syschmod.o后观察weiwei文件的属性,结果如下:

3、通过_syscall系统调用宏

Linux内核提供了一组宏,用于实现系统调用接口函数,实现系统调用后应用程序就可以使用该系统调用。这组宏是_syscalln(),其中n的范围从0到6,这组宏会设置好寄存器并调用软中断指令,_syscalln()宏如下:

_syscall0(),_syscall1(),_syscall2(),_syscall3(),_syscall4(),_syscall5(),_syscall6()。

宏名称字符串“syscall0”中的0表示无参数,“syscall1”中的1表示带1个参数,“syscall2”中的2表示带2个参数。如果系统调用带有1个参数,那么就应该使用宏_syscall1()。

以_syscall0()为例,_syscall0()为不带参数的系统调用宏函数,它以嵌入汇编的形式调用软中断指令int 0x80。

#define _syscall0(type,name) \
type name(void) \
 { \
 long __res; \
 __asm__ volatile ("int $0x80" \          // 调用系统中断0x80。
         : "=a" (__res) \                 // 返回值eax(__res)。
         : "0" (__NR_##name)); \          // 输入为系统中断调用号__NR_name。
 if (__res >= 0) \                        // 如果返回值>=0,则直接返回该值。
         return (type) __res; \
 errno = -__res; \                        // 否则置出错号,并返回-1。
 return -1; \
 }

假设我们要新增一个名为test系统调用,我们可以使用_syscall系统调用宏实现,假设test系统调用参数个数为0个,我们通过_syscall0(int, test)申请了一个新的系统调用。

我们通过_syscall0(int, test)声明一个系统调用,根据宏定义我们把_syscall0(int, test)这个宏展开并替代得到如下语句:

static inline int test(void)
{
long __res;

__asm__ volatile ("int $0x80" : "=a" (__res) : "0" (__NR_test));
if (__res >= 0)
        return (int) __res;
errno = -__res;
return -1;
}

_syscall0(int, test)实际上是声明了一个名为test的函数,声明函数后,应用程序就可以使用test这个系统调用了(当然还有内核相关代码需要实现),test系统调用示例代码如下:

#include
#include
//syscall接口函数声明在头文件unistd.h中
#include
//SYS_chmod在头文件syscall.h中
_syscall0(int, test);
int main()
{
    int rc=test();
    if(rc==-1)
        perror("test fail\n");
    else
        printf("test succeed\n");
    return 0;
}

4、通过软中断指令陷入

用户态程序通过软中断指令int 0x80 来陷入内核态,通过寄存器传递参数,eax 传递的是系统调用号,ebx、ecx、edx、esi和edi 来依次传递参数,当系统调用返回值存放在 eax 中。

以调用chmod修改文件属性为例,系统调用通过内联汇编实现,示例代码如下:

#include 
#include 
#include 
//SYS_chmod在头文件syscall.h中
#include 

int main()
{
    long rc;
    unsigned short mode = 0777;     
    char *file_name = "./weiwei";
 /*内联汇编 软中断指令 */
    asm(
            "int $0x80"
            : "=a" (rc)
            : "0" (SYS_chmod), "b" ((long)file_name), "c" ((long)mode)
    );     
    if (rc == -1)
       perror("SYS_chmod chmod fail\n");
    else
        printf("SYS_chmod chmod succeed\n");
    return 0;
}

2.2触发软中断

以上这4种方法,每种方法的底层都会用到触发软中断指令。系统调用的参数 由各通用寄存器传递,然后执行软中断指令(INT 0x80) ,处理器响应中断并开始执行中断服务程序,此时处理器模式变为特权模式。我们以glibc-2.23中的X86体系为例,下面分别讲述4中方法如何调用软中断指令。

1、glibc 库函数

glibc-2.23\sysdeps\unix\sysv\linux\generic中有chmod函数的定义,代码如下:

#include 
#include 
#include 
#include 
#include 

/* Change the protections of FILE to MODE.  */
int
__chmod (const char *file, mode_t mode)
{
  return INLINE_SYSCALL (fchmodat, 3, AT_FDCWD, file, mode);
}
weak_alias (__chmod, chmod)

INLINE_SYSCALL 宏在glibc-2.23\glibc-2.23\sysdeps\i386\sysdep.h中定义,代码如下:

# define INLINE_SYSCALL(name, nr, args...) \

  ({               \
    unsigned int resultvar = INTERNAL_SYSCALL (name, , nr, args);       \
    __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (resultvar, ))        \
    ? __syscall_error (-INTERNAL_SYSCALL_ERRNO (resultvar, ))        \
    : (int) resultvar; })

INTERNAL_SYSCALL 宏在glibc-2.23\glibc-2.23\sysdeps\i386\sysdep.h中定义,代码如下:

#define INTERNAL_SYSCALL(name, err, nr, args...) \
  ({               \
    register unsigned int resultvar;           \
    INTERNAL_SYSCALL_MAIN_##nr (name, err, args);         \
    (int) resultvar; })

INTERNAL_SYSCALL_MAIN_##nr宏的几种形式在glibc-2.23\glibc-2.23\sysdeps\i386\sysdep.h中定义如下:

#define INTERNAL_SYSCALL_MAIN_0(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 0, args)
#define INTERNAL_SYSCALL_MAIN_1(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 1, args)
#define INTERNAL_SYSCALL_MAIN_2(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 2, args)
#define INTERNAL_SYSCALL_MAIN_3(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 3, args)
#define INTERNAL_SYSCALL_MAIN_4(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 4, args)
#define INTERNAL_SYSCALL_MAIN_5(name, err, args...) \
    INTERNAL_SYSCALL_MAIN_INLINE(name, err, 5, args)

INTERNAL_SYSCALL_MAIN_INLINE宏在glibc-2.23\glibc-2.23\sysdeps\i386\sysdep.h中定义,代码如下:

#  define INTERNAL_SYSCALL_MAIN_INLINE(name, err, nr, args...) \

    LOADREGS_##nr(args)       \
    asm volatile (       \
    "int $0x80"        \
    : "=a" (resultvar)       \
    : "a" (__NR_##name) ASMARGS_##nr(args) : "memory", "cc")

chmod库函数的定义最终通过int $0x80 触发软中断。

2、 syscall函数

glibc-2.23\glibc-2.23\sysdeps\unix\sysv\linux\hppa\syscall.c中的syscall函数定义如下:

long int
syscall (long int __sysno, ...)
{
  /* FIXME: Keep this matching INLINE_SYSCALL for hppa */
  va_list args;
  long int arg0, arg1, arg2, arg3, arg4, arg5;
  long int __sys_res;

  /* Load varargs */
  va_start (args, __sysno);
  arg0 = va_arg (args, long int);
  arg1 = va_arg (args, long int);
  arg2 = va_arg (args, long int);
  arg3 = va_arg (args, long int);
  arg4 = va_arg (args, long int);
  arg5 = va_arg (args, long int);
  va_end (args);

  {
    LOAD_ARGS_6 (arg0, arg1, arg2, arg3, arg4, arg5)
    register unsigned long int __res asm("r28");
    PIC_REG_DEF
    LOAD_REGS_6
    asm volatile (SAVE_ASM_PIC
    " ble  0x100(%%sr2, %%r0) \n"
    " copy %1, %%r20  \n"
    LOAD_ASM_PIC
    : "=r" (__res)
    : "r" (__sysno) PIC_REG_USE ASM_ARGS_6
    : "memory", CALL_CLOB_REGS CLOB_ARGS_6);
    __sys_res = __res;
  }
  if ((unsigned long int) __sys_res >= (unsigned long int) -4095)
    {
      __set_errno (-__sys_res);
      __sys_res = -1;
    }
  return __sys_res;
}

在syscall 函数中使用嵌入汇编的形式调用软中断指令。

3、_syscall系统调用宏

以_syscall0()为例,它以嵌入汇编的形式调用软中断指令int 0x80

4、通过软中断指令陷入

使用软中断陷入是直接使用汇编指令int $0x80 触发软中断

3.响应请求

软中断是通过一条具体指令SWI,当CPU执行到SWI指令时会触发中断,进入中断程序。以X86 体系架构为例,软件中断指令( int 0x80)用于产生软中断,同时处理器从用户模式变换到特权模式。

应用程序调用系统调用接口函数后,底层会执行软中断指令( int 0x80 ),处理器就从用户态切换到内核态,并跳转到了 0x80 中断向量号 ,对应的中断向量服务程序 ,并根据传入的调用号执行相应的系统服务函数,中断触发后的响应流程如下图:

\linux-2.6.28.6\arch\x86\include\asm\irq_vectors.h中SYSCALL_VECTOR宏如下:

# define SYSCALL_VECTOR  0x80

linux-2.6.28.6\arch\x86\kernel\traps.c 中断配置如下:

void __init trap_init(void)
{
 .....省略代码.....
 set_intr_gate(0, ÷_error);
 set_intr_gate_ist(1, &debug, DEBUG_STACK);
 set_intr_gate_ist(2, &nmi, NMI_STACK);
 /* int3 can be called from all */
 set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
 /* int4 can be called from all */
 set_system_intr_gate(4, &overflow);
 set_intr_gate(5, &bounds);
 set_intr_gate(6, &invalid_op);
 set_intr_gate(7, &device_not_available);
 .....省略代码.....
 set_system_trap_gate(SYSCALL_VECTOR, &system_call);
 .....省略代码.....
}

0x80 中断向量服务入口为system_call,system_call函数定义在linux-2.6.28.6/arch/x86/kernel/ entry_32.S中ENTRY(system_call),system_call汇编代码涉较多,下面的代码保留了最核心部分代码:

ENTRY(system_call)
 RING0_INT_FRAME   # can't unwind into user space anyway
 pushl %eax   # save orig_eax
 CFI_ADJUST_CFA_OFFSET 4
 SAVE_ALL
 GET_THREAD_INFO(%ebp)
     # system call tracing in operation / emulation
 /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */
 testw $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
 jnz syscall_trace_entry
 cmpl $(nr_syscalls), %eax
 jae syscall_badsys
syscall_call:
 call *sys_call_table(,%eax,4)
 movl %eax,PT_EAX(%esp)  # store the return value
  .....省略代码.....
ENDPROC(system_call)

我们将以上简化的代码根据syscall_call标号分为两部分:syscall_call准备,syscall_call调用

syscall_call准备
SAVE_ALL 的主要工作就是将 gs、fs、es、ds、eax、ebp 等寄存器中的值在调用系统调用服务程序之前将其压入到内核栈中保存。

cmpl $(nr_syscalls), %eax 指令语句则是用来判断从用户态传入的系统调用号是否大于系统中所实现的最大的系统调用编号,判断传入的系统调用编号是否合法,如果不合法程序就跳转到 syscall_badsys 处执行相应的出错处理程序。

syscall_call调用
syscall_call中的工作就是就是去调用与传入系统调用号对应的系统调用服务程序,而这一步中就只有一条非常简单的 call 指令语句,如下所示:

call *sys_call_table(,%eax,4)

call *sys_call_table(,%eax,4) 根据 eax 中传入的系统调用号来调用对应的系统调用服务程序, sys_call_table是一个函数指针数组(跳转表)。

sys_call_table跳转表

sys_call_table定义如下:

/* 代码文件路径:/linux-2.6.28.6/arch/x86/kernel/syscall_32.c */
#undef __SYSCALL
#define __SYSCALL(nr, sym) [nr] = sym,
#undef _ASM_X86_UNISTD_64_H

typedef void (*sys_call_ptr_t)(void);

extern void sys_ni_syscall(void);

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
 /*
 *Smells like a like a compiler bug -- it doesn't work
 *when the & below is removed.
 */
 [0 ... __NR_syscall_max] = &sys_ni_syscall,
#include 
};

sys_call_table 是函数指针类型的的数组,数组长度就是系统中所包含的全部系统调用的数量__NR_syscall_max + 1,[0 … __NR_syscall_max] = &sys_ni_syscall代码完成的就是对数组元素初始化的工作, #include 是直接将头文件中的内容在数组中展开。

asm/unistd_64.h文件内容如下:

#ifndef _ASM_X86_UNISTD_64_H
#define _ASM_X86_UNISTD_64_H

#ifndef __SYSCALL
#define __SYSCALL(a, b)
#endif


/* at least 8 syscall per cacheline */
#define __NR_read    0

__SYSCALL(__NR_read, sys_read)
#define __NR_write    1
__SYSCALL(__NR_write, sys_write)
#define __NR_open    2

__SYSCALL(__NR_open, sys_open)
#define __NR_close    3
__SYSCALL(__NR_close, sys_close)
#define __NR_stat    4

__SYSCALL(__NR_stat, sys_newstat)
#define __NR_fstat    5
__SYSCALL(__NR_fstat, sys_newfstat)
#define __NR_lstat    6

__SYSCALL(__NR_lstat, sys_newlstat)
#define __NR_poll    7
__SYSCALL(__NR_poll, sys_poll)

  .....省略代码.....

sys_call_table扩展开后为:

__visible const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
    [0 ] = sys_read,
    [1] = sys_write
    [2] = sys_open,
 [3] = sys_close,
  .....省略代码.....
};

sys_call_table[0] 就是执行sys_read函数,使用跳转表后程序的执行状态如下图:

4.功能实现

系统调用号和系统调用服务程序是一一对应关系,一个系统调用对应一个系统调用服务程序。90号系统调用对应的系统调用服务程序就是 sys_chmod,如下所示:

#define __NR_chmod    90
__SYSCALL(__NR_chmod, sys_chmod)

sys_chmod函数定义如下:

linux-2.6.28.6\linux-2.6.28.6\fs\open.c 
SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)
{
 return sys_fchmodat(AT_FDCWD, filename, mode);
}

为什么不是 sys_chmod() 作为函数名呢?Linux 系统中的系统调用服务函数都是使用 SYSCALL_DEFINEx (0,1,2,3,4,5,6) 宏来实现的,这样使得用户态和内核态的两个函数“看起来一样”。

SYSCALL_DEFINEx 的定义如下所示,

/* 代码文件路径:/linux-3.18.6/include/linux/syscalls.h */
#define SYSCALL_METADATA(sname, nb, ...)


#define SYSCALL_DEFINE0(sname)                  \
    SYSCALL_METADATA(_##sname, 0);              \
    asmlinkage long sys_##sname(void)

#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__)
#define SYSCALL_DEFINEx(x, sname, ...)              \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)         \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))   \
        __attribute__((alias(__stringify(SyS##name))));     \

所以根据上面的定义,宏 SYSCALL_DEFINE2(chmod, const char __user *, filename, mode_t, mode)展开后得到的结果就是:

asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
{
 return sys_fchmodat(AT_FDCWD, filename, mode);

5.自定义一个系统调用

通常情况下已有的系统调用可以满足我们绝大多少需求,但是在极少数情况下,我们需要额外增加一个自定义的系统调用。接下来我们来学习一下如何增加一个自定义系统调用。例如我们自定义一个名为weiweicall的系统调用(该系统调用的参数为0)。

一旦系统调用的名字确定下来了,那么在系统调用中的几个相关名字也就确定下来了。
调用接口函数:weiweicall
系统调用的编号名字:__NR_weiweicall
内核中系统调用的实现程序的名字:sys_weiweicall

5.1接口函数

在前面我们描述了4种系统调用的接口,我们可以使用linux系统调用宏_syscall0来定义一个可以产生软中断的函数:

#include 
_syscall0(int,weiweicall) /* 注意这里没有分号*/
int main()
{
 weiweicall();
}

定义了weiweicall用户系统调用函数,接下来我们定义系统调用号。

5.2添加系统调用号

我们要做的就是在文件asm/unistd_64.h文中添加自定义的系统调用号__NR_weiweicall,代码如下:

linux-2.6.28.6\arch\x86\include\asm\unistd_64.h

#define __NR_eventfd2    290

__SYSCALL(__NR_eventfd2, sys_eventfd2)
#define __NR_epoll_create1   291
__SYSCALL(__NR_epoll_create1, sys_epoll_create1)
#define __NR_dup3    292

__SYSCALL(__NR_dup3, sys_dup3)
#define __NR_pipe2    293
__SYSCALL(__NR_pipe2, sys_pipe2)
#define __NR_inotify_init1   294

__SYSCALL(__NR_inotify_init1, sys_inotify_init1)
//增加自定义系统调用
#define __NR_weiweicall   295
__SYSCALL(__NR_weiweicall, sys_weiweicall)

添加系统调用号之后,系统才能根据这个号作为索引,去找syscall_table中的相应表项。目前系统已经能够正确地找到并且调用sys_mysyscall。剩下事情的就只剩下sys_mysyscall内核函数的实现。

5.3sys_mysyscall 的实现

我们自定义的程序添加在内核代码中,如kernel/sys.c 里面,我们没有在kernel 目录下另外 添加自己的一个文件,这样做的不用修改Makefile,可以直接编译。我们可以用宏实现功能函数,也可以直接定义实现功能函数:

//直接定义sys_xxx函数
asmlinkage int sys_weiweicall(void)
{
 printk( "weiwei  system call!");
 return 1;
}
//使用SYSCALL_DEFINE定义函数
SYSCALL_DEFINE0(weiweicall)
{
 printk( "weiwei  system call!");
 return 1;
}

编译内核后,应用程序就可以使用weiweicall系统调用。

#include 
_syscall0(int,weiweicall) /* 注意这里没有分号*/
int main()
{
 weiweicall();
}

6.系统调用分类

系统调⽤按照功能逻辑⼤致可分为“进程控制”、“⽂件系统控制”、“系统控制”、“存管管理”、“⽹络管理”、“socket控制”、“⽤户管理”、“进程间通信”。

进程控制类系统调用

fork,clone,execve,exit,_exit,getdtablesize,getpgid,setpgid,getpgrp,setpgrp,getpid,getppid,getpriority,setpriority,modify_ldt,nanosleep,nice,pause,personality,prctl,ptrace,sched_get_priority_max,sched_get_priority_min,sched_getparam,sched_getscheduler,sched_rr_get_interval,sched_setparam,sched_setscheduler,sched_yield,vfork,wait,wait3,waitpid,wait4,capget,capset,getsid,setsid

文件操作类系统调用

fcntl,open,creat,close,read,write,readv,writev,pread,pwrite,lseek,_llseek,dup,dup2,flock,polltruncate,ftruncate,umask,fsync

文件系统操作类系统调用

access,chdir,fchdir,chmod,fchmod,chown,fchown,lchown,chroot,stat,lstat,fstat,statfs,fstatfs,readdir,getdents,mkdir,mknod,rmdir,rename,link,symlink,unlink,readlink,mount,umount,ustat,utime,utimes,quotactl

系统控制类系统调用

ioctl,_sysctl,acct,getrlimit,setrlimit,getrusage,uselib,ioperm,iopl,outb,reboot,swapon,swapoff,bdflush,sysfs,sysinfo,adjtimex,alarm,getitimer,setitimer,gettimeofday,settimeofday,stime,time,times,uname,vhangup,nfsservctl,vm86,create_module,delete_module,init_modulequery_module,get_kernel_syms

内存管理类系统调用

brk,sbrk,mlock,munlock,mlockall,munlockall,mmap,munmap,mremap,msync,mprotect,getpagesize,sync,cacheflush

网络管理类系统调用

getdomainname,setdomainname,gethostid,sethostid,gethostname,sethostname,socketcall,socket,bind,connect,accept,send,sendto,sendmsg,recv,recvfrom,recvmsg,listen,select,shutdown,getsockname,getpeername,getsockopt,setsockopt,sendfile,socketpair

用户管理类系统调用

getuid,setuid,getgid,setgid,getegid,setegid,geteuid,seteuid,setregid,setreuid,getresgid,setresgid,getresuid,setresuid,setfsgid,setfsuid,getgroups,setgroups

进程间通信类系统调用

sigaction,sigprocmask,sigpending,sigsuspend,signal,kill,sigblock,siggetmask,sigsetmask,sigmask,sigpause,sigvec,ssetmask,msgctl,msgget,msgsnd,msgrcv,pipe ,semctl,semget,semop,shmctl,shmget,shmat,shmdt

总结:系统调用使用接口函数产生软中断,处理器进入中断状态执行相应的功能程序。

原文:https://blog.csdn.net/li_man_man_man/article/details/124599825

文章来源于网络,版权归原作者所有,如有侵权,请联系删除。



关注【一起学嵌入式】,回复加群进技术交流群。



觉得文章不错,点击“分享”、“”、“在看” 呗!

一起学嵌入式 公众号【一起学嵌入式】,RTOS、Linux编程、C/C++,以及经验分享、行业资讯、物联网等技术知
评论
  • 概述 说明(三)探讨的是比较器一般带有滞回(Hysteresis)功能,为了解决输入信号转换速率不够的问题。前文还提到,即便使能滞回(Hysteresis)功能,还是无法解决SiPM读出测试系统需要解决的问题。本文在说明(三)的基础上,继续探讨为SiPM读出测试系统寻求合适的模拟脉冲检出方案。前四代SiPM使用的高速比较器指标缺陷 由于前端模拟信号属于典型的指数脉冲,所以下降沿转换速率(Slew Rate)过慢,导致比较器检出出现不必要的问题。尽管比较器可以使能滞回(Hysteresis)模块功
    coyoo 2024-12-03 12:20 170浏览
  • RDDI-DAP错误通常与调试接口相关,特别是在使用CMSIS-DAP协议进行嵌入式系统开发时。以下是一些可能的原因和解决方法: 1. 硬件连接问题:     检查调试器(如ST-Link)与目标板之间的连接是否牢固。     确保所有必要的引脚都已正确连接,没有松动或短路。 2. 电源问题:     确保目标板和调试器都有足够的电源供应。     检查电源电压是否符合目标板的规格要求。 3. 固件问题: &n
    丙丁先生 2024-12-01 17:37 114浏览
  • 在电子工程领域,高速PCB设计是一项极具挑战性和重要性的工作。随着集成电路的迅猛发展,电路系统的复杂度和运行速度不断提升,对PCB设计的要求也越来越高。在这样的背景下,我有幸阅读了田学军老师所著的《高速PCB设计经验规则应用实践》一书,深感受益匪浅。以下是我从本书中学习到的新知识和经验分享,重点涵盖特殊应用电路的PCB设计、高速PCB设计经验等方面。一、高速PCB设计的基础知识回顾与深化 在阅读本书之前,我对高速PCB设计的基础知识已有一定的了解,但通过阅读,我对这些知识的认识得到了进一步的深
    金玉其中 2024-12-05 10:01 2浏览
  • 当前,智能汽车产业迎来重大变局,随着人工智能、5G、大数据等新一代信息技术的迅猛发展,智能网联汽车正呈现强劲发展势头。11月26日,在2024紫光展锐全球合作伙伴大会汽车电子生态论坛上,紫光展锐与上汽海外出行联合发布搭载紫光展锐A7870的上汽海外MG量产车型,并发布A7710系列UWB数字钥匙解决方案平台,可应用于数字钥匙、活体检测、脚踢雷达、自动泊车等多种智能汽车场景。 联合发布量产车型,推动汽车智能化出海紫光展锐与上汽海外出行达成战略合作,联合发布搭载紫光展锐A7870的量产车型
    紫光展锐 2024-12-03 11:38 126浏览
  • 最近几年,新能源汽车愈发受到消费者的青睐,其销量也是一路走高。据中汽协公布的数据显示,2024年10月,新能源汽车产销分别完成146.3万辆和143万辆,同比分别增长48%和49.6%。而结合各家新能源车企所公布的销量数据来看,比亚迪再度夺得了销冠宝座,其10月新能源汽车销量达到了502657辆,同比增长66.53%。众所周知,比亚迪是新能源汽车领域的重要参与者,其一举一动向来为外界所关注。日前,比亚迪汽车旗下品牌方程豹汽车推出了新车方程豹豹8,该款车型一上市就迅速吸引了消费者的目光,成为SUV
    刘旷 2024-12-02 09:32 140浏览
  • 作为优秀工程师的你,已身经百战、阅板无数!请先醒醒,新的项目来了,这是一个既要、又要、还要的产品需求,ARM核心板中一个处理器怎么能实现这么丰富的外围接口?踌躇之际,你偶阅此文。于是,“潘多拉”的魔盒打开了!没错,USB资源就是你打开新世界得钥匙,它能做哪些扩展呢?1.1  USB扩网口通用ARM处理器大多带两路网口,如果项目中有多路网路接口的需求,一般会选择在主板外部加交换机/路由器。当然,出于成本考虑,也可以将Switch芯片集成到ARM核心板或底板上,如KSZ9897、
    万象奥科 2024-12-03 10:24 96浏览
  • TOF多区传感器: ND06   ND06是一款微型多区高集成度ToF测距传感器,其支持24个区域(6 x 4)同步测距,测距范围远达5m,具有测距范围广、精度高、测距稳定等特点。适用于投影仪的无感自动对焦和梯形校正、AIoT、手势识别、智能面板和智能灯具等多种场景。                 如果用ND06进行手势识别,只需要经过三个步骤: 第一步&
    esad0 2024-12-04 11:20 109浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2024-12-02 10:40 144浏览
  •         温度传感器的精度受哪些因素影响,要先看所用的温度传感器输出哪种信号,不同信号输出的温度传感器影响精度的因素也不同。        现在常用的温度传感器输出信号有以下几种:电阻信号、电流信号、电压信号、数字信号等。以输出电阻信号的温度传感器为例,还细分为正温度系数温度传感器和负温度系数温度传感器,常用的铂电阻PT100/1000温度传感器就是正温度系数,就是说随着温度的升高,输出的电阻值会增大。对于输出
    锦正茂科技 2024-12-03 11:50 143浏览
  • 戴上XR眼镜去“追龙”是种什么体验?2024年11月30日,由上海自然博物馆(上海科技馆分馆)与三湘印象联合出品、三湘印象旗下观印象艺术发展有限公司(下简称“观印象”)承制的《又见恐龙》XR嘉年华在上海自然博物馆重磅开幕。该体验项目将于12月1日正式对公众开放,持续至2025年3月30日。双向奔赴,恐龙IP撞上元宇宙不久前,上海市经济和信息化委员会等部门联合印发了《上海市超高清视听产业发展行动方案》,特别提到“支持博物馆、主题乐园等场所推动超高清视听技术应用,丰富线下文旅消费体验”。作为上海自然
    电子与消费 2024-11-30 22:03 109浏览
  • 遇到部分串口工具不支持1500000波特率,这时候就需要进行修改,本文以触觉智能RK3562开发板修改系统波特率为115200为例,介绍瑞芯微方案主板Linux修改系统串口波特率教程。温馨提示:瑞芯微方案主板/开发板串口波特率只支持115200或1500000。修改Loader打印波特率查看对应芯片的MINIALL.ini确定要修改的bin文件#查看对应芯片的MINIALL.ini cat rkbin/RKBOOT/RK3562MINIALL.ini修改uart baudrate参数修改以下目
    Industio_触觉智能 2024-12-03 11:28 112浏览
  • 11-29学习笔记11-29学习笔记习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-02 23:58 94浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦