Linux内核学习(一)8086编程模型

2023-05-16

本文主要介绍Intel8086系列的编程模型,包括分段与分页机制、任务切换过程以及中断处理系统。作为Linux内核学习曲线的起点,本文的侧重点在于对于每个主题,硬件上是如何实现的,以及为软件(操作系统)提供了什么样的接口。本文不会介绍x86汇编语言的知识,有关知识请自行参考资料。

需要说明的是,Linux内核基于80x86,因此需要遵循8086的编程模型,但在很多地方实现了自己的策略。因此,如果发现8086中很多讲解的典型场景有与Linux内核不一致的地方,请不要惊讶。

本文主要参考《Intel80386 Programmers’ perference manual》。

1. 分段机制的安全模型

80x86的保护模式和分段机制有效结合,形成了一套安全体系。

1.1 名词解释

分段机制:指令和数据的地址由段基地址和段内偏移两部分组成。有关分段和分页的概念,请参考任一本操作系统或80x86汇编或架构方面的书籍。

保护模式:保护模式下系统拥有一张段描述符表,寻址时以段寄存器值为索引,查找段描述符表获得段基地址。段描述符包含段基地址、段界限长度、段特权级DPL。其中,段界限和DPL共同决定了保护模式下的安全机制。

特权级:一个取值0~3的数字,用来标识当前CPU或者某个代码段/数据段的特权级。CPU当前特权级称为CPL;代码段或数据段或者其它类型段的特权级值位于段描述符里,称为DPL。特权级值越小,特权级越高。因此,0最高,3最低。

1.2 基本安全机制

如果所有的代码均顺序执行,并且不需要访问其它地方的数据,那么也就没有必要进行保护了。因此,安全机制包含两层含义:访问数据;指令跳转。

8086以段为安全对象,因此如果访问的数据或者跳转的指令与原指令在同一段,只需要检查是否超过段界限长度即可。

针对跨越段的数据访问,有如下策略:

规则1:如果访问的是数据段,那么只能高权限代码访问低权限的数据。因此需要CPL <= DPL。此外,段寄存器不仅保存了段索引,还保存了2bit的RPL,在访问数据时还要保证RPL<=DPL。[为什么这样要求,留到后面讲述调用门时说明。这其实跟操作系统的权限代理有关]。

规则2:如果访问的是代码段(谈的是数据访问,怎么会访问代码段?考虑到有时候在代码段存放一些只读的数据),那么需要考虑目标代码段的一致性1。如果是一致性代码段,那么访问总是成功;如果是非一致性代码段,那么需要遵从规则1。

针对跨越段的指令跳转,有如下策略:

规则1:如果跳转到非一致性代码段,那么要求CPL = DPL。也就是说,不允许跨越特权级的代码跳转。这也很好理解,要是允许跨越特权级跳转,那我随便跳到高特权级的代码段,进而也就能随便地访问数据了,谈何保护。

规则2:对于某些场景(比如说用户级代码需要用到系统态的一些公共服务,一般情况下还是要跳转回去的),会允许低特权级代码跳转到高特权级代码,也就是CPL >= DPL。但是为了防止与规则1冲突,在跳转之后CPL不能变,不能因为暂时的跳转而升级代码的权限。因为CPU的当前特权级没有改变,所以这样的目标代码段,称作一致性代码段

聪明的读者发现没有,如果按照上面列出的安全规则,CPU在运行时的特权级CPL好像从来都没有变化过:要么访问特权级一样的非一致性代码段,要么访问特权级高但是CPL保持不变的一致性代码段。那说好的用户态和内核态呢?别急,Intel程序员已经考虑到了!答案就是门!

1.3 调用门Call Gate

门(Gate)是一种特殊的段。有多特殊?你只需要为它定义好段描述符就好,在内存中不再占用其它空间,这点不像数据段或者代码段。程序世界的“门”就像是科幻电影里的门一样:拿粉笔在墙上(位于现在所处的位置)画一个形状(定义门描述符符),然后拧开门把手就能进入另外一个世界(另外一个代码段)!

