<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>操作系统 on 随记</title><link>https://blog.liuyi2026.asia/zh/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/</link><description>Recent content in 操作系统 on 随记</description><generator>Hugo</generator><language>zh</language><lastBuildDate>Thu, 29 May 2025 12:07:17 +0800</lastBuildDate><atom:link href="https://blog.liuyi2026.asia/zh/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/index.xml" rel="self" type="application/rss+xml"/><item><title>16SystemLevelI_O</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/16SystemLevelI_O/</link><pubDate>Thu, 29 May 2025 12:07:17 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/16SystemLevelI_O/</guid><description>&lt;h1 id="概述">概述&lt;a class="anchor" href="#%e6%a6%82%e8%bf%b0">#&lt;/a>&lt;/h1>
&lt;p>从程序员的角度来讨论这个话题
标准的Unix库：printf和scanf&lt;br>
低级IO，直接面向操作系统&lt;br>
&lt;img src="img/ly-20250529121539706.png" alt="" />&lt;/p>
&lt;h1 id="unix-io概括">Unix I/O概括&lt;a class="anchor" href="#unix-io%e6%a6%82%e6%8b%ac">#&lt;/a>&lt;/h1>
&lt;p>用文件(一堆二字节序列)来描述很多抽象的事物，比如I/O设备，打字机；网络连接(套接字)，消息是写入套字节传送，读取套字节接收；&lt;/p>
&lt;p>&lt;img src="img/ly-20250529121931900.png" alt="" />&lt;/p>
&lt;p>文件还有个属性：读取位置；网络套接字不允许在时间上跳转，只能在数据包进入时对其进行读或写&lt;/p>
&lt;h1 id="文件类型">文件类型&lt;a class="anchor" href="#%e6%96%87%e4%bb%b6%e7%b1%bb%e5%9e%8b">#&lt;/a>&lt;/h1>
&lt;p>文件、目录、套接字(作为发送和接收)、应用程序之间接收发送（视频不讲）&lt;br>
符号链接（多指针指向同一文件等）&lt;/p>
&lt;p>&lt;img src="img/ly-20250529122236123.png" alt="" />&lt;/p>
&lt;h1 id="普通文件">普通文件&lt;a class="anchor" href="#%e6%99%ae%e9%80%9a%e6%96%87%e4%bb%b6">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>有些应用程序会区分文本文件和二进制文件(不是在操作系统级别区分，而是在更高级别)
&lt;ul>
&lt;li>主要区别：文本文件只有标准的ASCII字符或者对非英文字符编码的Unicode字符&lt;/li>
&lt;li>二进制文件是&lt;em>图像&lt;/em>或&lt;em>实际目标代码&lt;/em>或&lt;em>音视频文件&lt;/em>等所有其他的文件(这类文件有一个字节序列直接是某种形式编码的数字)&lt;/li>
&lt;li>文本文件：新行 符号，0xa；windows：\r\n &lt;del>0xd 0xa&lt;/del>，Linux：\n &lt;del>0xa&lt;/del>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250529183908746.png" alt="" />&lt;/p>
&lt;h1 id="目录">目录&lt;a class="anchor" href="#%e7%9b%ae%e5%bd%95">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250529184102455.png" alt="" />&lt;/p>
&lt;p>&lt;img src="img/ly-20250529184140034.png" alt="" />&lt;/p>
&lt;h2 id="目录名">目录名&lt;a class="anchor" href="#%e7%9b%ae%e5%bd%95%e5%90%8d">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250529184208311.png" alt="" />&lt;/p>
&lt;h1 id="打开文件">打开文件&lt;a class="anchor" href="#%e6%89%93%e5%bc%80%e6%96%87%e4%bb%b6">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>以指定方式打开文件，这里会返回一个&lt;mark>文件操作符&lt;/mark>&lt;/li>
&lt;li>O_RDONLY（什么模式下访问文件）&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250529221819931.png" alt="" />&lt;/p>
&lt;p>&lt;img src="img/ly-20250529184622815.png" alt="" />&lt;/p>
&lt;ul>
&lt;li>同时打开的文件数量有限&lt;br>
&lt;img src="img/ly-20250529221447419.png" alt="" />&lt;/li>
&lt;/ul>
&lt;p>&lt;mark>每次进行系统调用时都应该检查返回值&lt;/mark>，看看是否存在错误，并采取适当方法处理错误&lt;/p>
&lt;ul>
&lt;li>有几种和终端关联的文件：标准输入、标准输出、标准错误&lt;/li>
&lt;/ul>
&lt;h1 id="关闭文件">关闭文件&lt;a class="anchor" href="#%e5%85%b3%e9%97%ad%e6%96%87%e4%bb%b6">#&lt;/a>&lt;/h1>
&lt;p>多线程中容易出错，关闭已经关闭的文件&lt;/p>
&lt;p>&lt;img src="img/ly-20250529222050340.png" alt="" />&lt;/p>
&lt;h1 id="读文件">读文件&lt;a class="anchor" href="#%e8%af%bb%e6%96%87%e4%bb%b6">#&lt;/a>&lt;/h1>
&lt;p>读入若干字节数（最小是1）&lt;/p></description></item><item><title>21NetworkProgramming01</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/21NetworkProgramming01/</link><pubDate>Thu, 29 May 2025 11:57:41 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/21NetworkProgramming01/</guid><description>&lt;h1 id="主旨">主旨&lt;a class="anchor" href="#%e4%b8%bb%e6%97%a8">#&lt;/a>&lt;/h1>
&lt;p>真正的理解和熟练地编写网络软件&lt;br>
利用与网络编程有关的c语言api&lt;br>
如何建立一个网络系统&lt;/p>
&lt;h1 id="客户端-服务端传输">客户端-服务端传输&lt;a class="anchor" href="#%e5%ae%a2%e6%88%b7%e7%ab%af-%e6%9c%8d%e5%8a%a1%e7%ab%af%e4%bc%a0%e8%be%93">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250529120327058.png" alt="" />&lt;/p>
&lt;h1 id="网络主机的硬件结构">网络主机的硬件结构&lt;a class="anchor" href="#%e7%bd%91%e7%bb%9c%e4%b8%bb%e6%9c%ba%e7%9a%84%e7%a1%ac%e4%bb%b6%e7%bb%93%e6%9e%84">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250529120505341.png" alt="" />&lt;/p>
&lt;p>当你发送信息时，实际上是通过向一个叫做网络的虚拟文件写入数据来实现的；而当你想接收数据时，通过读取该文件来实现&lt;/p></description></item><item><title>09MachineLevelProgramming05AdvancedTopics</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/09MachineLevelProgramming05AdvancedTopics/</link><pubDate>Tue, 27 May 2025 14:59:48 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/09MachineLevelProgramming05AdvancedTopics/</guid><description/></item><item><title>08MachineLevelProgramming04Data</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/08MachineLevelProgramming04Data/</link><pubDate>Tue, 27 May 2025 14:59:38 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/08MachineLevelProgramming04Data/</guid><description>&lt;h1 id="概述">概述&lt;a class="anchor" href="#%e6%a6%82%e8%bf%b0">#&lt;/a>&lt;/h1>
&lt;p>&lt;del>数据表示&lt;/del>&lt;br>
目前都是操作整数、长整数、指针（标量数据），而不是聚合形式的数据&lt;/p>
&lt;p>&lt;em>数组、结构&lt;/em>&lt;/p>
&lt;p>&lt;em>在机器内存中的表现方式&lt;/em>&lt;/p>
&lt;p>数组不过是一堆字节，但是这些字节的集合，是在连续位置上存储的；结构也是如此，作为字节集合来分配的&lt;/p>
&lt;h1 id="数组分配">数组分配&lt;a class="anchor" href="#%e6%95%b0%e7%bb%84%e5%88%86%e9%85%8d">#&lt;/a>&lt;/h1>
&lt;p>x,x+4,x+8这些都是内存地址(机器代码会这么处理)(不是指数组下标)&lt;/p>
&lt;p>&lt;img src="img/ly-20250527162110705.png" alt="" />&lt;/p>
&lt;p>&lt;code>T A[L];&lt;/code>&lt;/p>
&lt;ol>
&lt;li>分配足够的存储字节来保存整个数组&lt;/li>
&lt;li>像对待指针一样对待标识符A&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="img/ly-20250527170620842.png" alt="" />&lt;/p>
&lt;p>对于找val[4]这个元素，汇编中，编译器知道指针类型后，会自动写出合适的缩放因子，不需要程序员手动处理&lt;/p>
&lt;h2 id="例子">例子&lt;a class="anchor" href="#%e4%be%8b%e5%ad%90">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250527195052816.png" alt="" />&lt;/p>
&lt;h2 id="访问数组的例子">访问数组的例子&lt;a class="anchor" href="#%e8%ae%bf%e9%97%ae%e6%95%b0%e7%bb%84%e7%9a%84%e4%be%8b%e5%ad%90">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250527202902490.png" alt="" />&lt;/p>
&lt;h2 id="循环处理数组元素">循环处理数组元素&lt;a class="anchor" href="#%e5%be%aa%e7%8e%af%e5%a4%84%e7%90%86%e6%95%b0%e7%bb%84%e5%85%83%e7%b4%a0">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>&lt;code>ZLEN=5，cmpq b,a&lt;/code> （比较的是a和b），jbe 低于或等于；这里就是说如果%rax 小于或等于4，则跳转到.L4
&lt;blockquote class='book-hint '>
&lt;p>程序解释：先比较 %rax和$4，如果小于或等于0，则跳转到.L4&lt;/p>&lt;/blockquote>&lt;/li>
&lt;li>&lt;code>addl $1,(%rdi,%rax,4)&lt;/code>，首先从内存中读取原始值，进行加法运算，然后将结果放回内存中&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250527212611592.png" alt="" />&lt;/p>
&lt;h1 id="数组和指针之间真正区别">数组和指针之间真正区别&lt;a class="anchor" href="#%e6%95%b0%e7%bb%84%e5%92%8c%e6%8c%87%e9%92%88%e4%b9%8b%e9%97%b4%e7%9c%9f%e6%ad%a3%e5%8c%ba%e5%88%ab">#&lt;/a>&lt;/h1>
&lt;p>当你在c中声明一个数组时，你既在分配空间，分配某个位置的空间，同时，也在创建一个允许在指针运算使用的数组名称。当你只是声明一个指针时，你所分配的只是&lt;mark>指针本身&lt;/mark>的空间，没有给他指向的东西分配空间&lt;/p>
&lt;p>&lt;img src="img/ly-20250605114115594.png" alt="" />&lt;/p>
&lt;h2 id="例子2">例子2&lt;a class="anchor" href="#%e4%be%8b%e5%ad%902">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>【从内往外读】A3是一个指针，指向（由三个int组成的数组）&lt;/li>
&lt;li>A3可能是一个空指针，即 *A3可能为空&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250616214841319.png" alt="" />&lt;/p>
&lt;ul>
&lt;li>优先级排序：()，[],&lt;code>*&lt;/code>，&lt;/li>
&lt;li>A4是三个元素的数组，这些元素是指针，而这些指针指向int&lt;/li>
&lt;/ul>
&lt;h1 id="多维数组">多维数组&lt;a class="anchor" href="#%e5%a4%9a%e7%bb%b4%e6%95%b0%e7%bb%84">#&lt;/a>&lt;/h1></description></item><item><title>07MachineLevelProgramming03Procedures</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/07MachineLevelProgramming03Procedures/</link><pubDate>Mon, 26 May 2025 06:54:40 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/07MachineLevelProgramming03Procedures/</guid><description>&lt;h1 id="概述">概述&lt;a class="anchor" href="#%e6%a6%82%e8%bf%b0">#&lt;/a>&lt;/h1>
&lt;p>procedures：面向过程编程中的函数、过程，或者，面向对象中的方法&lt;br>
abi(应用程序二进制接口): application binary interface。它要求所有Linux程序、编译器、操作系统、系统所有不同部分，都需要对如何管理机器上的资源有一些共同的理解。机器程序级别的接口。&lt;/p>
&lt;ul>
&lt;li>ABI关注的是二进制代码如何在实际硬件上执行和交互&lt;/li>
&lt;li>Windows、Linux 和 macOS 的 ABI（应用程序二进制接口）在核心设计上有显著差异，这导致它们的二进制程序通常无法直接跨平台运行。&lt;/li>
&lt;/ul>
&lt;h1 id="控制函数调用">控制(函数调用)&lt;a class="anchor" href="#%e6%8e%a7%e5%88%b6%e5%87%bd%e6%95%b0%e8%b0%83%e7%94%a8">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250526071813399.png" alt="" />&lt;/p>
&lt;ol>
&lt;li>将控制权转移给另一个函数，且函数执行完毕后返回控制权&lt;/li>
&lt;li>如何传参，以及被调用函数如何将结果传给调用函数&lt;/li>
&lt;li>被调用函数中的局部变量分配问题&lt;/li>
&lt;li>尽量减小过程调用中的开销(对于程序员，良好的编程习惯: 尽量多功能多函数)&lt;/li>
&lt;/ol>
&lt;h1 id="控制权转移">控制权转移&lt;a class="anchor" href="#%e6%8e%a7%e5%88%b6%e6%9d%83%e8%bd%ac%e7%a7%bb">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>stack(栈)：其实只是普通内存的一块区域&lt;/li>
&lt;li>对于汇编层面的程序员来说，内存只是一个巨大的字节数组&lt;/li>
&lt;li>用栈来管理&lt;mark>过程调用与返回&lt;/mark>的状态&lt;/li>
&lt;li>利用栈后进先出的特点：调用函数时需要一些信息，从函数返回需要丢掉一些信息。&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250526082428961.png" alt="" />&lt;/p>
&lt;h2 id="pop">pop&lt;a class="anchor" href="#pop">#&lt;/a>&lt;/h2>
&lt;p>这是三个操作复合成一个操作（先读取，后递减栈指针，最后存储值）&lt;/p>
&lt;p>&lt;img src="img/ly-20250526083358168.png" alt="" />&lt;/p>
&lt;p>栈的释放只是移动栈指针，没有其他特殊操作。数据还在内存中，只不过不是栈的一部分了。&lt;/p>
&lt;h2 id="push">push&lt;a class="anchor" href="#push">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>被push的参数，也必须是寄存器，或立即数。（因为不允许直接从内存传递数据到内存）&lt;/li>
&lt;li>这也是个复合操作：获取操作数，递减栈指针(而且，内存读一个数据，数据的地址指的是它的(最)低地址)，最后写入值&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250526083923083.png" alt="" />&lt;/p>
&lt;h2 id="例子1">例子1&lt;a class="anchor" href="#%e4%be%8b%e5%ad%901">#&lt;/a>&lt;/h2>
&lt;ul>
&lt;li>call和ret引用了栈的思想&lt;/li>
&lt;li>局部变量的存取通过 %rsp 偏移(%rsp-8,%rsp+8之类)实现，不会直接修改 %rsp&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250526084907858.png" alt="" />&lt;/p>
&lt;p>调用前将返回地址压入栈中，然后去执行函数，调用后从栈顶(%rsp)取出调用函数前存的下一条指令的地址，并将%rip(程序计数器[Program Counter, PC]设置为该值&lt;br>
&lt;del>注意：在函数返回前，需通过 add $N, %rsp 或 leave 指令（相当于 mov %rbp, %rsp + pop %rbp）恢复[很重要!!] %rsp 到调用前的状态。&lt;/del>&lt;/p>
&lt;p>&lt;img src="img/ly-20250526085400162.png" alt="" />&lt;/p>
&lt;h2 id="例子2call">例子2(call)&lt;a class="anchor" href="#%e4%be%8b%e5%ad%902call">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250526092359021.png" alt="" />&lt;/p>
&lt;h2 id="例子3ret">例子3(ret)&lt;a class="anchor" href="#%e4%be%8b%e5%ad%903ret">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250526092645689.png" alt="" />&lt;/p></description></item><item><title>06Machine-LevelProgramming02Control</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/06Machine-LevelProgramming02Control/</link><pubDate>Sat, 24 May 2025 17:02:48 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/06Machine-LevelProgramming02Control/</guid><description>&lt;h1 id="概述">概述&lt;a class="anchor" href="#%e6%a6%82%e8%bf%b0">#&lt;/a>&lt;/h1>
&lt;p>本节主要学习如何控制机器级别指令的执行顺序&lt;br>
基本条件语句(条件码，条件分支)、循环(循环)、switch语句&lt;/p>
&lt;h1 id="processorstate">ProcessorState&lt;a class="anchor" href="#processorstate">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250526163512295.png" alt="" />&lt;/p>
&lt;h1 id="1条件码">1.条件码&lt;a class="anchor" href="#1%e6%9d%a1%e4%bb%b6%e7%a0%81">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>CF(无符号)：进位(溢出)&lt;/li>
&lt;li>ZF：刚才的计算结果为零&lt;/li>
&lt;li>SF(有符号)：结果的最高有效位为1(负值)&lt;/li>
&lt;li>OF(有符号)：进位(溢出)&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="img/ly-20250526163759157.png" alt="" />&lt;/p>
&lt;p>这些标志一般情况下会被忽视，当进行&lt;mark>条件&lt;/mark>操作时会被关注&lt;/p>
&lt;h2 id="显式设置1">显式设置1&lt;a class="anchor" href="#%e6%98%be%e5%bc%8f%e8%ae%be%e7%bd%ae1">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250526164945858.png" alt="" />&lt;/p>
&lt;h2 id="显式设置2">显式设置2&lt;a class="anchor" href="#%e6%98%be%e5%bc%8f%e8%ae%be%e7%bd%ae2">#&lt;/a>&lt;/h2>
&lt;p>testq b,a相当于计算 a&amp;amp;b&lt;br>
&lt;img src="img/ly-20250526165157037.png" alt="" />&lt;/p>
&lt;p>如果testq a,a。那么只有当a为零时，ZF才会被设置&lt;/p>
&lt;h1 id="读取条件码">读取条件码&lt;a class="anchor" href="#%e8%af%bb%e5%8f%96%e6%9d%a1%e4%bb%b6%e7%a0%81">#&lt;/a>&lt;/h1>
&lt;p>根据条件码的某种&lt;mark>组合&lt;/mark>，将一个字节设置成0或1&lt;/p>
&lt;ul>
&lt;li>最简单的是，设置ZF条件码的值&lt;code>sete %al&lt;/code>(ZF是什么就设置成什么)
&lt;img src="img/ly-20250526170443671.png" alt="" />&lt;/li>
&lt;/ul>
&lt;h3 id="直接设置寄存器的最低字节">直接设置寄存器的最低字节&lt;a class="anchor" href="#%e7%9b%b4%e6%8e%a5%e8%ae%be%e7%bd%ae%e5%af%84%e5%ad%98%e5%99%a8%e7%9a%84%e6%9c%80%e4%bd%8e%e5%ad%97%e8%8a%82">#&lt;/a>&lt;/h3>
&lt;p>该操作不会影响其他7个字节&lt;/p>
&lt;p>&lt;img src="img/ly-20250526171325831.png" alt="" />&lt;/p>
&lt;h1 id="条件相关例子">条件相关例子&lt;a class="anchor" href="#%e6%9d%a1%e4%bb%b6%e7%9b%b8%e5%85%b3%e4%be%8b%e5%ad%90">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250526172229365.png" alt="" />&lt;/p>
&lt;ul>
&lt;li>%eax是%rax的低四位&lt;/li>
&lt;li>mov指令，从单字节到四字节的零扩展指令&lt;/li>
&lt;li>前两步骤保证了&lt;mark>低四字节的零扩展&lt;/mark>；x86-64保证：任何计算结果是32位(四字节)的计算，会把寄存器&lt;mark>其余32位设置为0(高四字节)&lt;/mark>。但是，如果是单字节，或双字节，只会影响这个单字节或双字节的结果。&lt;/li>
&lt;/ul>
&lt;h1 id="跳转指令">跳转指令&lt;a class="anchor" href="#%e8%b7%b3%e8%bd%ac%e6%8c%87%e4%bb%a4">#&lt;/a>&lt;/h1>
&lt;p>包括无条件跳转/有条件跳转&lt;br>
&lt;img src="img/ly-20250526173302100.png" alt="" />&lt;/p>
&lt;h2 id="传统分支例子">传统分支例子&lt;a class="anchor" href="#%e4%bc%a0%e7%bb%9f%e5%88%86%e6%94%af%e4%be%8b%e5%ad%90">#&lt;/a>&lt;/h2>
&lt;p>jle .L4 表示如果条件码结果表示是 y &amp;lt;=x，则跳转到 .L4&lt;/p>
&lt;p>&lt;img src="img/ly-20250526181327535.png" alt="" />&lt;/p>
&lt;p>&lt;em>使用goto表达上述的汇编代码的意思:&lt;/em>&lt;/p>
&lt;p>&lt;del>goto Else之后，会继续执行Done标签之后的语句，也就是Done标签后的语句是无论判断是否失败都会执行的&lt;/del>&lt;br>
&lt;img src="img/ly-20250526201935480.png" alt="" />&lt;/p>
&lt;h3 id="编译器翻译">编译器翻译&lt;a class="anchor" href="#%e7%bc%96%e8%af%91%e5%99%a8%e7%bf%bb%e8%af%91">#&lt;/a>&lt;/h3>
&lt;p>&lt;img src="img/ly-20250526202542218.png" alt="" />&lt;/p>
&lt;p>Done表示这个C Code后面的所有逻辑代码&lt;/p>
&lt;h2 id="条件移动">条件移动&lt;a class="anchor" href="#%e6%9d%a1%e4%bb%b6%e7%a7%bb%e5%8a%a8">#&lt;/a>&lt;/h2>
&lt;p>result是最后的结果。先把两个结果都算出来，result默认先赋值给其中一个。如果&lt;mark>判断错误，则修改result（有条件的移动）&lt;/mark>，否则直接返回。&lt;/p>
&lt;p>&lt;img src="img/ly-20250526212833533.png" alt="" />&lt;/p>
&lt;ol>
&lt;li>用“提前计算 + 条件选择”取代“分支预测”，避免流水线清空。&lt;/li>
&lt;li>只是 根据条件选择寄存器值，没有跳转，完全避免分支预测错误&lt;/li>
&lt;/ol>
&lt;ul>
&lt;li>假设你知道的指令序列正在代码海洋中巡航，这些指令可以很顺畅的执行，因为他们使用了所谓的流水线技术。这意味着他们&lt;mark>在完成下一个指令之前就开始执行下一个指令的一部分&lt;/mark>，实际上流水线能达到20条以上指令的深度，能达到的深度取决于提前获取的指令的条数，&lt;mark>当完成一些指令时仍然有另一些指令留在流水线上&lt;/mark>，这就是我的海洋线或我的游轮类比。但突然他们到达一个分支会发生什么？他们会试着猜测分支结果，这被称为分支预测技术，猜测会运行哪个分支。在你熟悉的情况下，条件分支将被采用或将被落空，并且他们非常擅长预测，98%的时候他们都能猜对，所以他们甚至可以在路上预测suta曲线，并且开始朝着这个方向前进，只要猜测正确，就会非常有效率。&lt;mark>但是，如果分支猜错了，你必须阻止它并转向另一个方向重新开始，在较差的情况下，可能需要40个指令40个时钟周期&lt;/mark>&lt;/li>
&lt;li>通过&lt;mark>先执行两个分支&lt;/mark>来提高效率要容易得多，&lt;mark>在最后一分钟，你要做的就是是否将值移入寄存器&lt;/mark>，这并&lt;mark>不需要暂停整个处理器的执行然后重新选择分支&lt;/mark>执行&lt;/li>
&lt;/ul>
&lt;h3 id="conditionmoveexample">ConditionMoveExample&lt;a class="anchor" href="#conditionmoveexample">#&lt;/a>&lt;/h3>
&lt;p>CMOV是单条指令，不会打断 CPU 的指令流水线。
&lt;img src="img/ly-20250526221147756.png" alt="" />&lt;/p></description></item><item><title>05MachineLevelProgramming01Basic</title><link>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/05MachineLevelProgramming01Basic/</link><pubDate>Sun, 19 Jan 2025 09:34:54 +0800</pubDate><guid>https://blog.liuyi2026.asia/zh/docs/technology/System/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%B3%BB%E7%BB%9F/%E8%A7%86%E9%A2%91%E7%AC%94%E8%AE%B0/05MachineLevelProgramming01Basic/</guid><description>&lt;h1 id="概述">概述&lt;a class="anchor" href="#%e6%a6%82%e8%bf%b0">#&lt;/a>&lt;/h1>
&lt;p>计算机为了运行程序，会执行一串独立的指令&lt;br>
两种形式的机器语言：&lt;/p>
&lt;ol>
&lt;li>在计算机上运行的实际目标代码（字节，二进制01）&lt;/li>
&lt;li>汇编代码（编译器的目标，文本格式）&lt;/li>
&lt;/ol>
&lt;p>不写汇编，但需要学习：&lt;/p>
&lt;ol>
&lt;li>编译器产生的结果（汇编及目标代码）与文本代码关联&lt;/li>
&lt;li>低级代码（汇编、二进制）如何实现高级别程序构造&lt;/li>
&lt;li>过程函数、结构体、数组在机器语言中的实现&lt;/li>
&lt;/ol>
&lt;p>课程选择64位版本的Intel指令集&lt;br>
为什么叫x86处理器&lt;del>16位微处理器&lt;/del>(也称CISC&lt;code>复杂&lt;/code>，与之对应的是RISC&lt;code>精简&lt;/code>)，因为一开始的处理器是8086，接着8286,8386&amp;hellip;&lt;br>
需要更加关注&amp;ndash;gcc编译生成的代码长什么样&lt;/p>
&lt;h1 id="x86进化">x86进化&lt;a class="anchor" href="#x86%e8%bf%9b%e5%8c%96">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250524215533438.png" alt="" />&lt;/p>
&lt;h1 id="多核处理器">多核处理器&lt;a class="anchor" href="#%e5%a4%9a%e6%a0%b8%e5%a4%84%e7%90%86%e5%99%a8">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250524215618621.png" alt="" />&lt;/p>
&lt;p>&lt;img src="img/ly-20250524215936110.png" alt="" />&lt;/p>
&lt;p>另一个公司：AMD&lt;br>
&lt;img src="img/ly-20250524221923709.png" alt="" />&lt;/p>
&lt;h1 id="教学范围">教学范围&lt;a class="anchor" href="#%e6%95%99%e5%ad%a6%e8%8c%83%e5%9b%b4">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250524222101769.png" alt="" />&lt;/p>
&lt;h1 id="哪些处理器">哪些处理器&lt;a class="anchor" href="#%e5%93%aa%e4%ba%9b%e5%a4%84%e7%90%86%e5%99%a8">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>ARM(AcornRISCMachine)，比x86机器功耗更低&lt;/li>
&lt;li>x86&lt;/li>
&lt;/ul>
&lt;h1 id="定义">定义&lt;a class="anchor" href="#%e5%ae%9a%e4%b9%89">#&lt;/a>&lt;/h1>
&lt;ul>
&lt;li>指令集&lt;/li>
&lt;li>寄存器：非常小的内存位置&lt;/li>
&lt;li>机器指令&lt;br>
&lt;img src="img/ly-20250524223748161.png" alt="" />&lt;/li>
&lt;/ul>
&lt;p>（无法直接操作缓存(没有这个概念），是机器级别的概念)&lt;/p>
&lt;h1 id="将c源代码转换成目标文件">将c源代码转换成目标文件&lt;a class="anchor" href="#%e5%b0%86c%e6%ba%90%e4%bb%a3%e7%a0%81%e8%bd%ac%e6%8d%a2%e6%88%90%e7%9b%ae%e6%a0%87%e6%96%87%e4%bb%b6">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250524224747058.png" alt="" />&lt;/p>
&lt;h1 id="汇编简介">汇编简介&lt;a class="anchor" href="#%e6%b1%87%e7%bc%96%e7%ae%80%e4%bb%8b">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250524225343526.png" alt="" />&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-shell" data-lang="shell">&lt;span style="display:flex;">&lt;span>gcc -Og -S sum.c &lt;span style="color:#75715e">#-Og 调试级别的优化过的（英文字母大写O)； -S 生成汇编 &lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="img/ly-20250525001250355.png" alt="" />&lt;br>
带点的这些，是给调试器用的(用来定位)；也有一些是给链接器用（告诉它这是个全局定义的函数）&lt;/p>
&lt;h2 id="数据类型">数据类型&lt;a class="anchor" href="#%e6%95%b0%e6%8d%ae%e7%b1%bb%e5%9e%8b">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250525001625314.png" alt="" />&lt;/p>
&lt;ol>
&lt;li>多种整数数据类型（不区分符号与无符号，都以数字形式存储在计算机）&lt;/li>
&lt;li>浮点（使用和整型不一样的寄存器组）&lt;/li>
&lt;li>程序本身在x86中，是一系列字节&lt;/li>
&lt;li>没有数组或结构，由编译器人工处理&lt;/li>
&lt;/ol>
&lt;h2 id="指令">指令&lt;a class="anchor" href="#%e6%8c%87%e4%bb%a4">#&lt;/a>&lt;/h2>
&lt;p>每条指令做的事很有限（只做一件小事）
&lt;img src="img/ly-20250525002329491.png" alt="" />&lt;/p>
&lt;h2 id="反汇编">反汇编&lt;a class="anchor" href="#%e5%8f%8d%e6%b1%87%e7%bc%96">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250525003437180.png" alt="" />&lt;/p>
&lt;h2 id="举例">举例&lt;a class="anchor" href="#%e4%b8%be%e4%be%8b">#&lt;/a>&lt;/h2>
&lt;p>&lt;img src="img/ly-20250525002329491.png" alt="" />&lt;/p>
&lt;ul>
&lt;li>变量的概念在汇编级别代码中完全消失（变成了寄存器或内存中某个东西）&lt;/li>
&lt;/ul>
&lt;h1 id="使用gdb反汇编">使用gdb反汇编&lt;a class="anchor" href="#%e4%bd%bf%e7%94%a8gdb%e5%8f%8d%e6%b1%87%e7%bc%96">#&lt;/a>&lt;/h1>
&lt;p>&lt;img src="img/ly-20250525133614958.png" alt="" />&lt;/p></description></item></channel></rss>