系统编程入门,第一部分:程序员编写程序(2025)
摘要
一篇系统编程入门文章,涵盖诸如位操作、解析、文件系统、系统调用和内存管理等基础知识,面向程序员。
<p><a href="https://lobste.rs/s/aljull/starting_systems_programming_pt_1">评论</a></p>
查看缓存全文
缓存时间: 2026/05/16 15:13
# startingsystems1.md 来源:https://eblog.fly.dev/startingsystems1.html https://eblog.fly.dev/startingsystems1.html#starting-systems-programming-pt-1-programmers-write-programs
## 系统编程入门,第1部分:程序员编写程序 (https://eblog.fly.dev/startingsystems1.html#starting-systems-programming-pt-1-programmers-write-programs)
Efron Amber Licht 的一篇软件文章
**2025年3月**
https://eblog.fly.dev/startingsystems1.html#all-articles-index-html
### https://eblog.fly.dev/startingsystems1.html#all-articles-index-html
**所有文章** (https://eblog.fly.dev/index.html)
https://eblog.fly.dev/startingsystems1.html#license-license-html
### https://eblog.fly.dev/startingsystems1.html#license-license-html
**许可协议** (https://eblog.fly.dev/license.html)
https://eblog.fly.dev/startingsystems1.html#feeds
### 订阅源 (https://eblog.fly.dev/startingsystems1.html#feeds)
- RSS (https://eblog.fly.dev/feed.rss.xml)
- ATOM (https://eblog.fly.dev/feed.atom.xml)
- JSON (https://eblog.fly.dev/feed.json)
这是关于系统编程基础的四篇文章中的第一篇。它涵盖了许多核心概念,例如位操作、解析、文件系统、输入/输出、系统调用、内存管理和信号。与我的许多系列文章一样,这更像是一个“杂货袋”,而非全面指南——但我希望这对你有所帮助。
- 1. 系列介绍 (https://eblog.fly.dev/startingsystems1.html#1-series-introduction)
- 1.1. 程序员编写程序 (https://eblog.fly.dev/startingsystems1.html#11-programmers-write-programs)
- 关于风格和环境的说明 (https://eblog.fly.dev/startingsystems1.html#note-on-style-environment)
- 给 Python 程序员的说明 (https://eblog.fly.dev/startingsystems1.html#note-for-python-programmers)
- 示例 Go 代码块 (https://eblog.fly.dev/startingsystems1.html#example-go-block)
- 示例 Bash 代码块 (https://eblog.fly.dev/startingsystems1.html#example-bash-block)
- 1.2. 最后的一些注意事项 (https://eblog.fly.dev/startingsystems1.html#12-some-final-caveats)
- 1.3. 系列概览 (https://eblog.fly.dev/startingsystems1.html#13-series-overview)
- 2. 什么是系统编程? (https://eblog.fly.dev/startingsystems1.html#2-what-is-systems-programming)
- 3. 窥探黑箱:程序究竟是什么? (https://eblog.fly.dev/startingsystems1.html#3-peeking-into-the-black-box-what-is-a-program-anyways)
- 3.1. hello.go (https://eblog.fly.dev/startingsystems1.html#31-hellogo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview)
- 3.2. buildhello.bash (https://eblog.fly.dev/startingsystems1.html#32-buildhellobash)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-1)
- 4. 研究数据段 (https://eblog.fly.dev/startingsystems1.html#4-investigating-the-data-segment)
- 4.1. 使用 `findoffset.go` 查找字符串 (https://eblog.fly.dev/startingsystems1.html#41-finding-strings-with-findoffsetgo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-2)
- 本示例中使用的内容 (https://eblog.fly.dev/startingsystems1.html#used-in-this-example)
- findoffset.py:点击此处 (https://eblog.fly.dev/startingsystems1.html#findoffsetpy-click-here)
- 4.2. 使用 `echo.go` 写入简单文件 (https://eblog.fly.dev/startingsystems1.html#42-writing-simple-files-with-echogo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-3)
- 4.3. 使用 `cat.go` 打印文件 (https://eblog.fly.dev/startingsystems1.html#43-printing-files-with-catgo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-4)
- 练习 (https://eblog.fly.dev/startingsystems1.html#exercises)
- 4.4. 使用 `findoffset`、`echo` 和 `cat` 研究 `hello` 程序 (https://eblog.fly.dev/startingsystems1.html#44-investigating-the-hello-program-with-findoffset-echo-and-cat)
- Bash 脚本:`catfox.bash` (https://eblog.fly.dev/startingsystems1.html#bash-script-catfoxbash)
- 4.5. 使用 `binpatch.go` 进行基本破解 (https://eblog.fly.dev/startingsystems1.html#45-basic-hacking-w-binpatchgo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-5)
- 破解一个二进制文件 (https://eblog.fly.dev/startingsystems1.html#hacking-a-binary)
- 4.6. 使用 `torso.go` 深入文件内部 (https://eblog.fly.dev/startingsystems1.html#46-reaching-into-files-with-torsogo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-6)
- 4.7. 探究:`3814697265625` 是怎么回事? (https://eblog.fly.dev/startingsystems1.html#47-investigation-whats-with-3814697265625)
- IN (https://eblog.fly.dev/startingsystems1.html#in)
- OUT (https://eblog.fly.dev/startingsystems1.html#out)
- 5. 研究代码段 (https://eblog.fly.dev/startingsystems1.html#5-investigating-the-code-segment)
- 5.1. 使用 `shexdump.go` 读取二进制文件 (https://eblog.fly.dev/startingsystems1.html#51-reading-binary-files-with-shexdumpgo)
- 练习 (https://eblog.fly.dev/startingsystems1.html#exercises-1)
- 5.2. 使用 `unhexdump.go` 反序列化十六进制转储 (https://eblog.fly.dev/startingsystems1.html#52-deserializing-hexdumps-with-unhexdumpgo)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-7)
- 程序:`unhexdump.go` (https://eblog.fly.dev/startingsystems1.html#program-unhexdumpgo)
- 5.3. hexdump_test.bash (https://eblog.fly.dev/startingsystems1.html#53-hexdump_testbash)
- 概述 (https://eblog.fly.dev/startingsystems1.html#overview-8)
- 5.4. 研究 `hello` 的 ELF 头 (https://eblog.fly.dev/startingsystems1.html#54-investigating-the-elf-header-of-hello)
- 6. 结论:系统编程的精神 (https://eblog.fly.dev/startingsystems1.html#6-conclusion-the-spirit-of-systems-programming)
- 边注:字节序的起源 (https://eblog.fly.dev/startingsystems1.html#sidenote-the-origin-of-endianness)
https://eblog.fly.dev/startingsystems1.html#1-series-introduction
## 1. 系列介绍 (https://eblog.fly.dev/startingsystems1.html#1-series-introduction)
https://eblog.fly.dev/startingsystems1.html#1-1-programmers-write-programs-startingsystems1-md-programmers-write-programs
### 1.1. (https://eblog.fly.dev/startingsystems1.html#1-1-programmers-write-programs-startingsystems1-md-programmers-write-programs)
程序员编写程序 (https://eblog.fly.dev/startingsystems1.md#programmers-write-programs)
你上一次从头开始编写程序是什么时候?对于数量惊人的程序员来说,答案是“在学校”。这是业界一个普遍存在的问题,而且日益严重。我面试过很多候选人,遇到过拥有“Tesla 技术主管”头衔(甚至更糟,首席工程师)的人,他们连最基本的编程能力都没有。我通常的面试问题是“请编写一个 `grep`”——一个本应适合大学一、二年级计算机科学学生的问题——但绝大多数候选人都答不上来。我并不认为他们笨——通常他们并不笨——但他们缺乏编程基础——系统编程基础——这是他们真正“编程”所必需的。这对候选人、对行业、对我们日益计算机化的世界都不利。为什么?构建可靠、直观且高效的软件关键在于最小化复杂性。如果你只能对现有程序进行“添加”,你就被已有的复杂性束缚住了。如果你无法**从头编写一个程序**,你就被困在别人的代码和别人的错误中。**想要擅长某件事,就必须去做。投手投球,画家作画,程序员编程。**因此,这篇文章将专注于**编写程序**——数十个小程序。这样一来,虽然阅读本文的文字内容可能让你学到一些东西,但要想真正充分利用,你需要理解这些程序。我提供了练习来帮助你实践。
https://eblog.fly.dev/startingsystems1.html#note-on-style-environment-startingsystems1-md-note-on-style-environment
#### https://eblog.fly.dev/startingsystems1.html#note-on-style-environment-startingsystems1-md-note-on-style-environment
关于风格和环境的说明 (https://eblog.fly.dev/startingsystems1.md#note-on-style--environment)
在可能的情况下,本系列的代码将尽可能少地使用库。这并不是说你不应该使用库——而是说你不需要**依赖**它们。我想向你展示,你可以用简单的原语制作实用的工具。在本文中,你会看到许多代码块。它们要么是 Go 程序,要么是 Bash shell 脚本。如果你有主流编程语言(如 Python、JavaScript 或 C)的经验,你应该能够跟得上,但你可能需要复习一下指针。Go 使用 `//` 表示注释,而 Bash 和 Python 使用 `#`。我会在每个代码块开头用注释标明语言:`// filename.go` 或 `#!/usr/bin/env bash`。
https://eblog.fly.dev/startingsystems1.html#note-for-python-programmers-startingsystems1-md-note-for-python-programmers
#### https://eblog.fly.dev/startingsystems1.html#note-for-python-programmers-startingsystems1-md-note-for-python-programmers
给 Python 程序员的说明 (https://eblog.fly.dev/startingsystems1.md#note-for-python-programmers)
> **我为本系列中的许多程序提供了 Python 实现**。请查看我的 `gitlab` 仓库中的 `articles/startingsystems/cmd/pythonports` 目录 (https://gitlab.com/efronlicht/blog/-/tree/master/articles/startingsystems/cmd/pythonports?ref_type=heads)。我会尽量在每个 Go 程序的开头链接到相应的文件。Go 程序应始终被视为“权威”版本。我可能会在下一篇文章中继续这一做法,也可能不会——这工作量很大。
---
https://eblog.fly.dev/startingsystems1.html#example-go-block
#### 示例 Go 代码块 (https://eblog.fly.dev/startingsystems1.html#example-go-block)
Go 程序将以 `// filename.go` 开头。
``
1// minimal.go is an example go program.
2// see https://gitlab.com/efronlicht/blog/-/blob/58fb4c13f870a73514284617c71027bbe0a76e2a/articles/startingsystems/cmd/pythonports/minimal.py for the python version.
3package main
4import "fmt"
5func main(){ fmt.Println("this is a go program") }
``
https://eblog.fly.dev/startingsystems1.html#example-bash-block
#### 示例 Bash 代码块 (https://eblog.fly.dev/startingsystems1.html#example-bash-block)
Bash 脚本将以 `#!/usr/bin/env bash` 开头。它们通常包含一系列你可以在终端中运行的命令,位于 `# IN` 注释之后。`# OUT` 注释显示了命令的预期输出。
``
1#!/usr/bin/env bash
2# example.bash demonstrates a simple bash script with an # IN and # OUT section.
3
4# IN:
5echo "this is a bash script"
6
7# OUT:
8this is a bash script
``
> https://eblog.fly.dev/startingsystems1.html#lemma-sidenotes
#### lemma: 边注 (https://eblog.fly.dev/startingsystems1.html#lemma-sidenotes)
边注将以缩进框的形式显示,就像这样。一个“lemma”是为了澄清某个要点而作的小小离题。
https://eblog.fly.dev/startingsystems1.html#lemma-shebang
#### lemma: shebang (`#!`) (https://eblog.fly.dev/startingsystems1.html#lemma-shebang)
文件开头的 shebang (`#!`) 告诉操作系统用什么程序来运行它。例如,`/usr/bin/bash` 会使用位于 `/usr/bin/bash` 的 Bash shell 来运行该文件。`#!/usr/bin/env bash` 则告诉操作系统使用 `PATH` 环境变量中的 `bash` 来运行脚本。我们将在后面的文章中详细讨论所有这些内容。
https://eblog.fly.dev/startingsystems1.html#1-2-some-final-caveats
### 1.2. 最后的一些注意事项 (https://eblog.fly.dev/startingsystems1.html#1-2-some-final-caveats)
- 我对 Linux 比对 Windows、Darwin 或 BSD 熟悉得多,因此本文将以 Linux 为中心。我会偶尔指出 Linux 与其他操作系统的差异——但当我说“操作系统”时,可能仅仅指 Linux。
- 这不可能是全面的指南。理想情况下,你应该具备一些计算机体系结构的基础知识。如果你遇到不懂的术语,比如“nibble”、“register”或“file descriptor”,**不要慌张**——通常你能够跟上。我会为我能想到的内容提供术语表,但肯定会有遗漏。
- 本系列文章提供了大量程序的源代码。**阅读代码是本系列的核心**——代码通常比文字更重要。我强烈建议你边阅读边修改代码。
好了,仪式到此结束。让我们开始吧。
https://eblog.fly.dev/startingsystems1.html#1-3-series-overview
### 1.3. 系列概览 (https://eblog.fly.dev/startingsystems1.html#1-3-series-overview)
1. #### 程序员编写程序 (https://eblog.fly.dev/startingsystems1.html) <—— 你在这里
在本篇文章中,我们将讨论什么是系统编程、什么是程序,以及如何与程序内部的数据进行交互。我们将构建一个程序,挖掘其内部数据,通过破解来改变其行为,并构建一系列软件工具来帮助我们理解它,这些工具将在整个系列中使用。
2. #### 你的程序与外部世界 (https://eblog.fly.dev/startingsystems2.html):命令行参数、环境变量和系统调用
程序如何与外部世界交互?我们将涵盖 UNIX 编程环境的基础知识,包括命令行参数、环境变量和系统调用,并最终构建一个简单的命令行解释器(即 shell)。
3. #### 执行计数:硬件、内存与软件性能 (即将推出)
程序如何与硬件交互?我们将涵盖存储和访问的基础知识——寄存器、内存管理和缓存——讨论调用函数或系统调用时**实际发生了什么**,并提供关于高性能编程的速成课程。
4. #### 等等,全都是 `goto`——编程、虚拟机、汇编、调试和 ABI 的基础 (即将推出)
等等,全都是 `goto`?归根结底,编程就是一些内存、一个指令指针和一系列条件跳转。我们将利用新的系统编程技能构建一个虚拟机与汇编语言,它是 Go 的一个有效子集。我们将借此说明调试器和 ABI 的工作原理。我们将发明一个虚拟机与编程语言,它是 Go 的一个有效子集,并利用它来探索编程和调试的基础。
https://eblog.fly.dev/startingsystems1.html#2-what-is-systems-programming
## 2. 什么是系统编程? (https://eblog.fly.dev/startingsystems1.html#2-what-is-systems-programming)
“系统编程”与其他编程之间没有明确的界限。如果一个问题符合以下条件,它可能属于系统编程:
- 与操作系统或硬件交互
- 有严格的性能约束
- 在“低层次”上操作,涉及单个字节或寄存器
**系统程序员**将计算机视为一台可以完全理解的**物理机器**,而不是数学或形式化的抽象。他们理解计算机系统的**硬件**和**软件**,并且能够**编写程序**与两者交互。系统程序员不惧怕拆解任何东西,因为他们有信心能把它重新组装起来。
https://eblog.fly.dev/startingsystems1.html#3-peeking-into-the-black-box-what-is-a-program-anyways
## 3. 窥探黑箱:程序究竟是什么? (https://eblog.fly.dev/startingsystems1.html#3-peeking-into-the-black-box-what-is-a-program-anyways)
**程序**是一个可执行文件,操作系统可以将其解释为一系列机器指令。也就是说,它是代码和数据的结合体,操作系统可以将其加载到内存中并执行。程序主要有两种类型:
1. 接受输入并产生输出的那种(即过滤
相似文章
以理论构建的视角阅读编程
本文推荐 Peter Naur 的著作《编程即理论构建》,主张编程的本质在于构建和传达对软件的心理模型,而不仅仅是编写代码。
@Franc0Fernand0:如果我要从零开始学习系统设计基础,我会读这16篇精选文章(链接如下)……
一份包含16篇文章的精选清单,推荐给从零开始学习系统设计基础的读者。
软件内部机制读书俱乐部
本文介绍了一个面向资深开发者的全球性电子邮件读书俱乐部,专注于阅读有关数据库、分布式系统和软件性能的技术书籍,目前正在研读《操作系统导论》(Operating Systems: Three Easy Pieces)。
七大编程原语言(2022)
一篇文章探讨了七种构成大多数现代编程语言基础的编程语言原型(原语言),认为学习植根于这些原型的基础知识比选择特定语言更重要。
Prolog编程的陷阱
关于Prolog编程中常见陷阱的指南,强调使用纯声明式构造而非不纯的构造,如cut、全局状态和低级I/O。