言归正传,如果我们想跳转到特权级高的代码,而且要求CPL同时改变成新代码段的DPL,怎么办?只需要为目标代码段定义一个Call Gate。Call Gate描述符格式如下:

OFFSET[31:16]

DPL

COUNT

目标段选择子

OFFSET[15:0]

其中,OFFSET定义了目标指令在目标段内偏移地址;DPL是调用门的DPL,不是目标段的DPL,后者位于目标段的段描述符。

调用CALL指令,调用门的访问规则是这样的:

规则1:将调用门看作是数据段(因为你只需要访问它),所以你需要CPL <= DPLgate

规则2:CPL>= DPLtarget

跳转之后,CPL变成DPLtarget,而不管目标代码段是一致性还是非一致性。

调用JMP指令,则只有目标代码段是一致性时才适用以上规则,否则只有CPL与DPLtarget相等才能跳转。

好了,现在可以讲清楚RPL是干嘛的了!利用CallGate会造成CPL的变更,或者更准确地说,代码权限得到了提升。还是这个场景:用户态A需要调用内核态B的公共服务接口。这时候,内核态(高特权级)的代码是代理者,代理用户态程序去执行某项服务,可能需要访问其它一些数据或代码C。而正好这部分数据或代码C是关键代码,是不允许A访问的,那么内核态就需要知道原来用户态A的权限,而这个权限就保存在访问C时的段寄存器(或者叫段选择子)里。

2. 任务切换

现代操作系统必须要支持多任务并发。Intel在设计80386时也提供了快速切换任务的机制。这种机制要求1)任务切换迅速;2)对原来的任务要维护现场,能够返回到原来任务继续运行。本节主要描述如何实现任务切换机制。

2.1 名词解释

任务状态段TSS

保存了管理某个任务的所有信息,包括所有寄存器值(通用寄存器/段寄存器/EFLAGS)、CR3(页目录地址)、栈顶指针(ESP0~2,分别对应特权级0~2)、IO映射基址等。此外,为了能够切换回之前的任务,TSS还包括之前任务的TSS地址。


TSS描述符


TSS作为一个段,在GDT中当然要有对应的段描述符啦,就是TSS描述符,格式如上所示。有以下几点比较有意思,值得提一下:

P.1 DPL字段指定了访问TSS描述符需要的权限,要求CPL<=DPL。能够访问TSS描述符,意味着能够执行任务切换。

P.2 TYPE字段指定了该TSS代表的任务是否已经在运行。CPU决不会切换到一个已经在运行的任务。即每个任务在系统中只能有一个实例。这跟一个程序在系统中有多个进程不同,同一个程序的每次运行都产生一个不同的进程(任务)。

P.3 能够访问TSS描述符不代表能够读或修改TSS段。要想修改TSS段,需要重新定义一个与该TSS段拥有相同地址空间的可读或可写的数据段。

TR寄存器

TR寄存器保存了TSS描述符的段索引值。跟所有的段寄存器一样,TR寄存器也包含可见部分和隐藏部分:16bit可见部分保存索引值;64bit隐藏部分缓存了当前任务的TSS描述符。这样,在任务不发生切换的情况下,只需要访问TR寄存器的隐藏部分即可获得TSS的地址,无需去访问GDT。

LTR/STR命令分别用来加载/保存TR寄存器的值。

任务门


首先需要明确的是,一个门一般是一个段描述符表(GDT / LDT / IDT)的表项。任务门作为一个段描述符表项,它的结构如上图所示。图中,SELECTOR包含一个TSS描述符的索引,指向了GDT中的一个TSS描述符。因此,它的作用也是执行任务切换。既然TSS描述符能够执行任务切换,为什么要多此一举再创建个任务门呢?而且通过任务门访问一个TSS段,需要两次索引(任务门->TSS描述符->TSS段),不是显得更累赘吗?

