库函数和系统调用

系统调用

系统调用(system call):是操作系统为用户态运行的进程和硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口,即就是设置在应用程序和硬件设备之间的一个接口层。可以说是操作系统留给用户程序的一个接口。再来说一下,linux内核是单内核,结构紧凑,执行速度快,各个模块之间是直接调用的关系。放眼望整个linux系统,从上到下依次是用户进程->linux内核->硬件。其中系统调用接口是位于Linux内核中的,如果再稍微细分一下的话,整个linux系统从上到下可以是:用户进程->系统调用接口->linux内核子系统->硬件,也就是说Linux内核包括了系统调用接口和内核子系统两部分;或者从下到上可以是:物理硬件->OS内核->OS服务->应用程序,其中操作系统起到“承上启下”的关键作用,向下管理物理硬件,向上为操作系服务和应用程序提供接口,这里的接口就是系统调用了。
一般地,操作系统为了考虑实现的难度和管理的方便,它只提供一少部分的系统调用,这些系统调用一般都是由C和汇编混合编写实现的,其接口用C来定义,而具体的实现则是汇编,这样的好处就是执行效率高,而且,极大的方便了上层调用。

可以Linux /usr/src/linux-headers-4.4.0-21/arch/arm64/include/asm 目录下找到所有的系统头文件。

acenv.h         cpuidle.h         insn.h            mmzone.h          stackprotector.h
acpi.h          cpu_ops.h         io.h              module.h          stacktrace.h
alternative.h   cputype.h         irqflags.h        neon.h            stat.h
arch_gicv3.h    dcc.h             irq.h             numa.h            string.h
arch_timer.h    debug-monitors.h  irq_work.h        opcodes.h         suspend.h
arm-cci.h       device.h          jump_label.h      page.h            sync_bitops.h
asm-offsets.h   dma-mapping.h     kasan.h           pci.h             syscall.h
assembler.h     dmi.h             Kbuild            percpu.h          sysreg.h
atomic.h        efi.h             kernel-pgtable.h  perf_event.h      system_misc.h
atomic_ll_sc.h  elf.h             kgdb.h            pgalloc.h         thread_info.h
atomic_lse.h    esr.h             kvm_arm.h         pgtable.h         timex.h
barrier.h       exception.h       kvm_asm.h         pgtable-hwdef.h   tlbflush.h
bitops.h        exec.h            kvm_coproc.h      pgtable-types.h   tlb.h
bitrev.h        fb.h              kvm_emulate.h     processor.h       topology.h
boot.h          fixmap.h          kvm_host.h        proc-fns.h        traps.h
bug.h           fpsimd.h          kvm_mmio.h        ptrace.h          uaccess.h
cacheflush.h    fpsimdmacros.h    kvm_mmu.h         seccomp.h         unistd32.h
cache.h         ftrace.h          kvm_psci.h        shmparam.h        unistd.h
cachetype.h     futex.h           linkage.h         signal32.h        vdso_datapage.h
cmpxchg.h       hardirq.h         lse.h             smp.h             vdso.h
compat.h        hugetlb.h         memblock.h        smp_plat.h        virt.h
compiler.h      hw_breakpoint.h   memory.h          sparsemem.h       word-at-a-time.h
cpufeature.h    hwcap.h           mmu_context.h     spinlock.h        xen
cpu.h           hypervisor.h      mmu.h             spinlock_types.h

库函数

顾名思义是把函数放到库里。是把一些常用到的函数编完放到一个文件里,供别人用。别人用的时候把它所在的文件名用#include<>加到里面就可以了。一般是放到lib文件里的。一般是指编译器提供的可在c源程序中调用的函数。可分为两类,一类是c语言标准规定的库函数,一类是编译器特定的库函数。(由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口)
libc中就是一个C标准库,里面存放一些基本函数,这些基本函数都是被标准化了的,而且这些函数通常都是用汇编直接实现的。
库函数一般可以概括的分为两类,一类是随着操作系统提供的,另一类是由第三方提供的。随着系统提供的这些库函数把系统调用进行封装或者组合,可以实现更多的功能,这样的库函数能够实现一些对内核来说比较复杂的操作。比如,read()函数根据参数,直接就能读文件,而背后隐藏的比如文件在硬盘的哪个磁道,哪个扇区,加载到内存的哪个位置等等这些操作,程序员是不必关心的,这些操作里面自然也包含了系统调用。而对于第三方的库,它其实和系统库一样,只是它直接利用系统调用的可能性要小一些,而是利用系统提供的API接口来实现功能(API的接口是开放的)。部分Libc库中的函数的功能的实现还是借助了系统掉调用,比如printf的实现最终还是调用了write这样的系统调用;而另一些则不会使用系统调用,比如strlen, strcat, memcpy等。

库函数是在系统调用上的一层包装,运行在用户态(user mode)。

所以虽然最终所有的工作都是系统调用做的,但是我们更通常的做法是调用库函数,有以下几个原因:

库函数提供了抽象,抽象是个好东西,可以让我们把更多的注意力集中在要解决问题的核心。
库函数给我们提供的接口更人性化,所以调用起来更方便。
调用库函数更安全,内存管理不用自己太操心。
调用库函数效率更高,程序跑的更快。虽然库函数最终是调用系统函数,但是库函数会比我们用更好的方式方法调用系统函数。

库函数不光可以在系统调用的基础上包装,也可以在其他库函数的基础上包装,提供更高级的抽象,更强大的功能。比如OGRE对OpenGL的包装,Qt对Xlib的包装。

最后介绍两个工具,strace和ltrace,strace查看我们的可执行文件调用了哪些系统调用,ltrace查看可执行文件调用了哪些库函数。用法很简单,直接在命令后面跟可执行文件路径就好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值