【编译、链接、装载十五】系统调用与API——printf源码分析

我们从程序如何链接、 如何使用运行库到运行库的实现机制, 层层挖掘和剖析, 现在已经到了用户层面与内核层面的界限了, 也就是常说的系统调用(System Call) 。系统调用是应用程序(运行库也是应用程序的一部分) 与操作系统内核之间的接口, 它决定了应用程序是如何与内核打交道的。 无论程序是直接进行系统调用, 还是通过运行库, 最终还是会到达系统调用这个层面上。Windows系统是完全基于DLL机制的, 它通过DLL对系统调用进行了包装, 形成了所谓的Windows API。 应用程序所能看到的Windows系统的最底层的接口就是Windows API

一、系统调用介绍

1、什么是系统调用

什么是系统调用在现代的操作系统里, 程序运行的时候, 本身是没有权利访问多少系统资源的。 由于系统有限的资源有可能被多个不同的应用程序同时访问,因此, 如果不加以保护, 那么各个应用程序难免产生冲突。 所以现代操作系统都将可能产生冲突的系统资源给保护起来, 阻止应用程序直接访问。 这些系统资源包括文件、 网络、 IO、 各种设备等。 举个例子, 无论在Windows下还是Linux下, 程序员都没有机会擅自去访问硬盘的某扇区上面的数据, 而必须通过文件系统; 也不能擅自修改任意文件, 所有的这些操作都必须经由操作系统所规定的方式来进行, 比如我们使用fopen去打开一个没有权限的文件就会发生失败。

为了让应用程序有能力访问系统资源, 也为了让程序借助操作系统做一些必须由操作系统支持的行为,

以下是一个简单的模拟设备驱动程序的代码示例,该驱动程序将创建一个名为 "mydevice" 的字符设备,并支持读取和写入操作: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #define DEVICE_NAME "mydevice" #define BUFFER_SIZE 1024 static char device_buffer[BUFFER_SIZE]; static int pos = 0; static int device_open(struct inode *inode, struct file *file) { printk(KERN_INFO "Device opened\n"); return 0; } static int device_release(struct inode *inode, struct file *file) { printk(KERN_INFO "Device closed\n"); return 0; } static ssize_t device_read(struct file *file, char *buffer, size_t length, loff_t *offset) { int bytes_read = 0; if (pos >= BUFFER_SIZE) { return 0; } while (length && pos < BUFFER_SIZE) { put_user(device_buffer[pos], buffer++); length--; pos++; bytes_read++; } return bytes_read; } static ssize_t device_write(struct file *file, const char *buffer, size_t length, loff_t *offset) { int bytes_written = 0; if (pos >= BUFFER_SIZE) { return -ENOSPC; } while (length && pos < BUFFER_SIZE) { get_user(device_buffer[pos], buffer++); length--; pos++; bytes_written++; } return bytes_written; } static struct file_operations fops = { .open = device_open, .release = device_release, .read = device_read, .write = device_write, }; static int __init mydevice_init(void) { int ret = register_chrdev(0, DEVICE_NAME, &fops); if (ret < 0) { printk(KERN_ALERT "Failed to register device\n"); return ret; } printk(KERN_INFO "Device registered\n"); return 0; } static void __exit mydevice_exit(void) { unregister_chrdev(0, DEVICE_NAME); printk(KERN_INFO "Device unregistered\n"); } module_init(mydevice_init); module_exit(mydevice_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple device driver"); ``` 将上述代码保存为 mydevice.c 文件,并在终端中使用以下命令编译为内核模块: ```bash make -C /lib/modules/$(uname -r)/build M=$(pwd) modules ``` 编译成功后,将会生成名为 mydevice.ko 的内核模块文件。接下来,使用以下命令将该模块装载到内存中: ```bash sudo insmod mydevice.ko ``` 使用以下命令查看模块是否成功装载: ```bash lsmod | grep mydevice ``` 最后,可以编写一个用户程序来调用该模块,以下是一个简单的示例程序: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> #define DEVICE_PATH "/dev/mydevice" #define BUFFER_SIZE 1024 int main() { int fd = open(DEVICE_PATH, O_RDWR); if (fd == -1) { perror("Failed to open device"); return 1; } char buffer[BUFFER_SIZE]; int bytes_read = read(fd, buffer, BUFFER_SIZE); if (bytes_read == -1) { perror("Failed to read from device"); return 1; } printf("Read %d bytes from device: %s\n", bytes_read, buffer); char *message = "Hello, device!"; int bytes_written = write(fd, message, strlen(message)); if (bytes_written == -1) { perror("Failed to write to device"); return 1; } printf("Wrote %d bytes to device\n", bytes_written); close(fd); return 0; } ``` 该程序将打开 mydevice 设备,并进行读取和写入操作。将上述代码保存为 myprogram.c 文件,并使用以下命令编译: ```bash gcc -o myprogram myprogram.c ``` 编译成功后,可以运行该程序: ```bash ./myprogram ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑同学的笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值