还是那句话,计算机的世界里,存在即合理。任务门可以解决TSS描述符的几个局限性:

P.1TSS描述符只能位于GDT中,但TSSGate可以位于GDT,LDT,甚至IDT;

P.2一个TSS段一般只在GDT中定义一个TSS描述符,且为了安全起见,它的DPL一般定义为0。而TSSGate的DPL可以设定为任意值。而且,通过TSS Gate访问TSS时检查的是TSSGate的DPL,而不是TSS描述符的DPL。这就给操作系统极大的自由,去设置不同代码访问同一个TSS段的权限。(访问TSS Gate的权限:CPL<= DPL && RPL <= DPL)。

2.2 任务切换过程

考虑通常情况下的任务切换,即调用CALL/JMP命令,目的地址是一个TSS描述符或者一个TSSGate,包含3个步骤:

Step1权限检查和状态检查(新任务是否已运行);

Step2查看tr寄存器获得当前任务TSS地址。将当前任务的现场(所有寄存器值)保存到TSS。

Step3加载新任务的TSS描述符到TR寄存器。根据新任务TSS中寄存器的值恢复新任务的执行环境,同时新任务的状态寄存器的TS位(Task Switched)置1。

新任务和旧任务的运行级别没有任何关联。因为新任务的CPL来自于TSS段的CS段寄存器的RPL字段。

3. 中断机制

关于中断,听到最多的就是中断和异常。Intel官方文档是这样解释中断和异常的:中断(Interrupts)和异常(exceptions)是不同寻常的CPU控制转移方式,工作起来就像自行调用(无需编程)的CALL指令一样。它们打断正在执行的代码,转而去处理来自外部的事件或者来自内部的异常状况。中断和异常的差异也在此:一个来自CPU外部的事件,一个来自CPU执行某条指令时自己产生的异常。

中断分为两类:可屏蔽中断和不可屏蔽中断。这两种中断由中断源连接到CPU的引脚来决定。连接到CPU的INTR引脚的中断可屏蔽;来自NMI引脚的中断不可屏蔽。

异常也分为两类:处理器检测到的异常和编程引起的异常。前者好理解,例如除数为0、缺页、权限不够等等情况,按照严重情况又可以分为故障(fault)、陷阱(trap)和终止(abort);后者是指特殊指令引起的特定的异常,例如int3指令,bound指令,或者int0x80等等,一般又叫做“软中断”。

当然,不管是中断还是异常,都有一个中断号。不可屏蔽中断和异常的中断号为0~31,可屏蔽中断的中断号为32~255。

实模式下和保护模式下的中断机制有很大不同。在实模式下,内存的起始处(0x0)必须放置一张中断向量表,这样当中断发生时,CPU自动保存相关寄存器值后跳转到中断向量表定义的中断处理程序(ISR)。在保护模式下,更复杂一点,系统不再强制必须要在内存起始处设置中断向量表,而是采用类似描述符表的中断描述符表IDT。IDT可以放在内存的任何地方,只要在IDTR寄存器里保存地址就行。IDT的表项可以是中断门,陷阱门,或者任务门。

新概念很多,但不要着急,还是一点一点地来介绍,毕竟在计算机的世界里,被程序员创造出来的东西,总有它存在的意义。

3.1 中断门 & 陷阱门

从一个描述符表项跳转到某条指令,这跟CALL指令的过程很类似。IDT的表项应该是指向中断处理程序的起始地址,即要包含中断处理程序的所在段的段选择子和段内偏移,跟调用门的格式很像。因此,我们把IDT的这种表项称为中断门或陷阱门。

根据第2章的讨论结果,任何时候CPU均是代替某个任务在执行。这个任务的信息保存在TSS段,而TSS的地址则由tr寄存器指定。当中断发生时,这时候CPU要终止当前的任务,但又不会切换到另外的任务,只是跳转到一段特定的代码,即中断处理程序。因此,CPU在执行中断处理程序时仍然处在之前进程的上下文中。这其实关系到在ISR中CPU使用的栈,因为仍处在之前进程上下文中,所以使用的栈当然也是之前进程的栈。但是需要明确的是,虽然我们说此时CPU仍然处于被中断进程的进程上下文中,但是此时CPU绝不会访问该进程的任何数据和代码,只是用它的栈而已。为了以示区别,我们称此时CPU处于中断上下文。

第2章还提到,每个进程均拥有4个栈,分别对应4种特权级。所以,如果ISR的特权级与被中断进程的特权级不一致的话,就会发生栈的切换:从该进程的TSS段查找到对应特权级的栈的地址(SS:ESP),切换到新栈,为了处理完之后恢复现场,还要把旧栈地址、EFLAGS、CS:EIP的值压入新栈。

再说一下从中断返回时的过程。ISR执行IRET指令,可以返回到之前被中断的进程。这与调用CALL再调用RET返回类似,但也有所不同:RET返回之后EIP指向的是CALL指令的下一条指令;而IRET返回之前旧EIP指向的是之前被中断的指令,因此IRET返回之后旧EIP要再加4,才指向下一条指令。

中断门和陷阱门也有区别:中断门会导致IF标志被复位(为0),意味着在CPU处理中断时会屏蔽中断。而陷阱门不会去复位IF标志。

3.2 任务门

中断门或陷阱门的特点是,中断处理程序运行时使用的栈是被中断任务(进程)的内核栈。对Linux内核来说,当“doublefault”发生时,内核在该异常对应的IDT表项中放置的是任务门。这就导致处理该异常时切换到新的任务,也就意味着新的内核栈。Linux内核的策略是,用自己的私有栈来处理“double fault”类型异常。

注:什么是“doublefault”?考虑以下情景:在异常发生后跳转到异常处理程序的时候再次发生异常。有时候处理器能够顺序地执行这两个异常,保证系统正常运行,但有时候处理器会当掉,称为“Double fault”。

4. I/O系统

Input/Output系统一般用来与外设进行通信。外部设备一般拥有自己的一套寄存器(包括数据寄存器或者控制寄存器)。所有外设的寄存器在处理器看来都是一个个端口(port)。处理器的I/O系统主要是指处理器对I/O端口的寻址方式。

理论上有两种I/O端口寻址方式:1)单独地址空间,利用特殊指令(IN/OUT)寻址;2)映射到内存地址空间,利用一般内存寻址指令访问I/O系统。80386支持这两种方式。

映射到内存地址空间的方式就不多说了,这里主要讲讲单独的I/O地址空间寻址时需要注意的地方,主要是权限检查。

外设的端口分为8bit,16bit或32bit。利用IN/OUT指令访问端口的时候,根据使用的寄存器(AL,AX,EAX)来判定访问端口的位数。如果32bit端口号是4字节对齐的,那么访问一次也只需要1个总线周期。

EFLAGS状态寄存器的IOPL字段指定了访问IO地址空间的权限:如果CPL<=IOPL,那么可以访问任何的端口;否则检查当前任务TSS段的I/O端口权限位图(I/OPermission Bit Map),查看对应的端口是否有权限(若为0,这有权限)。

回顾2.1节描述TSS结构的那张图,在66字节偏移处有个”I/O map base”字段。该字段指向了TSS段内I/O端口权限位图的起始地址。因此,可以给不同的任务指定不同的端口访问权限。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux内核学习(一)8086编程模型 的相关文章

  • C++如何监听http请求

    下面有个例子 xff0c 基于 Windows 的 xff0c 编译完 xff0c 运行 WebSrv 7070 即可 在程序的目录中放一个 index html 文件 Copyright c 2002 2005 by Zhang Huiy
  • 我的网页作品(div+css)

    前段时间为一个育儿网站做了一个个人空间主页 xff0c 这可是我的处女座 呵呵 请点击查看 xff1a Files shiyangxt baobaoke rar
  • 我用Visual Basic做的多模式计算器(应用小软件)!

    前一段时间参加了一个校内组织的IT实践大赛 xff0c 虽然当时没什么成熟的技术 xff0c 但是还是参加了 Visual Basic刚学也没多长时间 xff0c 于是就做了这个多模式计算器 xff0c 虽然技术含量不算高 xff0c 一些
  • C语言实现阶乘累加(1!+2!+3!+....+n!=?)

    最近要期末考试 xff0c 复习C语言 xff0c 见到一个看似很简单的问题 就是C语言实现阶乘累加 xff08 1 xff01 43 2 xff01 43 3 43 43 n 61 xff09 本来觉得这个肯定小意思 xff0c 但是修改
  • C++项目工程(包含opencv库以及项目的依赖库移植)编译成android可以使用的so库并在Android studio上调用so库进行使用(血泪操作总结)

    目录结构 概述预先准备编译操作so的函数导出并在android进行调用 概述 最近负责一个android项目需要使用到之前公司师兄编写的c 43 43 算法库 xff0c 一开始并不知道c 43 43 项目可以移植给android项目使用
  • C语言:用递归实现将输入的整数按逆序输出。如输入12345,则输出54321。

    这个程序是我对构造函数有个更深的认识 首先构造函数要先从头至尾走一边才会输出 xff0c 无论输出语句加的位置 xff08 循环内 xff0c 条件语句内 除外 xff09 然后构造函数递归可以把问题简单化 xff0c 本题如果按常规思路
  • Visual Basic函数大全!

    VB函数大全 Abs 函数 返回数的绝对值 And 运算符 执行两个表达式的逻辑连接 Array 函数 返回含一数组的 变体 Asc 函数 返回字符串首字母的 ANSI 字符代码 赋值运算符 61 给变量或属性赋值 Atn 函数 返回数的反
  • 数据结构与算法:哈夫曼树(源码)!

    这些天明白了一个道理 xff0c 搞技术也是需要激情的 也不知道为什么这段过的感觉特别的不爽 xff0c 也不知道是因为快要考试了 xff0c 心里没底 xff0c 而带来的恐惧 xff0c 还是 搞技术太久 xff0c 心里想放个假 xf
  • SSH超实用分页实现(原创开源)!

    SSH的分页网上有不少的例子 xff0c 有利用session的 xff0c 有利用分页组件的 我几个师兄原来搞的SSH项目也有一个成熟的分页插件 具体业务实现类中的分页方法 xff1a lt bgsound cep 61 34 0 34
  • 欢迎访问我的主博(http://shiyangxt.cnblogs.com)

    JavaEye的朋友 xff0c 大家好 我是一名大二的学生 xff0c 对编程技术怀有很大的热情 我的技术方向是Java xff0c 但是我的主博并不在这里 xff0c 而在博客园 xff0c 欢迎大家访问我的主博 施杨de编程世界 我渴
  • Linux应用编程---14.UDP服务器、客户端编程

    Linux应用编程 14 UDP服务器 客户端编程 之前有介绍过UDP是一种无连接 尽最大努力交付 面向报文的协议 应用层交给UDP多长的报文 xff0c UDP就照样发送 Linux下UDP属于数据报socket 数据报socket流程图
  • 0816网络编程day5

    include lt stdio h gt include lt sys types h gt include lt sys socket h gt include lt arpa inet h gt include lt netinet
  • STL容器特征

    STL中顺序容器类和关联容器类的主要特征如下 xff1a 1 vector 内部数据结构 xff1a 数组 随机访问每个元素 xff0c 所需要的时间为常量 在末尾增加或删除元素所需时间与元素数目无关 xff0c 在中间或开头增加或删除元素
  • 数据结构——不带头结点的单链表的基本操作

    数据结构 不带头节点的单链表的基本操作 结构体的创建 xff1a span class token keyword typedef span span class token keyword struct span SListNode sp
  • HTTP请求/响应报文结构

    HTTP请求 响应报文结构 HTTP请求报文 一个HTTP请求报文由四个部分组成 xff1a 请求行 请求头部 空行 请求数据 1 请求行 请求行由请求方法字段 URL字段和HTTP协议版本字段3个字段组成 xff0c 它们用空格分隔 比如
  • C语言练习笔记 ~结构体2 ~ 结构体在内存中的对齐说明

    文章目录 1 结构体变量在内存中的对齐说明例1 1个char型变量例2 2个char型变量例3 1个int型变量例4 1个char型变量和1个int型变量例5 3个char型变量和1个int型变量例6 5个char型变量和1个int型变量例
  • 思岚激光雷达+cartographer建图

    系统环境 xff1a Ubuntu18 04 ROS Melodic gcc 7 5 0 1 安装思岚ROS包 1 1 clone并编译 cd catkin ws src git clone https github com Slamtec
  • 使用PyTorch+functorch计算并可视化NTK矩阵

    2022年3月 xff0c PyTorch发布了PyTorch1 11和functorch functorch灵感来自于Google JAX xff0c 旨在提供vmap和autodiff转换配合PyTorch使用 本文将演示如何使用PyT
  • libcurl异步请求+http长连接池

    由于公司项目 xff0c 需要localhost的形式高并发的http访问本机服务 xff0c 所以面临了两方面的问题 xff1a 1 http短连接会造成大量的time wait xff0c 影响服务器的性能 2 libcurl easy
  • VC实现http发送get和post请求

    VC实现http发送get和post请求 get请求 首先通过前面介绍的抓包工具获取请求的详细内容 xff0c 然后再通过VC拼接Header xff0c 函数如下 xff1a bool CXXX http get eng mode lt

随机推荐

  • 链表(图文详解)

    链表的概念 链表是一种物理存储结构上非连续 xff0c 非顺序的存储结构 xff0c 数据元素的逻辑顺序是通过链表中的指针链接次序实现的 链表的结构是多式多样的 xff0c 当时通常用的也就是两种 xff1a 无头单向非循环列表 xff1a
  • PCB上能上锡的那层叫什么?

  • C++常用数学函数

    C 43 43 中有个头文件math h xff0c 它是数学函数库 一些数学计算的公式的具体实现是放在math h里 xff0c 为了方便大家使用 xff0c 特在此总结常用的一些函数 1 三角函数 double sin double d
  • LimeSDR实验教程(6) 发射GPS

    下载程序 xff1a git clone https github com osqzss gps sdr sim git 编译安装 xff1a cd gps sdr sim gcc gpssim c lm O3 o gps sdr sim
  • 如何理解引用作为函数的返回值?

    如何理解引用作为函数的返回值 xff1f 1 引用作为函数的返回值时 xff0c 必须在定义函数时在函数名前将 amp 2 用引用作函数的返回值的最大的好处是在内存中不产生返回值的副本 span class token comment 代码
  • 自制合成孔径雷达(2) SDR实现的对比(SDR实现测速雷达)

    我今天查了查资料 xff1a 技术干货 xff1a 用LimeSDR Mini制作一台软件定义多普勒雷达 搜狐汽车 搜狐网 查阅一些文献后 xff0c 笔者想探寻减少雷达系统所需的昂贵模拟前端部件数量的可能性 设计灵感来自于Gregory
  • 自制合成孔径雷达(3) doppler代码解读

    上一篇帖子 xff0c 看完了基于SDR的多普勒雷达 xff0c 就可以看看硬件雷达的多普勒测速的DSP代码了 先看一下这个图 xff1a 我们需要的多普勒频移的测量结果是从混频器 xff08 Multiply Conjugate xff0
  • 各类SDR的USB接口一致性测试

    最近用高带宽示波器测了好几个SDR产品的USB2接口一致性 由于探头数量只有1个 xff0c 所以不能测全所有的项目 但已经包含了最主要的USB眼图 xff08 信号质量 xff09 项目 测试场景 xff1a 待测件包含 xff1a 1
  • Portapack应用开发教程(十八)NavTex接收 D

    上回说到 xff0c 我现在已经做到用自己的gnuradio流图从音频信号做fsk解调 xff0c 得到方波 然后用c程序把方波转为二进制数 又用python把二进制数转为最终的字母 但是遗留问题是python解码 xff0c 起始位如果错
  • Portapack应用开发教程(十八)NavTex接收 E

    我现在已经成功把两部分解码的代码合并到一起 实现的功能是从stdout取出方波的采样点幅度 xff0c 然后把它转为解码输出 include lt stdio h gt include lt string gt include lt mat
  • 使用RTL-SDR和Matlab Simulink玩转软件无线电(二十一)

    3 13 扫描频谱 xff1a 把 25MHz 到 1 75GHz 的信号都收下来 这一节我们会做本章最后一个练习 xff0c 使用一个 RTL SDR 扫描整个频率范围内的信号 对于大多数 RTL SDR 设备来说 xff08 R820T
  • SDR# (SDRSharp)代码讲解 (一)

    SDR 也称SDRSharp 与Linux平台下常用的GQRX类似 xff0c 是目前Windows平台上最常用的频谱观察 xff0c 音频解调软件 xff0c 支持AM FM SSB等多种调制方式 以SDRSharp为基础又派生出了其它一
  • 自动跟随机器人教程(一)(树莓派、Arduino教程)

    机器人购买链接 xff1a https item taobao com item htm spm 61 a1z38n 10677092 0 0 59a21debCqLXYP amp id 61 532012951368 接下来打算发布一款自
  • 自动跟随机器人教程(二)硬件组装

    本机器人结构应该说比较简单 xff0c 除了上述图片里的4样东西外 xff0c 就是一个USB摄像头和一块航模专用12V锂电池 xff08 与电机电压一致 xff09 xff0c 一共6样东西 所有这些东西都不需要螺丝固定 xff0c 多数
  • LimeSDR 中文教程 (一)

    行业应用及合作请联系 j shao 64 limemicro com xff08 本文所有图片请参考Myriadrf官网原文 xff1a https myriadrf org blog limesdr made simple part 1
  • Linux系统——fork()函数详解(看这一篇就够了!!!)

    fork 函数详解 包看包会 xff01 xff01 xff01 1 fork 简介 函数原型 xff1a pid t fork void xff1b pid t为int类型 xff0c 进行了重载pid t getpid 获取当前进程的
  • HttpURLConnection详解、JSON的使用

    1 Http网络请求方法 Http的请求方法代表了客户端想对服务器进行的操作 xff0c 比如 xff1a POST GET HEAD PUT DELETE TRACE OPTIONS 常用的不过于CRUD四个 增 xff1a PUT 删
  • printf二进制输出

    include lt stdio h gt include lt conio h gt include lt stdlib h gt void main int i 61 31 char s 10 itoa i s 2 转换成字符串 xff
  • 秒懂HTTP之基本认证(Basic Authentication)

    版权申明 非商业目的注明出处可自由转载 博文地址 xff1a https blog csdn net ShuSheng0007 article details 89598299 出自 xff1a shusheng007 系列文章 xff1a
  • Linux内核学习(一)8086编程模型

    本文主要介绍Intel8086系列的编程模型 xff0c 包括分段与分页机制 任务切换过程以及中断处理系统 作为Linux内核学习曲线的起点 xff0c 本文的侧重点在于对于每个主题 xff0c 硬件上是如何实现的 xff0c 以及为软件