<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>SakiMidare&apos;s Blog</title><description>A personal blog site.</description><link>https://sakimidare.top/</link><language>zh_CN</language><item><title>Bomb Lab Writeup</title><link>https://sakimidare.top/posts/bomb-lab/</link><guid isPermaLink="true">https://sakimidare.top/posts/bomb-lab/</guid><pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;前言&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;邪恶的&lt;strong&gt;邪恶博士&lt;/strong&gt;在我们的班级机器上放置了大量的“二进制炸弹”。二进制炸弹是由一系列阶段组成的程序。每个阶段都要求你在 stdin 上键入一个特定的字符串。如果你输入了正确的字符串，那么这个阶段就被&lt;strong&gt;拆除&lt;/strong&gt;，炸弹进入下一个阶段。否则炸弹会&lt;strong&gt;爆炸&lt;/strong&gt;，并打印出 “BOOM!!!”，然后终止。当每一个阶段都被拆除时，炸弹才算拆除。&lt;/p&gt;
&lt;p&gt;有太多炸弹要我们处理，所以我们给每个学生一个炸弹来拆除。这是你的任务，你别无选择，只能接受，就是在截止时间前拆除你的炸弹。祝你好运，欢迎加入拆弹小组！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;开始&lt;/h1&gt;
&lt;p&gt;:::note
本 WriteUp 所有操作均在 &lt;code&gt;Linux sakimidare-arch 7.0.2-arch1-1-lily #1 SMP PREEMPT_DYNAMIC Thu, 30 Apr 2026 05:29:46 +0000 x86_64 GNU/Linux&lt;/code&gt; 上进行。
:::&lt;/p&gt;
&lt;p&gt;我拿到了一个 &lt;code&gt;bomb.tar&lt;/code&gt;，目录结构如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.
├── bomb
├── bomb.c
└── README

1 directory, 3 files
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们的目标是尽可能多地拆除炸弹（获取正确的拆弹密钥）。&lt;/p&gt;
&lt;p&gt;首先来看 &lt;code&gt;bomb.c&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/***************************************************************************
 * Dr. Evil&apos;s Insidious Bomb, Version 1.1
 * Copyright 2011, Dr. Evil Incorporated. All rights reserved.
 *
 * LICENSE:
 *
 * Dr. Evil Incorporated (the PERPETRATOR) hereby grants you (the
 * VICTIM) explicit permission to use this bomb (the BOMB).  This is a
 * time limited license, which expires on the death of the VICTIM.
 * The PERPETRATOR takes no responsibility for damage, frustration,
 * insanity, bug-eyes, carpal-tunnel syndrome, loss of sleep, or other
 * harm to the VICTIM.  Unless the PERPETRATOR wants to take credit,
 * that is.  The VICTIM may not distribute this bomb source code to
 * any enemies of the PERPETRATOR.  No VICTIM may debug,
 * reverse-engineer, run &quot;strings&quot; on, decompile, decrypt, or use any
 * other technique to gain knowledge of and defuse the BOMB.  BOMB
 * proof clothing may not be worn when handling this program.  The
 * PERPETRATOR will not apologize for the PERPETRATOR&apos;s poor sense of
 * humor.  This license is null and void where the BOMB is prohibited
 * by law.
 ***************************************************************************/

#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &quot;support.h&quot;
#include &quot;phases.h&quot;

/* 
 * Note to self: Remember to erase this file so my victims will have no
 * idea what is going on, and so they will all blow up in a
 * spectaculary fiendish explosion. -- Dr. Evil 
 */

FILE *infile;

int main(int argc, char *argv[])
{
    char *input;

    /* Note to self: remember to port this bomb to Windows and put a 
     * fantastic GUI on it. */

    /* When run with no arguments, the bomb reads its input lines 
     * from standard input. */
    if (argc == 1) {  
	infile = stdin;
    } 

    /* When run with one argument &amp;lt;file&amp;gt;, the bomb reads from &amp;lt;file&amp;gt; 
     * until EOF, and then switches to standard input. Thus, as you 
     * defuse each phase, you can add its defusing string to &amp;lt;file&amp;gt; and
     * avoid having to retype it. */
    else if (argc == 2) {
	if (!(infile = fopen(argv[1], &quot;r&quot;))) {
	    printf(&quot;%s: Error: Couldn&apos;t open %s\n&quot;, argv[0], argv[1]);
	    exit(8);
	}
    }

    /* You can&apos;t call the bomb with more than 1 command line argument. */
    else {
	printf(&quot;Usage: %s [&amp;lt;input_file&amp;gt;]\n&quot;, argv[0]);
	exit(8);
    }

    /* Do all sorts of secret stuff that makes the bomb harder to defuse. */
    initialize_bomb();

    printf(&quot;Welcome to my fiendish little bomb. You have 6 phases with\n&quot;);
    printf(&quot;which to blow yourself up. Have a nice day!\n&quot;);

    /* Hmm...  Six phases must be more secure than one phase! */
    input = read_line();             /* Get input                   */
    phase_1(input);                  /* Run the phase               */
    phase_defused();                 /* Drat!  They figured it out!
				      * Let me know how they did it. */
    printf(&quot;Phase 1 defused. How about the next one?\n&quot;);

    /* The second phase is harder.  No one will ever figure out
     * how to defuse this... */
    input = read_line();
    phase_2(input);
    phase_defused();
    printf(&quot;That&apos;s number 2.  Keep going!\n&quot;);

    /* I guess this is too easy so far.  Some more complex code will
     * confuse people. */
    input = read_line();
    phase_3(input);
    phase_defused();
    printf(&quot;Halfway there!\n&quot;);

    /* Oh yeah?  Well, how good is your math?  Try on this saucy problem! */
    input = read_line();
    phase_4(input);
    phase_defused();
    printf(&quot;So you got that one.  Try this one.\n&quot;);
    
    /* Round and &apos;round in memory we go, where we stop, the bomb blows! */
    input = read_line();
    phase_5(input);
    phase_defused();
    printf(&quot;Good work!  On to the next...\n&quot;);

    /* This phase will never be used, since no one will get past the
     * earlier ones.  But just in case, make this one extra hard. */
    input = read_line();
    phase_6(input);
    phase_defused();

    /* Wow, they got it!  But isn&apos;t something... missing?  Perhaps
     * something they overlooked?  Mua ha ha ha ha! */
    
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;support.h&lt;/code&gt; 和 &lt;code&gt;phases.h&lt;/code&gt; 并没有提供，源码中的 &lt;code&gt;initialize_bomb()&lt;/code&gt;, &lt;code&gt;read_line()&lt;/code&gt;, &lt;code&gt;phase_x()&lt;/code&gt;, &lt;code&gt;phase_defused()&lt;/code&gt; 未提供定义。这就需要我们用反汇编推出这几个函数内部的逻辑并猜出密钥。&lt;/p&gt;
&lt;p&gt;推测原型:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void initialize_bomb();
char* read_line();
void phase_x(char*);
void phase_defused();
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;反汇编&lt;/h1&gt;
&lt;p&gt;首先用 &lt;code&gt;readelf&lt;/code&gt; 看一眼这个 ELF 文件的布局：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;readelf -a bomb 
ELF 头：
  Magic：  7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  类别:                              ELF64
  数据:                              2 补码，小端序 (little endian)
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI 版本:                          0
  类型:                              EXEC (可执行文件)
  系统架构:                          Advanced Micro Devices X86-64
  版本:                              0x1
  入口点地址：              0x400c90
  程序头起点：              64 (bytes into file)
  Start of section headers:          18616 (bytes into file)
  标志：             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         36
  Section header string table index: 33

节头：
  [号] 名称              类型             地址              偏移量
       大小              全体大小          旗标   链接   信息   对齐
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000400238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000400254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.bu[...] NOTE             0000000000400274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000400298  00000298
       0000000000000030  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000004002c8  000002c8
       0000000000000300  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           00000000004005c8  000005c8
       000000000000016d  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000400736  00000736
       0000000000000040  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000400778  00000778
       0000000000000060  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             00000000004007d8  000007d8
       0000000000000060  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000400838  00000838
       0000000000000288  0000000000000018   A       5    12     8
  [11] .init             PROGBITS         0000000000400ac0  00000ac0
       000000000000000e  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         0000000000400ad0  00000ad0
       00000000000001c0  0000000000000010  AX       0     0     16
  [13] .text             PROGBITS         0000000000400c90  00000c90
       0000000000001614  0000000000000000  AX       0     0     16
  [14] .fini             PROGBITS         00000000004022a4  000022a4
       0000000000000009  0000000000000000  AX       0     0     4
  [15] .rodata           PROGBITS         00000000004022b0  000022b0
       00000000000004e5  0000000000000000   A       0     0     16
  [16] .eh_frame_hdr     PROGBITS         0000000000402798  00002798
       0000000000000104  0000000000000000   A       0     0     4
  [17] .eh_frame         PROGBITS         00000000004028a0  000028a0
       0000000000000454  0000000000000000   A       0     0     8
  [18] .init_array       INIT_ARRAY       0000000000602df8  00002df8
       0000000000000008  0000000000000000  WA       0     0     8
  [19] .fini_array       FINI_ARRAY       0000000000602e00  00002e00
       0000000000000008  0000000000000000  WA       0     0     8
  [20] .jcr              PROGBITS         0000000000602e08  00002e08
       0000000000000008  0000000000000000  WA       0     0     8
  [21] .dynamic          DYNAMIC          0000000000602e10  00002e10
       00000000000001d0  0000000000000010  WA       6     0     8
  [22] .got              PROGBITS         0000000000602fe0  00002fe0
       0000000000000008  0000000000000008  WA       0     0     8
  [23] .got.plt          PROGBITS         0000000000602fe8  00002fe8
       00000000000000f0  0000000000000008  WA       0     0     8
  [24] .data             PROGBITS         00000000006030e0  000030e0
       0000000000000660  0000000000000000  WA       0     0     32
  [25] .bss              NOBITS           0000000000603740  00003740
       00000000000006d0  0000000000000000  WA       0     0     32
  [26] .comment          PROGBITS         0000000000000000  00003740
       0000000000000053  0000000000000001  MS       0     0     1
  [27] .debug_aranges    PROGBITS         0000000000000000  00003793
       0000000000000030  0000000000000000           0     0     1
  [28] .debug_info       PROGBITS         0000000000000000  000037c3
       00000000000007a3  0000000000000000           0     0     1
  [29] .debug_abbrev     PROGBITS         0000000000000000  00003f66
       000000000000021f  0000000000000000           0     0     1
  [30] .debug_line       PROGBITS         0000000000000000  00004185
       0000000000000161  0000000000000000           0     0     1
  [31] .debug_str        PROGBITS         0000000000000000  000042e6
       00000000000002f3  0000000000000001  MS       0     0     1
  [32] .debug_loc        PROGBITS         0000000000000000  000045d9
       0000000000000188  0000000000000000           0     0     1
  [33] .shstrtab         STRTAB           0000000000000000  00004761
       0000000000000153  0000000000000000           0     0     1
  [34] .symtab           SYMTAB           0000000000000000  000051b8
       0000000000000eb8  0000000000000018          35    57     8
  [35] .strtab           STRTAB           0000000000000000  00006070
       00000000000006b6  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

There are no section groups in this file.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对我们有用的部分是 &lt;code&gt;.text&lt;/code&gt; 和 &lt;code&gt;.rodata&lt;/code&gt; 段。前者保存机器码，后者保存用到的常量（包括字符串）。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;initialize_bomb()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb -disassemble=initialize_bomb
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --disassemble=initialize_bomb

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

00000000004013a2 &amp;lt;initialize_bomb&amp;gt;:
  4013a2:       48 83 ec 08             sub    $0x8,%rsp
  4013a6:       be a0 12 40 00          mov    $0x4012a0,%esi
  4013ab:       bf 02 00 00 00          mov    $0x2,%edi
  4013b0:       e8 db f7 ff ff          call   400b90 &amp;lt;signal@plt&amp;gt;
  4013b5:       48 83 c4 08             add    $0x8,%rsp
  4013b9:       c3                      ret

Disassembly of section .fini:

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;%edi&lt;/code&gt; &lt;code&gt;%esi&lt;/code&gt; 按照惯例来讲应该是函数的两个参数。&lt;code&gt;%rsp&lt;/code&gt; 是栈指针，指向当前栈顶。上述汇编从栈中弹出一个四字（不用 &lt;code&gt;popq&lt;/code&gt; 大概是为了不污染 &lt;code&gt;%rax&lt;/code&gt;），并赋了两个魔数给两个寄存器，并调用了 &lt;code&gt;400b90&lt;/code&gt; 这个地方的函数 &lt;code&gt;&amp;lt;signal@plt&amp;gt;&lt;/code&gt; 。我们继续去反编译 &lt;code&gt;signal&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;0000000000400b90 &amp;lt;signal@plt&amp;gt;:
  400b90:       ff 25 c2 24 20 00       jmp    *0x2024c2(%rip)        # 603058 &amp;lt;signal@GLIBC_2.2.5&amp;gt;
  400b96:       68 0b 00 00 00          push   $0xb
  400b9b:       e9 30 ff ff ff          jmp    400ad0 &amp;lt;.plt&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;0000000000400ad0 &amp;lt;.plt&amp;gt;:
  400ad0:       ff 35 1a 25 20 00       push   0x20251a(%rip)        # 602ff0 &amp;lt;_GLOBAL_OFFSET_TABLE_+0x8&amp;gt;
  400ad6:       ff 25 1c 25 20 00       jmp    *0x20251c(%rip)        # 602ff8 &amp;lt;_GLOBAL_OFFSET_TABLE_+0x10&amp;gt;
  400adc:       0f 1f 40 00             nopl   0x0(%rax)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;坏事了，这个函数并不在我们的二进制文件里，而是动态链接到了 glibc 里面的 &lt;code&gt;signal&lt;/code&gt; 函数。&lt;/p&gt;
&lt;p&gt;查阅相关资料，发现 &lt;code&gt;signal&lt;/code&gt; 函数原型如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;signal.h&amp;gt;

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代入&lt;code&gt;%edi&lt;/code&gt;，&lt;code&gt;%esi&lt;/code&gt;，发现调用的函数是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sighandler_t signal(0x2, 0x4012a0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过查表：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ man signal

SIGNAL(7)                                                         Linux Programmer&apos;s Manual                                                        SIGNAL(7)

NAME
     signal - 有效信号的清单

描述 (DESCRIPTION)
     下面 列出 Linux 支持的 信号. 某些 信号 依赖于 体系结构(architecture).

     首先, POSIX.1 描述了 下列 信号.

     信号         值      动作   说明
     ─────────────────────────────────────────────────────────────────────
     SIGHUP        1       A     在控制终端上是挂起信号, 或者控制进程结束
     SIGINT        2       A     从键盘输入的中断
     SIGQUIT       3       C     从键盘输入的退出
     SIGILL        4       C     无效硬件指令
     SIGABRT       6       C     非正常终止, 可能来自 abort(3)
     SIGFPE        8       C     浮点运算例外
     SIGKILL       9      AEF    杀死进程信号
     SIGSEGV      11       C     无效的内存引用
     SIGPIPE      13       A     管道中止: 写入无人读取的管道
     SIGALRM      14       A     来自 alarm(2) 的超时信号
     SIGTERM      15       A     终止信号
     SIGUSR1   30,10,16    A     用户定义的信号 1
     SIGUSR2   31,12,17    A     用户定义的信号 2
     SIGCHLD   20,17,18    B     子进程结束或停止
     SIGCONT   19,18,25          继续停止的进程
     SIGSTOP   17,19,23   DEF    停止进程
     SIGTSTP   18,20,24    D     终端上发出的停止信号
     SIGTTIN   21,21,26    D     后台进程试图从控制终端(tty)输入
     SIGTTOU   22,22,27    D     后台进程试图在控制终端(tty)输出
...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现 &lt;code&gt;0x2&lt;/code&gt; 对应 &lt;code&gt;SIGINT&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SIGFPE&lt;/code&gt; 是键盘上按下 &lt;code&gt;Ctrl&lt;/code&gt;+&lt;code&gt;C&lt;/code&gt;时 Linux 向程序发送的信号。上面的函数捕获了这个信号并注册了一个函数，地址在&lt;code&gt;0x4012a0&lt;/code&gt;。通过&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;typedef void (*sighandler_t)(int);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们还能知道函数钩子的原型是 &lt;code&gt;void foo(int);&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;接下来反汇编 &lt;code&gt;0x4012a0&lt;/code&gt; 处的函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -d --start-address=0x4012a0 --stop-address=0x4013a0 bomb

bomb：     文件格式 elf64-x86-64


Disassembly of section .text:

00000000004012a0 &amp;lt;sig_handler&amp;gt;:
  4012a0:       48 83 ec 08             sub    $0x8,%rsp
  4012a4:       bf c0 24 40 00          mov    $0x4024c0,%edi
  4012a9:       e8 62 f8 ff ff          call   400b10 &amp;lt;puts@plt&amp;gt;
  4012ae:       bf 03 00 00 00          mov    $0x3,%edi
  4012b3:       e8 98 f9 ff ff          call   400c50 &amp;lt;sleep@plt&amp;gt;
  4012b8:       be 82 25 40 00          mov    $0x402582,%esi
  4012bd:       bf 01 00 00 00          mov    $0x1,%edi
  4012c2:       b8 00 00 00 00          mov    $0x0,%eax
  4012c7:       e8 34 f9 ff ff          call   400c00 &amp;lt;__printf_chk@plt&amp;gt;
  4012cc:       48 8b 3d 6d 24 20 00    mov    0x20246d(%rip),%rdi        # 603740 &amp;lt;stdout@GLIBC_2.2.5&amp;gt;
  4012d3:       e8 08 f9 ff ff          call   400be0 &amp;lt;fflush@plt&amp;gt;
  4012d8:       bf 01 00 00 00          mov    $0x1,%edi
  4012dd:       e8 6e f9 ff ff          call   400c50 &amp;lt;sleep@plt&amp;gt;
  4012e2:       bf 8a 25 40 00          mov    $0x40258a,%edi
  4012e7:       e8 24 f8 ff ff          call   400b10 &amp;lt;puts@plt&amp;gt;
  4012ec:       bf 10 00 00 00          mov    $0x10,%edi
  4012f1:       e8 2a f9 ff ff          call   400c20 &amp;lt;exit@plt&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个函数大量调用了 &lt;code&gt;puts()&lt;/code&gt; &lt;code&gt;sleep()&lt;/code&gt; &lt;code&gt;fflush()&lt;/code&gt; &lt;code&gt;exit()&lt;/code&gt; 等函数，猜测与炸弹密钥无关。但为了保险，我们先看看 &lt;code&gt;puts()&lt;/code&gt; 都输出了什么东西。&lt;/p&gt;
&lt;p&gt;查看 &lt;code&gt;0x4024c0&lt;/code&gt; &lt;code&gt;0x400b10&lt;/code&gt;对应的汇编：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -s -j .rodata bomb | grep -A 5 &quot;4024c0&quot;
 4024c0 536f2079 6f752074 68696e6b 20796f75  So you think you
 4024d0 2063616e 2073746f 70207468 6520626f   can stop the bo
 4024e0 6d622077 69746820 6374726c 2d632c20  mb with ctrl-c, 
 4024f0 646f2079 6f753f00 43757273 65732c20  do you?.Curses, 
 402500 796f7527 76652066 6f756e64 20746865  you&apos;ve found the
 402510 20736563 72657420 70686173 65210000   secret phase!..
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好吧确实没啥关系……不管了我们接着看下一个函数。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;phase_1()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -d bomb --disassemble=phase_1

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

0000000000400ee0 &amp;lt;phase_1&amp;gt;:
  400ee0:       48 83 ec 08             sub    $0x8,%rsp
  400ee4:       be 00 24 40 00          mov    $0x402400,%esi
  400ee9:       e8 4a 04 00 00          call   401338 &amp;lt;strings_not_equal&amp;gt;
  400eee:       85 c0                   test   %eax,%eax
  400ef0:       74 05                   je     400ef7 &amp;lt;phase_1+0x17&amp;gt;
  400ef2:       e8 43 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400ef7:       48 83 c4 08             add    $0x8,%rsp
  400efb:       c3                      ret

Disassembly of section .fini:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 &lt;code&gt;0x402400&lt;/code&gt; 处的汇编：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -s -j .rodata bomb | grep -A 10 &quot;402400&quot;
 402400 426f7264 65722072 656c6174 696f6e73  Border relations
 402410 20776974 68204361 6e616461 20686176   with Canada hav
 402420 65206e65 76657220 6265656e 20626574  e never been bet
 402430 7465722e 00000000 576f7721 20596f75  ter.....Wow! You
 402440 27766520 64656675 73656420 74686520  &apos;ve defused the 
 402450 73656372 65742073 74616765 2100666c  secret stage!.fl
 402460 79657273 00000000 00000000 00000000  yers............
 402470 7c0f4000 00000000 b90f4000 00000000  |.@.......@.....
 402480 830f4000 00000000 8a0f4000 00000000  ..@.......@.....
 402490 910f4000 00000000 980f4000 00000000  ..@.......@.....
 4024a0 9f0f4000 00000000 a60f4000 00000000  ..@.......@.....
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意这一行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 402430 7465722e 00000000 576f7721 20596f75  ter.....Wow! You
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;00&lt;/code&gt;标志着 C 风格字符串的结尾。也就是说，这个字符串的内容是:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Border relations with Canada have never been better.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;查看 &lt;code&gt;401338&lt;/code&gt; 的汇编：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --start-address=0x401338 --stop-address=0x401400

bomb：     文件格式 elf64-x86-64


Disassembly of section .text:

0000000000401338 &amp;lt;strings_not_equal&amp;gt;:
  401338:       41 54                   push   %r12
  40133a:       55                      push   %rbp
  40133b:       53                      push   %rbx
  40133c:       48 89 fb                mov    %rdi,%rbx
  40133f:       48 89 f5                mov    %rsi,%rbp
  401342:       e8 d4 ff ff ff          call   40131b &amp;lt;string_length&amp;gt;
  401347:       41 89 c4                mov    %eax,%r12d
  40134a:       48 89 ef                mov    %rbp,%rdi
  40134d:       e8 c9 ff ff ff          call   40131b &amp;lt;string_length&amp;gt;
  401352:       ba 01 00 00 00          mov    $0x1,%edx
  401357:       41 39 c4                cmp    %eax,%r12d
  40135a:       75 3f                   jne    40139b &amp;lt;strings_not_equal+0x63&amp;gt;
  40135c:       0f b6 03                movzbl (%rbx),%eax
  40135f:       84 c0                   test   %al,%al
  401361:       74 25                   je     401388 &amp;lt;strings_not_equal+0x50&amp;gt;
  401363:       3a 45 00                cmp    0x0(%rbp),%al
  401366:       74 0a                   je     401372 &amp;lt;strings_not_equal+0x3a&amp;gt;
  401368:       eb 25                   jmp    40138f &amp;lt;strings_not_equal+0x57&amp;gt;
  40136a:       3a 45 00                cmp    0x0(%rbp),%al
  40136d:       0f 1f 00                nopl   (%rax)
  401370:       75 24                   jne    401396 &amp;lt;strings_not_equal+0x5e&amp;gt;
  401372:       48 83 c3 01             add    $0x1,%rbx
  401376:       48 83 c5 01             add    $0x1,%rbp
  40137a:       0f b6 03                movzbl (%rbx),%eax
  40137d:       84 c0                   test   %al,%al
  40137f:       75 e9                   jne    40136a &amp;lt;strings_not_equal+0x32&amp;gt;
  401381:       ba 00 00 00 00          mov    $0x0,%edx
  401386:       eb 13                   jmp    40139b &amp;lt;strings_not_equal+0x63&amp;gt;
  401388:       ba 00 00 00 00          mov    $0x0,%edx
  40138d:       eb 0c                   jmp    40139b &amp;lt;strings_not_equal+0x63&amp;gt;
  40138f:       ba 01 00 00 00          mov    $0x1,%edx
  401394:       eb 05                   jmp    40139b &amp;lt;strings_not_equal+0x63&amp;gt;
  401396:       ba 01 00 00 00          mov    $0x1,%edx
  40139b:       89 d0                   mov    %edx,%eax
  40139d:       5b                      pop    %rbx
  40139e:       5d                      pop    %rbp
  40139f:       41 5c                   pop    %r12
  4013a1:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;……&lt;/p&gt;
&lt;p&gt;怎么这么长呀！&lt;/p&gt;
&lt;p&gt;猜测一手，上面那个函数的意思是把输入进去的内容和先前看到的字符串做比对，如果相同表明拆弹成功。到底是不是这样呢？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;嘿嘿，拆弹成功！&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;phase_2()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --disassemble=phase_2                           

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

0000000000400efc &amp;lt;phase_2&amp;gt;:
  400efc:       55                      push   %rbp
  400efd:       53                      push   %rbx
  400efe:       48 83 ec 28             sub    $0x28,%rsp
  400f02:       48 89 e6                mov    %rsp,%rsi
  400f05:       e8 52 05 00 00          call   40145c &amp;lt;read_six_numbers&amp;gt;
  400f0a:       83 3c 24 01             cmpl   $0x1,(%rsp)
  400f0e:       74 20                   je     400f30 &amp;lt;phase_2+0x34&amp;gt;
  400f10:       e8 25 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f15:       eb 19                   jmp    400f30 &amp;lt;phase_2+0x34&amp;gt;
  400f17:       8b 43 fc                mov    -0x4(%rbx),%eax
  400f1a:       01 c0                   add    %eax,%eax
  400f1c:       39 03                   cmp    %eax,(%rbx)
  400f1e:       74 05                   je     400f25 &amp;lt;phase_2+0x29&amp;gt;
  400f20:       e8 15 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f25:       48 83 c3 04             add    $0x4,%rbx
  400f29:       48 39 eb                cmp    %rbp,%rbx
  400f2c:       75 e9                   jne    400f17 &amp;lt;phase_2+0x1b&amp;gt;
  400f2e:       eb 0c                   jmp    400f3c &amp;lt;phase_2+0x40&amp;gt;
  400f30:       48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:       48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:       eb db                   jmp    400f17 &amp;lt;phase_2+0x1b&amp;gt;
  400f3c:       48 83 c4 28             add    $0x28,%rsp
  400f40:       5b                      pop    %rbx
  400f41:       5d                      pop    %rbp
  400f42:       c3                      ret

Disassembly of section .fini:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个函数开始出现了比较多的跳转指令，猜测由 &lt;code&gt;if&lt;/code&gt; 和 &lt;code&gt;while&lt;/code&gt; 编译而来。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;&amp;lt;read_six_numbers&amp;gt;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;先去看看 &lt;code&gt;40145c&lt;/code&gt; 的 &lt;code&gt;read_six_numbers&lt;/code&gt; 函数吧，看看读入的六个数字存到哪里去。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --start-address=0x40145c --stop-address=0x40155c

bomb：     文件格式 elf64-x86-64


Disassembly of section .text:

000000000040145c &amp;lt;read_six_numbers&amp;gt;:
  40145c:       48 83 ec 18             sub    $0x18,%rsp
  401460:       48 89 f2                mov    %rsi,%rdx
  401463:       48 8d 4e 04             lea    0x4(%rsi),%rcx
  401467:       48 8d 46 14             lea    0x14(%rsi),%rax
  40146b:       48 89 44 24 08          mov    %rax,0x8(%rsp)
  401470:       48 8d 46 10             lea    0x10(%rsi),%rax
  401474:       48 89 04 24             mov    %rax,(%rsp)
  401478:       4c 8d 4e 0c             lea    0xc(%rsi),%r9
  40147c:       4c 8d 46 08             lea    0x8(%rsi),%r8
  401480:       be c3 25 40 00          mov    $0x4025c3,%esi
  401485:       b8 00 00 00 00          mov    $0x0,%eax
  40148a:       e8 61 f7 ff ff          call   400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
  40148f:       83 f8 05                cmp    $0x5,%eax
  401492:       7f 05                   jg     401499 &amp;lt;read_six_numbers+0x3d&amp;gt;
  401494:       e8 a1 ff ff ff          call   40143a &amp;lt;explode_bomb&amp;gt;
  401499:       48 83 c4 18             add    $0x18,%rsp
  40149d:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我不行了这都啥啊！&lt;/p&gt;
&lt;p&gt;看一眼 &lt;code&gt;sscanf()&lt;/code&gt; 的原型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int sscanf(const char *str, const char *format, ...);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现不同于直接从 stdin 读取的 &lt;code&gt;scanf&lt;/code&gt;, 他接收 n+2 = 8 个参数。&lt;/p&gt;
&lt;p&gt;已知 x86-64 汇编中函数传参的顺序是 &lt;code&gt;%rdi&lt;/code&gt; &lt;code&gt;%rsi&lt;/code&gt; &lt;code&gt;%rdx&lt;/code&gt; &lt;code&gt;%rcx&lt;/code&gt; &lt;code&gt;%r8&lt;/code&gt; &lt;code&gt;%r9&lt;/code&gt;，而我们读入六个数字需要传给 &lt;code&gt;sscanf()&lt;/code&gt; 8个参数。还余下两个怎么办？经过查找资料发现会从栈里从顶到底挨个读取数据。&lt;/p&gt;
&lt;p&gt;第二个参数是&lt;code&gt;%rsi&lt;/code&gt;。盲猜一手 &lt;code&gt;0x4025c3&lt;/code&gt; 那边存的应该是类似 &lt;code&gt;%d %d %d %d %d %d&lt;/code&gt; 的东西。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 4025c0 702e0025 64202564 20256420 25642025  p..%d %d %d %d %
 4025d0 64202564 00457272 6f723a20 5072656d  d %d.Error: Prem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;那问题来了，&lt;code&gt;%rdi&lt;/code&gt; 在哪？&lt;/p&gt;
&lt;p&gt;既然是我输入的字符串，我有理由猜测输入的字符串原封不动地躺在 &lt;code&gt;%edi&lt;/code&gt; 里边 &lt;s&gt;大概吧（）&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;:::note
这个地方是我蒙的不小心蒙对了（）
:::&lt;/p&gt;
&lt;p&gt;注意到有几行汇编非常有意思：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400efe:       48 83 ec 28             sub    $0x28,%rsp
  400f02:       48 89 e6                mov    %rsp,%rsi
  400f05:       e8 52 05 00 00          call   40145c &amp;lt;read_six_numbers&amp;gt;
  ...
  40145c:       48 83 ec 18             sub    $0x18,%rsp
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;400efe&lt;/code&gt; 行：开辟 &lt;code&gt;0x28&lt;/code&gt; 字节大小空间；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;400f02&lt;/code&gt; 行：给当前栈指针做个备份，赋给 &lt;code&gt;%rsi&lt;/code&gt;；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;40145c&lt;/code&gt; 行：开辟 &lt;code&gt;0x18&lt;/code&gt; 字节大小空间。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;  401460:       48 89 f2                mov    %rsi,%rdx
  401463:       48 8d 4e 04             lea    0x4(%rsi),%rcx
  401478:       4c 8d 4e 0c             lea    0xc(%rsi),%r9
  40147c:       4c 8d 46 08             lea    0x8(%rsi),%r8
  401480:       be c3 25 40 00          mov    $0x4025c3,%esi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这几行涉及内存地址的计算。可以看到，所有参数对应的内存偏移量都是以 &lt;code&gt;%rsi&lt;/code&gt;（也就是刚刚备份过的 &lt;code&gt;%rsp&lt;/code&gt;）为基准的。&lt;code&gt;sscanf&lt;/code&gt; 写入的所有数据都保存在 &lt;code&gt;phase_2&lt;/code&gt; 的栈帧中。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  401467:       48 8d 46 14             lea    0x14(%rsi),%rax
  40146b:       48 89 44 24 08          mov    %rax,0x8(%rsp)
  401470:       48 8d 46 10             lea    0x10(%rsi),%rax
  401474:       48 89 04 24             mov    %rax,(%rsp)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这几行不同于上文的&lt;code&gt;lea 0x...(%rsi) %寄存器&lt;/code&gt; 是因为给参数使用的寄存器用完了，不得不从栈里读数据。这里的栈指针为分配好 &lt;code&gt;0x18&lt;/code&gt; 字节之后的指针，确保不会覆盖之前读取好的数据。&lt;/p&gt;
&lt;p&gt;于是我们就有了下面一张表：&lt;/p&gt;
&lt;p&gt;&amp;lt;div id=&quot;target-point&quot;&amp;gt;&amp;lt;/div&amp;gt;
（对不起我用 AI 整理了一下实在不好意思...）&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;次序&lt;/th&gt;
&lt;th&gt;参数意义&lt;/th&gt;
&lt;th&gt;存放位置&lt;/th&gt;
&lt;th&gt;具体数据&lt;/th&gt;
&lt;th&gt;汇编证据&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;输入字符串&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%rdi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(%rdi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;(外部传入，直接透传)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;格式化字符串&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%rsi&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x4025c3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mov $0x4025c3, %esi&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;数字 1 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%rdx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;mov %rsi, %rdx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;数字 2 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%rcx&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x4(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lea 0x4(%rsi), %rcx&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;数字 3 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%r8&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x8(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lea 0x8(%rsi), %r8&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;数字 4 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;%r9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0xc(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lea 0xc(%rsi), %r9&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;数字 5 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(%rsp)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x10(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lea 0x10(%rsi),%rax&lt;/code&gt; &lt;code&gt;mov %rax, (%rsp)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;数字 6 的地址&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x8(%rsp)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x14(%rsi)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;lea 0x14(%rsi),%rax&lt;/code&gt; &lt;code&gt;mov %rax, 0x8(%rsp)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;注意到了 &lt;code&gt;401492&lt;/code&gt; 的比较跳转指令正好跳过了&lt;code&gt;401494&lt;/code&gt; 的爆炸函数，所以我们要想办法满足 &lt;code&gt;jg&lt;/code&gt; 的条件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  40148a:       e8 61 f7 ff ff          call   400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
  40148f:       83 f8 05                cmp    $0x5,%eax
  401492:       7f 05                   jg     401499 &amp;lt;read_six_numbers+0x3d&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们来查阅 &lt;code&gt;sscanf&lt;/code&gt; 的返回值：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;RETURN VALUE
  On success, these functions return the number of input items
  successfully matched and assigned; this can be fewer than provided
  for, or even zero, in the event of an early matching failure.

  The value EOF is returned if the end of input is reached before
  either the first successful conversion or a matching failure
  occurs.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现返回值 （也就是 &lt;code&gt;%eax&lt;/code&gt; 里的值）是解析出的输入个数。之后 &lt;code&gt;40148f&lt;/code&gt; 行将返回值与 5 进行比较，如果返回值大于 5，就跳过炸弹。&lt;/p&gt;
&lt;p&gt;这个操作等效于以下 C 代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if(sscanf(&quot;%d %d %d %d %d %d&quot;, &amp;amp;a1, &amp;amp;a2, &amp;amp;a3, &amp;amp;a4, &amp;amp;a5, &amp;amp;a6) &amp;lt;= 5) {
    explode_bomb();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;于是我们顺利分析了 &lt;code&gt;read_six_numbers&lt;/code&gt; 的行为。&lt;/p&gt;
&lt;h3&gt;循环与跳转&lt;/h3&gt;
&lt;p&gt;调用完 &lt;code&gt;read_six_numbers&lt;/code&gt; 函数后，紧接着 &lt;code&gt;phase_2&lt;/code&gt; 做了以下行为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400f0a:       83 3c 24 01             cmpl   $0x1,(%rsp)
  400f0e:       74 20                   je     400f30 &amp;lt;phase_2+0x34&amp;gt;
  400f10:       e8 25 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f15:       eb 19                   jmp    400f30 &amp;lt;phase_2+0x34&amp;gt;
  400f17:       8b 43 fc                mov    -0x4(%rbx),%eax
  400f1a:       01 c0                   add    %eax,%eax
  400f1c:       39 03                   cmp    %eax,(%rbx)
  400f1e:       74 05                   je     400f25 &amp;lt;phase_2+0x29&amp;gt;
  400f20:       e8 15 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f25:       48 83 c3 04             add    $0x4,%rbx
  400f29:       48 39 eb                cmp    %rbp,%rbx
  400f2c:       75 e9                   jne    400f17 &amp;lt;phase_2+0x1b&amp;gt;
  400f2e:       eb 0c                   jmp    400f3c &amp;lt;phase_2+0x40&amp;gt;
  400f30:       48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:       48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:       eb db                   jmp    400f17 &amp;lt;phase_2+0x1b&amp;gt;
  400f3c:       48 83 c4 28             add    $0x28,%rsp
  400f40:       5b                      pop    %rbx
  400f41:       5d                      pop    %rbp
  400f42:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  400f0a:       83 3c 24 01             cmpl   $0x1,(%rsp)
  400f0e:       74 20                   je     400f30 &amp;lt;phase_2+0x34&amp;gt;
  400f10:       e8 25 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f15:       eb 19                   jmp    400f30 &amp;lt;phase_2+0x34&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;(%rsp)&lt;/code&gt; 不是 &lt;code&gt;1&lt;/code&gt;，直接引爆炸弹。之后跳转到 &lt;code&gt;400f30&lt;/code&gt; 段落。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400f30:       48 8d 5c 24 04          lea    0x4(%rsp),%rbx
  400f35:       48 8d 6c 24 18          lea    0x18(%rsp),%rbp
  400f3a:       eb db                   jmp    400f17 &amp;lt;phase_2+0x1b&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这时候遇到了 &lt;code&gt;0x...(%rsp)&lt;/code&gt;！时刻记住上面推导出来的&lt;a href=&quot;#target-point&quot;&gt;那张表&lt;/a&gt;，注意所有的&lt;code&gt;%rsi&lt;/code&gt;均需换成&lt;code&gt;%rsp&lt;/code&gt;，因为栈帧已还原。&lt;/p&gt;
&lt;p&gt;上述汇编做了个什么事呢？首先 &lt;code&gt;%rbx&lt;/code&gt; 被赋予了 &lt;code&gt;%rsp + 0x4&lt;/code&gt;。也就是&lt;strong&gt;第二个数字的地址&lt;/strong&gt;。然后，&lt;code&gt;%rbp&lt;/code&gt; 被赋予了 &lt;code&gt;%rsp + 0x18&lt;/code&gt;，查表发现，刚好是最后一个数字&lt;strong&gt;之后的地址&lt;/strong&gt;。随后跳转到 &lt;code&gt;400f17&lt;/code&gt; 开始执行指令。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400f17:       8b 43 fc                mov    -0x4(%rbx),%eax
  400f1a:       01 c0                   add    %eax,%eax
  400f1c:       39 03                   cmp    %eax,(%rbx)
  400f1e:       74 05                   je     400f25 &amp;lt;phase_2+0x29&amp;gt;
  400f20:       e8 15 05 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f25:       48 83 c3 04             add    $0x4,%rbx
  400f29:       48 39 eb                cmp    %rbp,%rbx
  400f2c:       75 e9                   jne    400f17 &amp;lt;phase_2+0x1b&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;400f17&lt;/code&gt;: &lt;code&gt;%eax&lt;/code&gt; 赋值为 &lt;code&gt;%rbx&lt;/code&gt;的 &lt;strong&gt;前一个数字&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f00f1a&lt;/code&gt;: 将&lt;code&gt;%eax&lt;/code&gt; 翻倍；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400f1c&lt;/code&gt;: 比较翻倍后的前一个数字与当前数字；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400f1e&lt;/code&gt;: 如果相等，跳过炸弹，否则引爆炸弹；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400f25&lt;/code&gt;: &lt;code&gt;%rbx&lt;/code&gt; 增加 &lt;code&gt;0x4&lt;/code&gt;，指向&lt;strong&gt;后一个数字&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400f29&lt;/code&gt;: 检查 &lt;code&gt;%rbx&lt;/code&gt; 是否与 &lt;code&gt;%rbp&lt;/code&gt; 相等（指针是否指向了末尾）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400f2c&lt;/code&gt;: 如果没有指向末尾，重复执行上述操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这不就是经典的&lt;code&gt;for&lt;/code&gt;循环吗！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; for(long *p = &amp;amp;a2; p &amp;lt; &amp;amp;a6 + 1; p++) {
    if(*(p - 1) * 2 != *p) explode_bomb();
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显然可以看出，&lt;code&gt;phase_2&lt;/code&gt; 是一个检查输入 &lt;strong&gt;是否为等比数列&lt;/strong&gt; 的函数，初值为 &lt;code&gt;1&lt;/code&gt;，公比是 &lt;code&gt;2&lt;/code&gt;，项数为&lt;code&gt;6&lt;/code&gt;！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That&apos;s number 2.  Keep going!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;phase_3()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --disassemble=phase_3

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

0000000000400f43 &amp;lt;phase_3&amp;gt;:
  400f43:       48 83 ec 18             sub    $0x18,%rsp
  400f47:       48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  400f4c:       48 8d 54 24 08          lea    0x8(%rsp),%rdx
  400f51:       be cf 25 40 00          mov    $0x4025cf,%esi
  400f56:       b8 00 00 00 00          mov    $0x0,%eax
  400f5b:       e8 90 fc ff ff          call   400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
  400f60:       83 f8 01                cmp    $0x1,%eax
  400f63:       7f 05                   jg     400f6a &amp;lt;phase_3+0x27&amp;gt;
  400f65:       e8 d0 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400f6a:       83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
  400f6f:       77 3c                   ja     400fad &amp;lt;phase_3+0x6a&amp;gt;
  400f71:       8b 44 24 08             mov    0x8(%rsp),%eax
  400f75:       ff 24 c5 70 24 40 00    jmp    *0x402470(,%rax,8)
  400f7c:       b8 cf 00 00 00          mov    $0xcf,%eax
  400f81:       eb 3b                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f83:       b8 c3 02 00 00          mov    $0x2c3,%eax
  400f88:       eb 34                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f8a:       b8 00 01 00 00          mov    $0x100,%eax
  400f8f:       eb 2d                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f91:       b8 85 01 00 00          mov    $0x185,%eax
  400f96:       eb 26                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f98:       b8 ce 00 00 00          mov    $0xce,%eax
  400f9d:       eb 1f                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f9f:       b8 aa 02 00 00          mov    $0x2aa,%eax
  400fa4:       eb 18                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fa6:       b8 47 01 00 00          mov    $0x147,%eax
  400fab:       eb 11                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fad:       e8 88 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400fb2:       b8 00 00 00 00          mov    $0x0,%eax
  400fb7:       eb 05                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fb9:       b8 37 01 00 00          mov    $0x137,%eax
  400fbe:       3b 44 24 0c             cmp    0xc(%rsp),%eax
  400fc2:       74 05                   je     400fc9 &amp;lt;phase_3+0x86&amp;gt;
  400fc4:       e8 71 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400fc9:       48 83 c4 18             add    $0x18,%rsp
  400fcd:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;又是经典&lt;code&gt;sscanf&lt;/code&gt;。看看格式化字符串：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 4025c0 702e0025 64202564 20256420 25642025  p..%d %d %d %d %
 4025d0 64202564 00457272 6f723a20 5072656d  d %d.Error: Prem
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;竟然复用&lt;code&gt;phase_2&lt;/code&gt;的字符串！但是起始位置不同。这次的格式化字符串是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;%d %d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;意味着我需要输入俩数字，存到 &lt;code&gt;(%rdx)&lt;/code&gt; 和 &lt;code&gt;(%rcx)&lt;/code&gt; （也就是 &lt;code&gt;0x8(%rsp)&lt;/code&gt;, &lt;code&gt;0xc(%rsp)&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;根据 &lt;code&gt;phase_2&lt;/code&gt; 的经验，我们直接来看这段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400f6a:       83 7c 24 08 07          cmpl   $0x7,0x8(%rsp)
  400f6f:       77 3c                   ja     400fad &amp;lt;phase_3+0x6a&amp;gt;
  400f71:       8b 44 24 08             mov    0x8(%rsp),%eax
  400f75:       ff 24 c5 70 24 40 00    jmp    *0x402470(,%rax,8)
  400f7c:       b8 cf 00 00 00          mov    $0xcf,%eax
  400f81:       eb 3b                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f83:       b8 c3 02 00 00          mov    $0x2c3,%eax
  400f88:       eb 34                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f8a:       b8 00 01 00 00          mov    $0x100,%eax
  400f8f:       eb 2d                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f91:       b8 85 01 00 00          mov    $0x185,%eax
  400f96:       eb 26                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f98:       b8 ce 00 00 00          mov    $0xce,%eax
  400f9d:       eb 1f                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400f9f:       b8 aa 02 00 00          mov    $0x2aa,%eax
  400fa4:       eb 18                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fa6:       b8 47 01 00 00          mov    $0x147,%eax
  400fab:       eb 11                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fad:       e8 88 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400fb2:       b8 00 00 00 00          mov    $0x0,%eax
  400fb7:       eb 05                   jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
  400fb9:       b8 37 01 00 00          mov    $0x137,%eax
  400fbe:       3b 44 24 0c             cmp    0xc(%rsp),%eax
  400fc2:       74 05                   je     400fc9 &amp;lt;phase_3+0x86&amp;gt;
  400fc4:       e8 71 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  400fc9:       48 83 c4 18             add    $0x18,%rsp
  400fcd:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;400f6f&lt;/code&gt; 会直接把炸弹搞炸，所以 &lt;code&gt;0x8(%rsp)&lt;/code&gt; 不应该大于 &lt;code&gt;0x7&lt;/code&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400f71:       8b 44 24 08             mov    0x8(%rsp),%eax
  400f75:       ff 24 c5 70 24 40 00    jmp    *0x402470(,%rax,8)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是干啥的？&lt;/p&gt;
&lt;p&gt;看看 &lt;code&gt;0x402470&lt;/code&gt; 附近有啥吧。&lt;/p&gt;
&lt;p&gt;怎么反编译出来没这个地址？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;00000000004022a0 &amp;lt;__libc_csu_fini&amp;gt;:
  4022a0:       f3 c3                   repz ret
  4022a2:       90                      nop
  4022a3:       90                      nop

Disassembly of section .fini:

00000000004022a4 &amp;lt;_fini&amp;gt;:
  4022a4:       48 83 ec 08             sub    $0x8,%rsp
  4022a8:       48 83 c4 08             add    $0x8,%rsp
  4022ac:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;？？？？&lt;/p&gt;
&lt;p&gt;我没招了。&lt;/p&gt;
&lt;p&gt;（激情拷打 Gemini）&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你看到的 402470 是 跳转表（Jump Table） 的基地址。&lt;/p&gt;
&lt;p&gt;这正是 C 语言中 switch-case 语句编译后的典型模样。因为 switch 的分支太多，编译器为了效率，不会写一堆 if-else，而是直接在内存里建了一张“地址表”，根据你输入的数字直接查表跳转。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;$ gdb bomb 
GNU gdb (GDB) 17.1
Copyright (C) 2025 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type &quot;show copying&quot; and &quot;show warranty&quot; for details.
This GDB was configured as &quot;x86_64-pc-linux-gnu&quot;.
Type &quot;show configuration&quot; for configuration details.
For bug reporting instructions, please see:
&amp;lt;https://www.gnu.org/software/gdb/bugs/&amp;gt;.
Find the GDB manual and other documentation resources online at:
    &amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.

For help, type &quot;help&quot;.
Type &quot;apropos word&quot; to search for commands related to &quot;word&quot;...
Reading symbols from bomb...
(gdb) x/8gx 0x402470
0x402470:       0x0000000000400f7c      0x0000000000400fb9
0x402480:       0x0000000000400f83      0x0000000000400f8a
0x402490:       0x0000000000400f91      0x0000000000400f98
0x4024a0:       0x0000000000400f9f      0x0000000000400fa6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::note
gdb 显示的地址为大端序，实际上 .rodata 以小端序存放地址。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -s -j .rodata bomb --start-address=0x402470

bomb：     文件格式 elf64-x86-64

Contents of section .rodata:
 402470 7c0f4000 00000000 b90f4000 00000000  |.@.......@.....
 402480 830f4000 00000000 8a0f4000 00000000  ..@.......@.....
 402490 910f4000 00000000 980f4000 00000000  ..@.......@.....
 4024a0 9f0f4000 00000000 a60f4000 00000000  ..@.......@.....
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;行吧，那么得出这么一张表：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;%rax&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;地址&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f7c&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400fb9&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f83&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f8a&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f91&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f98&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400f9f&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x400fa6&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;凭直觉，我猜测这可能是个多解问题。假设我们的&lt;code&gt;0x8(%rsp)&lt;/code&gt;是&lt;code&gt;0&lt;/code&gt;，那么跳转到&lt;code&gt;0x400f7c&lt;/code&gt;。
那么会依次执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mov    $0xcf,%eax
# jmp    400fbe &amp;lt;phase_3+0x7b&amp;gt;
cmp    0xc(%rsp),%eax
# je     400fc9 &amp;lt;phase_3+0x86&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果 &lt;code&gt;je&lt;/code&gt; 不满足条件。就会直接触发下一行的炸弹。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;0xcf&lt;/code&gt; == &lt;code&gt;0d207&lt;/code&gt;。
所以第二个数字应该输入 &lt;code&gt;207&lt;/code&gt;！&lt;/p&gt;
&lt;p&gt;为了验证猜想，我们把所有可能的答案都列出来：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;code&gt;0x8(%rsp)&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;0xc(%rsp)&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;207&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;311&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;707&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;389&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;206&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;682&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;327&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That&apos;s number 2.  Keep going!
0 207
Halfway there!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;phase_4()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -d bomb --disassemble=phase_4

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

000000000040100c &amp;lt;phase_4&amp;gt;:
  40100c:       48 83 ec 18             sub    $0x18,%rsp
  401010:       48 8d 4c 24 0c          lea    0xc(%rsp),%rcx
  401015:       48 8d 54 24 08          lea    0x8(%rsp),%rdx
  40101a:       be cf 25 40 00          mov    $0x4025cf,%esi
  40101f:       b8 00 00 00 00          mov    $0x0,%eax
  401024:       e8 c7 fb ff ff          call   400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
  401029:       83 f8 02                cmp    $0x2,%eax
  40102c:       75 07                   jne    401035 &amp;lt;phase_4+0x29&amp;gt;
  40102e:       83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp)
  401033:       76 05                   jbe    40103a &amp;lt;phase_4+0x2e&amp;gt;
  401035:       e8 00 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  40103a:       ba 0e 00 00 00          mov    $0xe,%edx
  40103f:       be 00 00 00 00          mov    $0x0,%esi
  401044:       8b 7c 24 08             mov    0x8(%rsp),%edi
  401048:       e8 81 ff ff ff          call   400fce &amp;lt;func4&amp;gt;
  40104d:       85 c0                   test   %eax,%eax
  40104f:       75 07                   jne    401058 &amp;lt;phase_4+0x4c&amp;gt;
  401051:       83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
  401056:       74 05                   je     40105d &amp;lt;phase_4+0x51&amp;gt;
  401058:       e8 dd 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  40105d:       48 83 c4 18             add    $0x18,%rsp
  401061:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;经典 &lt;code&gt;sscanf&lt;/code&gt;。这次的格式化字符串是 &lt;code&gt;0x4025cf&lt;/code&gt;。还是 &lt;code&gt;phase_3&lt;/code&gt; 的格式，意味着输入俩整数进去，保存到 &lt;code&gt;0x8(%rsp)&lt;/code&gt;和 &lt;code&gt;0xc(%rsp)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;此时我们的研究重心到了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  40102e:       83 7c 24 08 0e          cmpl   $0xe,0x8(%rsp)
  401033:       76 05                   jbe    40103a &amp;lt;phase_4+0x2e&amp;gt;
  401035:       e8 00 04 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  40103a:       ba 0e 00 00 00          mov    $0xe,%edx
  40103f:       be 00 00 00 00          mov    $0x0,%esi
  401044:       8b 7c 24 08             mov    0x8(%rsp),%edi
  401048:       e8 81 ff ff ff          call   400fce &amp;lt;func4&amp;gt;
  40104d:       85 c0                   test   %eax,%eax
  40104f:       75 07                   jne    401058 &amp;lt;phase_4+0x4c&amp;gt;
  401051:       83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
  401056:       74 05                   je     40105d &amp;lt;phase_4+0x51&amp;gt;
  401058:       e8 dd 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  40105d:       48 83 c4 18             add    $0x18,%rsp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;jbe&lt;/code&gt;需满足 &lt;code&gt;0xe&lt;/code&gt; &amp;lt; &lt;code&gt;0x8(%rsp)&lt;/code&gt;。即第一个数需要大于 &lt;code&gt;14&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;又已知函数传参的顺序是&lt;code&gt;%edi&lt;/code&gt;, &lt;code&gt;%esi&lt;/code&gt;, &lt;code&gt;%edx&lt;/code&gt;。在上面的汇编中，分别被赋值成 &lt;code&gt;0x8(%esp)&lt;/code&gt;, &lt;code&gt;$0&lt;/code&gt;, &lt;code&gt;$14&lt;/code&gt;。
查看 &lt;code&gt;func4&lt;/code&gt; 的汇编：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;objdump -d bomb --disassemble=func4                

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

0000000000400fce &amp;lt;func4&amp;gt;:
  400fce:       48 83 ec 08             sub    $0x8,%rsp
  400fd2:       89 d0                   mov    %edx,%eax
  400fd4:       29 f0                   sub    %esi,%eax
  400fd6:       89 c1                   mov    %eax,%ecx
  400fd8:       c1 e9 1f                shr    $0x1f,%ecx
  400fdb:       01 c8                   add    %ecx,%eax
  400fdd:       d1 f8                   sar    $1,%eax
  400fdf:       8d 0c 30                lea    (%rax,%rsi,1),%ecx
  400fe2:       39 f9                   cmp    %edi,%ecx
  400fe4:       7e 0c                   jle    400ff2 &amp;lt;func4+0x24&amp;gt;
  400fe6:       8d 51 ff                lea    -0x1(%rcx),%edx
  400fe9:       e8 e0 ff ff ff          call   400fce &amp;lt;func4&amp;gt;
  400fee:       01 c0                   add    %eax,%eax
  400ff0:       eb 15                   jmp    401007 &amp;lt;func4+0x39&amp;gt;
  400ff2:       b8 00 00 00 00          mov    $0x0,%eax
  400ff7:       39 f9                   cmp    %edi,%ecx
  400ff9:       7d 0c                   jge    401007 &amp;lt;func4+0x39&amp;gt;
  400ffb:       8d 71 01                lea    0x1(%rcx),%esi
  400ffe:       e8 cb ff ff ff          call   400fce &amp;lt;func4&amp;gt;
  401003:       8d 44 00 01             lea    0x1(%rax,%rax,1),%eax
  401007:       48 83 c4 08             add    $0x8,%rsp
  40100b:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;哦我的上帝这是什么诡异的递归……&lt;/p&gt;
&lt;p&gt;（拿出草稿纸）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  400fd2:       89 d0                   mov    %edx,%eax
  400fd4:       29 f0                   sub    %esi,%eax
  400fd6:       89 c1                   mov    %eax,%ecx
  400fd8:       c1 e9 1f                shr    $0x1f,%ecx
  400fdb:       01 c8                   add    %ecx,%eax
  400fdd:       d1 f8                   sar    $1,%eax
  400fdf:       8d 0c 30                lea    (%rax,%rsi,1),%ecx
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;询问 Gemini 之后发现这部分实现了一个取平均数的操作。&lt;s&gt;（原谅我）&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;shr $0x1f,%ecx&lt;/code&gt; 这条指令极其炫技。想想&lt;code&gt;0x1f&lt;/code&gt;是什么？31 对吧。对一个有符号双字右移 31 位得到了什么？符号位！所以这条指令取了&lt;code&gt;%ecx&lt;/code&gt; (也就是&lt;code&gt;%eax&lt;/code&gt;的备份) 的符号位。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;add %ecx,%eax&lt;/code&gt; 更神奇。我们不妨分情况讨论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;%eax&lt;/code&gt; 是正数：符号位为 0, 直接右移。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%eax&lt;/code&gt; 是负奇数：加一再右移（结果无区别）；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%eax&lt;/code&gt; 是负偶数：加一再右移（结果 + 1）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;发现了吗？这一部分实现了 C 标准的向 0 取整，确保右移和数学除法没有区别。&lt;/p&gt;
&lt;p&gt;执行完之后 &lt;code&gt;%rax&lt;/code&gt; 里面是差值的一半，而 &lt;code&gt;%ecx&lt;/code&gt; 里面正好就是平均数（&lt;code&gt;low + (low + high) &amp;gt;&amp;gt; 1&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;之后的条件跳转就不细说了，整体逻辑可以简化为下面的函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int func4(int target, int low, int high) {
    int mid = low + (high - low) / 2;
    if (mid &amp;gt; target) {
        return 2 * func4(target, low, mid - 1);
    } else if (mid &amp;lt; target) {
        return 2 * func4(target, mid + 1, high) + 1;
    } else {
        return 0;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;剩下下面几行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  40104d:       85 c0                   test   %eax,%eax
  40104f:       75 07                   jne    401058 &amp;lt;phase_4+0x4c&amp;gt;
  401051:       83 7c 24 0c 00          cmpl   $0x0,0xc(%rsp)
  401056:       74 05                   je     40105d &amp;lt;phase_4+0x51&amp;gt;
  401058:       e8 dd 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  40105d:       48 83 c4 18             add    $0x18,%rsp
  401061:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;显然，如果返回值不是 0，就会跳转到爆炸函数。&lt;code&gt;0xc(%rsp)&lt;/code&gt; 如果不等于 0，也会触发爆炸。&lt;/p&gt;
&lt;p&gt;那么显然，我们的&lt;code&gt;0x8(%esp)&lt;/code&gt;应该被赋值成 7, &lt;code&gt;0xc(%esp)&lt;/code&gt; 应该被赋值成 0。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./bomb
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That&apos;s number 2.  Keep going!
0 207
Halfway there!
7 0
So you got that one.  Try this one.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;phase_5()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -d bomb --disassemble=phase_5                       

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

0000000000401062 &amp;lt;phase_5&amp;gt;:
  401062:       53                      push   %rbx
  401063:       48 83 ec 20             sub    $0x20,%rsp
  401067:       48 89 fb                mov    %rdi,%rbx
  40106a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  401071:       00 00 
  401073:       48 89 44 24 18          mov    %rax,0x18(%rsp)
  401078:       31 c0                   xor    %eax,%eax
  40107a:       e8 9c 02 00 00          call   40131b &amp;lt;string_length&amp;gt;
  40107f:       83 f8 06                cmp    $0x6,%eax
  401082:       74 4e                   je     4010d2 &amp;lt;phase_5+0x70&amp;gt;
  401084:       e8 b1 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  401089:       eb 47                   jmp    4010d2 &amp;lt;phase_5+0x70&amp;gt;
  40108b:       0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:       88 0c 24                mov    %cl,(%rsp)
  401092:       48 8b 14 24             mov    (%rsp),%rdx
  401096:       83 e2 0f                and    $0xf,%edx
  401099:       0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:       88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:       48 83 c0 01             add    $0x1,%rax
  4010a8:       48 83 f8 06             cmp    $0x6,%rax
  4010ac:       75 dd                   jne    40108b &amp;lt;phase_5+0x29&amp;gt;
  4010ae:       c6 44 24 16 00          movb   $0x0,0x16(%rsp)
  4010b3:       be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:       48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:       e8 76 02 00 00          call   401338 &amp;lt;strings_not_equal&amp;gt;
  4010c2:       85 c0                   test   %eax,%eax
  4010c4:       74 13                   je     4010d9 &amp;lt;phase_5+0x77&amp;gt;
  4010c6:       e8 6f 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  4010cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  4010d0:       eb 07                   jmp    4010d9 &amp;lt;phase_5+0x77&amp;gt;
  4010d2:       b8 00 00 00 00          mov    $0x0,%eax
  4010d7:       eb b2                   jmp    40108b &amp;lt;phase_5+0x29&amp;gt;
  4010d9:       48 8b 44 24 18          mov    0x18(%rsp),%rax
  4010de:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4010e5:       00 00 
  4010e7:       74 05                   je     4010ee &amp;lt;phase_5+0x8c&amp;gt;
  4010e9:       e8 42 fa ff ff          call   400b30 &amp;lt;__stack_chk_fail@plt&amp;gt;
  4010ee:       48 83 c4 20             add    $0x20,%rsp
  4010f2:       5b                      pop    %rbx
  4010f3:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意到有一行代码是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  40106a:       64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是个啥（）&lt;/p&gt;
&lt;p&gt;这个寻址方式我从来没见过，让我搜一手：&lt;/p&gt;
&lt;p&gt;在 Stack OverFlow 上的帖子 &lt;a href=&quot;https://stackoverflow.com/questions/10325713/why-does-this-memory-address-fs0x28-fs0x28-have-a-random-value&quot;&gt;Why does this memory address %fs:0x28 ( fs[0x28] ) have a random value?&lt;/a&gt; 中，有一位答主解释了这行代码的作用：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Both the &lt;code&gt;FS&lt;/code&gt; and &lt;code&gt;GS&lt;/code&gt; registers can be used as base-pointer addresses in order to access special operating system data-structures. So what you&apos;re seeing is a value loaded at an offset from the value held in the &lt;code&gt;FS&lt;/code&gt; register, and not bit manipulation of the contents of the &lt;code&gt;FS&lt;/code&gt; register.&lt;/p&gt;
&lt;p&gt;Specifically what&apos;s taking place, is that &lt;code&gt;FS:0x28&lt;/code&gt; on Linux is storing a special sentinel stack-guard value, and the code is performing a stack-guard check. For instance, if you look further in your code, you&apos;ll see that the value at &lt;code&gt;FS:0x28&lt;/code&gt; is stored on the stack, and then the contents of the stack are recalled and an &lt;code&gt;XOR&lt;/code&gt; is performed with the original value at &lt;code&gt;FS:0x28&lt;/code&gt;. If the two values are equal, which means that the zero-bit has been set because &lt;code&gt;XOR&lt;/code&gt;&apos;ing two of the same values results in a zero-value, then we jump to the &lt;code&gt;test&lt;/code&gt; routine, otherwise we jump to a special function that indicates that the stack was somehow corrupted, and the sentinel value stored on the stack was changed.&lt;/p&gt;
&lt;p&gt;If using GCC, this can be disabled with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-fno-stack-protector
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;中文翻译如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;FS&lt;/code&gt; 和 &lt;code&gt;GS&lt;/code&gt; 寄存器都可以作为基址指针（Base-pointer addresses），用于访问操作系统特殊的内部数据结构。因此，你所看到的实际上是从 &lt;code&gt;FS&lt;/code&gt; 寄存器保存的基地址加上一个偏移量后加载的数据，而不是对 &lt;code&gt;FS&lt;/code&gt; 寄存器本身的内容进行位运算。&lt;/p&gt;
&lt;p&gt;具体来说，在 Linux 系统上，&lt;code&gt;FS:0x28&lt;/code&gt; 的位置存储了一个特殊的哨兵值，称为 栈保护值（Stack-guard value / Canary），这段代码正在进行栈保护检查。例如，如果你查看代码的后续部分，会发现程序先将 &lt;code&gt;FS:0x28&lt;/code&gt; 处的值存入栈中；函数结束前，再将栈中的值取出，与 &lt;code&gt;FS:0x28&lt;/code&gt; 原有的值进行 &lt;code&gt;XOR&lt;/code&gt;（异或）运算。&lt;/p&gt;
&lt;p&gt;如果两个值相等（这意味着异或运算的结果为 0，从而设置了零标志位 ZF），程序就会跳转到正常的测试或后续流程；否则，程序会跳转到一个特殊的函数，表明栈已经被破坏（缓冲区溢出），即存储在栈上的那个哨兵值被篡改了。&lt;/p&gt;
&lt;p&gt;如果你使用 GCC 编译器，可以通过以下参数禁用此功能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-fno-stack-protector
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;观察后续代码，确实有将 &lt;code&gt;%fs:0x28&lt;/code&gt; 与 &lt;code&gt;%rax&lt;/code&gt; 异或运算的逻辑，如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  4010de:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4010e5:       00 00 
  4010e7:       74 05                   je     4010ee &amp;lt;phase_5+0x8c&amp;gt;
  4010e9:       e8 42 fa ff ff          call   400b30 &amp;lt;__stack_chk_fail@plt&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们继续往下看，看到下面这一段：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  401073:       48 89 44 24 18          mov    %rax,0x18(%rsp)
  401078:       31 c0                   xor    %eax,%eax
  40107a:       e8 9c 02 00 00          call   40131b &amp;lt;string_length&amp;gt;
  40107f:       83 f8 06                cmp    $0x6,%eax
  401082:       74 4e                   je     4010d2 &amp;lt;phase_5+0x70&amp;gt;
  401084:       e8 b1 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;前两行表示把之前存的那个 Canary 值压到栈里，并且把 &lt;code&gt;%eax&lt;/code&gt; 清空。这也好理解，毕竟做校验嘛，不能到处留这个值。
下面一行又出现了 &lt;code&gt;string_length&lt;/code&gt;。 直觉告诉我们，&lt;code&gt;%rdi&lt;/code&gt; 里面存的准是输入字符串，而且长度必须为 6，否则爆炸。&lt;/p&gt;
&lt;p&gt;那问题来了，这个字符串长度包不包含 &lt;code&gt;\0&lt;/code&gt;？&lt;code&gt;phase_1&lt;/code&gt; 蒙对了这个函数，但这里可不能蒙了，我们必须使用 gdb 来调试一手：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gdb bomb
Reading symbols from bomb...
(gdb) b *0x40107a             # 在 call 40131b &amp;lt;string_length&amp;gt; 处打断点
Breakpoint 1 at 0x40107a 
(gdb) r                       # 运行程序
Starting program: /home/sakimidare/bomb/bomb 
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That&apos;s number 2.  Keep going!
0 207
Halfway there!
7 0
So you got that one.  Try this one.
123456                        # 输入一个 123456 看看效果

Breakpoint 1, 0x000000000040107a in phase_5 ()
(gdb) ni                      # 运行下一条指令 （即执行完整个 call）
0x000000000040107f in phase_5 ()
(gdb) i r eax                 # 立即查看寄存器 %eax 的值
eax            0x6                 6
(gdb) 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们得出结论：&lt;code&gt;string_length&lt;/code&gt; 函数返回的长度不包含 &lt;code&gt;\0&lt;/code&gt;。也就是说，我们应该输入一个长度为 6 的字符串。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  401089:       eb 47                   jmp    4010d2 &amp;lt;phase_5+0x70&amp;gt;
  ...
  4010d2:       b8 00 00 00 00          mov    $0x0,%eax
  4010d7:       eb b2                   jmp    40108b &amp;lt;phase_5+0x29&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;  40108b:       0f b6 0c 03             movzbl (%rbx,%rax,1),%ecx
  40108f:       88 0c 24                mov    %cl,(%rsp)
  401092:       48 8b 14 24             mov    (%rsp),%rdx
  401096:       83 e2 0f                and    $0xf,%edx
  401099:       0f b6 92 b0 24 40 00    movzbl 0x4024b0(%rdx),%edx
  4010a0:       88 54 04 10             mov    %dl,0x10(%rsp,%rax,1)
  4010a4:       48 83 c0 01             add    $0x1,%rax
  4010a8:       48 83 f8 06             cmp    $0x6,%rax
  4010ac:       75 dd                   jne    40108b &amp;lt;phase_5+0x29&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;此时，&lt;code&gt;%rbx&lt;/code&gt; 是 &lt;code&gt;%rdi&lt;/code&gt; 里面的值，也就是输入的字符串地址。注意到这里新出现了一个寄存器 &lt;code&gt;%cl&lt;/code&gt;。这是干啥的？&lt;/p&gt;
&lt;p&gt;&lt;s&gt;（对不起写这一段的时候忘掉了 &lt;code&gt;%cl&lt;/code&gt; 是 &lt;code&gt;rcx&lt;/code&gt; 的低位）&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;那就是说 &lt;code&gt;40108b&lt;/code&gt; 把内存里那个字符串地址加上 &lt;code&gt;%rax&lt;/code&gt; 的偏移量，得到的那个字节抠低位放到 &lt;code&gt;(%rsp)&lt;/code&gt; 和 &lt;code&gt;%rdx&lt;/code&gt; 去呗！&lt;/p&gt;
&lt;p&gt;那有个问题啊，&lt;code&gt;(%rsp)&lt;/code&gt; 是刚刚从 &lt;code&gt;%cl&lt;/code&gt; 复制过来的一个字节，&lt;code&gt;%rdx&lt;/code&gt; 是一个双字。如果强行复制，那么不会导致高位（x86-64 是小端序）充满垃圾值吗？&lt;/p&gt;
&lt;p&gt;还好，下一行的 &lt;code&gt;and&lt;/code&gt; 直接只保留了低位，把垃圾值舍弃了。&lt;/p&gt;
&lt;p&gt;看看 &lt;code&gt;0x4024b0&lt;/code&gt; 里面是啥吧！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -s -j .rodata bomb --start-address=0x4024b0

bomb：     文件格式 elf64-x86-64

Contents of section .rodata:
 4024b0 6d616475 69657273 6e666f74 7662796c  maduiersnfotvbyl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;现在 &lt;code&gt;%edx&lt;/code&gt; 中塞的是上文硬编码字符串偏移当前输入字符低两位的字符（好拗口）。例如第一个字符输入 &lt;code&gt;&apos;H&apos;&lt;/code&gt; ，&lt;code&gt;&apos;H&apos; = 0x48&lt;/code&gt;。低两位是 &lt;code&gt;0x8&lt;/code&gt;，那么就会往 &lt;code&gt;edx&lt;/code&gt; 里面存入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;maduiersnfotvbyl
        ^
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&apos;n&apos;&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;之后 &lt;code&gt;mov %dl,0x10(%rsp,%rax,1)&lt;/code&gt; 往内存里压栈，&lt;code&gt;%rax&lt;/code&gt; 自增 1，并判断 &lt;code&gt;%rax&lt;/code&gt; 是否已自增到 6。如果自增到 6，那么跳出循环。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  4010ae:       c6 44 24 16 00          movb   $0x0,0x16(%rsp)
  4010b3:       be 5e 24 40 00          mov    $0x40245e,%esi
  4010b8:       48 8d 7c 24 10          lea    0x10(%rsp),%rdi
  4010bd:       e8 76 02 00 00          call   401338 &amp;lt;strings_not_equal&amp;gt;
  4010c2:       85 c0                   test   %eax,%eax
  4010c4:       74 13                   je     4010d9 &amp;lt;phase_5+0x77&amp;gt;
  4010c6:       e8 6f 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  4010cb:       0f 1f 44 00 00          nopl   0x0(%rax,%rax,1)
  4010d0:       eb 07                   jmp    4010d9 &amp;lt;phase_5+0x77&amp;gt;
  4010d2:       b8 00 00 00 00          mov    $0x0,%eax
  4010d7:       eb b2                   jmp    40108b &amp;lt;phase_5+0x29&amp;gt;
  4010d9:       48 8b 44 24 18          mov    0x18(%rsp),%rax
  4010de:       64 48 33 04 25 28 00    xor    %fs:0x28,%rax
  4010e5:       00 00 
  4010e7:       74 05                   je     4010ee &amp;lt;phase_5+0x8c&amp;gt;
  4010e9:       e8 42 fa ff ff          call   400b30 &amp;lt;__stack_chk_fail@plt&amp;gt;
  4010ee:       48 83 c4 20             add    $0x20,%rsp
  4010f2:       5b                      pop    %rbx
  4010f3:       c3                      ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;第一行给末尾加上&lt;code&gt;\0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;40245e&lt;/code&gt; 的内容是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 40245e 666c 79657273 00000000 00000000 0000 flyers..........
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;即 &lt;code&gt;flyers&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;那么答案呼之欲出：&lt;/p&gt;
&lt;p&gt;按照之前说的方法，输入的字符串取 ASCII 最后一个字节，然后在固定字符串上做偏移。最后拼出来的字符串应该是 &lt;code&gt;flyers&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以一个可能的答案是&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;IONEFG
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;./bomb 
Welcome to my fiendish little bomb. You have 6 phases with
which to blow yourself up. Have a nice day!
Border relations with Canada have never been better.
Phase 1 defused. How about the next one?
1 2 4 8 16 32
That&apos;s number 2.  Keep going!
0 207
Halfway there!
7 0
So you got that one.  Try this one.
IONEFG
Good work!  On to the next...
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;code&gt;phase_6()&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;$ objdump -d bomb --disassemble=phase_6                        

bomb：     文件格式 elf64-x86-64


Disassembly of section .init:

Disassembly of section .plt:

Disassembly of section .text:

00000000004010f4 &amp;lt;phase_6&amp;gt;:
  4010f4:       41 56                   push   %r14
  4010f6:       41 55                   push   %r13
  4010f8:       41 54                   push   %r12
  4010fa:       55                      push   %rbp
  4010fb:       53                      push   %rbx
  4010fc:       48 83 ec 50             sub    $0x50,%rsp
  401100:       49 89 e5                mov    %rsp,%r13
  401103:       48 89 e6                mov    %rsp,%rsi
  401106:       e8 51 03 00 00          call   40145c &amp;lt;read_six_numbers&amp;gt;
  40110b:       49 89 e6                mov    %rsp,%r14
  40110e:       41 bc 00 00 00 00       mov    $0x0,%r12d
  401114:       4c 89 ed                mov    %r13,%rbp
  401117:       41 8b 45 00             mov    0x0(%r13),%eax
  40111b:       83 e8 01                sub    $0x1,%eax
  40111e:       83 f8 05                cmp    $0x5,%eax
  401121:       76 05                   jbe    401128 &amp;lt;phase_6+0x34&amp;gt;
  401123:       e8 12 03 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  401128:       41 83 c4 01             add    $0x1,%r12d
  40112c:       41 83 fc 06             cmp    $0x6,%r12d
  401130:       74 21                   je     401153 &amp;lt;phase_6+0x5f&amp;gt;
  401132:       44 89 e3                mov    %r12d,%ebx
  401135:       48 63 c3                movslq %ebx,%rax
  401138:       8b 04 84                mov    (%rsp,%rax,4),%eax
  40113b:       39 45 00                cmp    %eax,0x0(%rbp)
  40113e:       75 05                   jne    401145 &amp;lt;phase_6+0x51&amp;gt;
  401140:       e8 f5 02 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  401145:       83 c3 01                add    $0x1,%ebx
  401148:       83 fb 05                cmp    $0x5,%ebx
  40114b:       7e e8                   jle    401135 &amp;lt;phase_6+0x41&amp;gt;
  40114d:       49 83 c5 04             add    $0x4,%r13
  401151:       eb c1                   jmp    401114 &amp;lt;phase_6+0x20&amp;gt;
  401153:       48 8d 74 24 18          lea    0x18(%rsp),%rsi
  401158:       4c 89 f0                mov    %r14,%rax
  40115b:       b9 07 00 00 00          mov    $0x7,%ecx
  401160:       89 ca                   mov    %ecx,%edx
  401162:       2b 10                   sub    (%rax),%edx
  401164:       89 10                   mov    %edx,(%rax)
  401166:       48 83 c0 04             add    $0x4,%rax
  40116a:       48 39 f0                cmp    %rsi,%rax
  40116d:       75 f1                   jne    401160 &amp;lt;phase_6+0x6c&amp;gt;
  40116f:       be 00 00 00 00          mov    $0x0,%esi
  401174:       eb 21                   jmp    401197 &amp;lt;phase_6+0xa3&amp;gt;
  401176:       48 8b 52 08             mov    0x8(%rdx),%rdx
  40117a:       83 c0 01                add    $0x1,%eax
  40117d:       39 c8                   cmp    %ecx,%eax
  40117f:       75 f5                   jne    401176 &amp;lt;phase_6+0x82&amp;gt;
  401181:       eb 05                   jmp    401188 &amp;lt;phase_6+0x94&amp;gt;
  401183:       ba d0 32 60 00          mov    $0x6032d0,%edx
  401188:       48 89 54 74 20          mov    %rdx,0x20(%rsp,%rsi,2)
  40118d:       48 83 c6 04             add    $0x4,%rsi
  401191:       48 83 fe 18             cmp    $0x18,%rsi
  401195:       74 14                   je     4011ab &amp;lt;phase_6+0xb7&amp;gt;
  401197:       8b 0c 34                mov    (%rsp,%rsi,1),%ecx
  40119a:       83 f9 01                cmp    $0x1,%ecx
  40119d:       7e e4                   jle    401183 &amp;lt;phase_6+0x8f&amp;gt;
  40119f:       b8 01 00 00 00          mov    $0x1,%eax
  4011a4:       ba d0 32 60 00          mov    $0x6032d0,%edx
  4011a9:       eb cb                   jmp    401176 &amp;lt;phase_6+0x82&amp;gt;
  4011ab:       48 8b 5c 24 20          mov    0x20(%rsp),%rbx
  4011b0:       48 8d 44 24 28          lea    0x28(%rsp),%rax
  4011b5:       48 8d 74 24 50          lea    0x50(%rsp),%rsi
  4011ba:       48 89 d9                mov    %rbx,%rcx
  4011bd:       48 8b 10                mov    (%rax),%rdx
  4011c0:       48 89 51 08             mov    %rdx,0x8(%rcx)
  4011c4:       48 83 c0 08             add    $0x8,%rax
  4011c8:       48 39 f0                cmp    %rsi,%rax
  4011cb:       74 05                   je     4011d2 &amp;lt;phase_6+0xde&amp;gt;
  4011cd:       48 89 d1                mov    %rdx,%rcx
  4011d0:       eb eb                   jmp    4011bd &amp;lt;phase_6+0xc9&amp;gt;
  4011d2:       48 c7 42 08 00 00 00    movq   $0x0,0x8(%rdx)
  4011d9:       00 
  4011da:       bd 05 00 00 00          mov    $0x5,%ebp
  4011df:       48 8b 43 08             mov    0x8(%rbx),%rax
  4011e3:       8b 00                   mov    (%rax),%eax
  4011e5:       39 03                   cmp    %eax,(%rbx)
  4011e7:       7d 05                   jge    4011ee &amp;lt;phase_6+0xfa&amp;gt;
  4011e9:       e8 4c 02 00 00          call   40143a &amp;lt;explode_bomb&amp;gt;
  4011ee:       48 8b 5b 08             mov    0x8(%rbx),%rbx
  4011f2:       83 ed 01                sub    $0x1,%ebp
  4011f5:       75 e8                   jne    4011df &amp;lt;phase_6+0xeb&amp;gt;
  4011f7:       48 83 c4 50             add    $0x50,%rsp
  4011fb:       5b                      pop    %rbx
  4011fc:       5d                      pop    %rbp
  4011fd:       41 5c                   pop    %r12
  4011ff:       41 5d                   pop    %r13
  401201:       41 5e                   pop    %r14
  401203:       c3                      ret

Disassembly of section .fini:
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Niri 安装与配置</title><link>https://sakimidare.top/posts/niri-manual/</link><guid isPermaLink="true">https://sakimidare.top/posts/niri-manual/</guid><description>Niri 窗口管理器的安装配置以及踩坑备忘录</description><pubDate>Fri, 24 Oct 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Niri 简介&lt;/h1&gt;
&lt;p&gt;:::hyperlink{href=&quot;https://wiki.archlinux.org/title/Niri&quot; title=&quot;Niri&quot; avatar=&quot;https://wiki.archlinuxcn.org/favicon.ico&quot; description=&quot;Arch Linux 的 Niri 介绍&quot;}
:::&lt;/p&gt;
&lt;p&gt;Niri 和 我们熟悉的 Windows 桌面或 KDE Plasma 不同。他是一个水平式排列的窗口管理器。每当新打开一个窗口，便会显示在当前窗口的右侧（而非像 Windows 那样堆叠）。在 Niri 中，没有开始按钮、没有最小化、没有最大化，有的只是随心所欲用快捷键和触摸板切换窗口的流畅操作和炫酷动画！&lt;/p&gt;
&lt;h1&gt;成品图&lt;/h1&gt;
&lt;p&gt;话不多说，赶快端上成品图：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./screenshot1.png&quot; alt=&quot;BTW I use arch!&quot; /&gt;
&lt;img src=&quot;./screenshot2.png&quot; alt=&quot;Material Design 风格的控制中心&quot; /&gt;
&lt;img src=&quot;./screenshot3.png&quot; alt=&quot;比 Windows 更炫酷的多桌面&quot; /&gt;&lt;/p&gt;
&lt;p&gt;通知栏的图标暂时没有配置，不过问题不大。想拥有这个炫酷 WM (Window Manager) 吗？跟我一步一步配置，你也可以做到！&lt;/p&gt;
&lt;h1&gt;安装步骤&lt;/h1&gt;
&lt;p&gt;:::note
下面的安装步骤假定你已经安装好了 Arch Linux。如果并非如此，请参阅其他安装 Arch Linux 的教程。我推荐阅读 &lt;a href=&quot;https://wiki.archlinuxcn.org/wiki/%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97&quot;&gt;Archwiki&lt;/a&gt;。
:::&lt;/p&gt;
&lt;p&gt;:::warning
以下教程对你有以下要求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;耐心，愿意试错；&lt;/li&gt;
&lt;li&gt;阅读过&lt;a href=&quot;https://www.sakimidare.top/posts/how-to-ask-questions-the-smart-way/&quot;&gt;提问的智慧&lt;/a&gt;；&lt;/li&gt;
&lt;li&gt;有初步的 Linux 知识；
:::&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;开始之前，放几个链接：&lt;/p&gt;
&lt;p&gt;:::hyperlink{href=&quot;https://yalter.github.io/niri/Getting-Started.html&quot; title=&quot;Niri&quot; avatar=&quot;https://yalter.github.io/favicon.ico&quot; description=&quot;Niri 项目维护者的教程&quot;}
:::&lt;/p&gt;
&lt;p&gt;:::github{repo=&quot;YaLTeR/niri&quot;}
:::&lt;/p&gt;
&lt;h2&gt;安装 Niri 软件包&lt;/h2&gt;
&lt;p&gt;:::warning&lt;/p&gt;
&lt;p&gt;Niri 并不像 KDE Plasma 和 Xfce 一样附带了一系列 GUI 程序可以开箱即用。因此，你可能需要安装附加程序如 &lt;code&gt;blueman&lt;/code&gt; 来管理蓝牙设备、&lt;code&gt;dolphin&lt;/code&gt; 来浏览文件、&lt;code&gt;alacritty&lt;/code&gt; 来运行终端、&lt;code&gt;gwenview&lt;/code&gt; 来看图、 &lt;code&gt;vlc&lt;/code&gt; 打开媒体、&lt;code&gt;fcitx5&lt;/code&gt; 作为中文输入法、&lt;code&gt;noto-fonts&lt;/code&gt;来显示中文字体等等。具体安装步骤不再赘述，请参阅&lt;a href=&quot;https://wiki.archlinuxcn.org/&quot;&gt;Arch Linux 中文维基&lt;/a&gt;获得必要信息。&lt;/p&gt;
&lt;p&gt;另外，如上文所述，本文假定你是一个 Linux 用户。所以你的电脑上理应有 &lt;code&gt;git&lt;/code&gt; &lt;code&gt;yay&lt;/code&gt; &lt;code&gt;gcc&lt;/code&gt; &lt;code&gt;clang&lt;/code&gt; &lt;code&gt;rust&lt;/code&gt;  &lt;code&gt;make&lt;/code&gt; &lt;code&gt;python&lt;/code&gt;等最基本的软件包。Niri 使用 Rust 编写，所以你得安装 &lt;code&gt;rust&lt;/code&gt; 软件包来执行 &lt;code&gt;make&lt;/code&gt; 操作。如有这些软件包缺失，请自行安装。
:::&lt;/p&gt;
&lt;p&gt;你可以用这两条命令：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S niri xdg-desktop-portal-gtk xdg-desktop-portal-gnome alacritty swaybg swayidle hyprlock xwayland-satellite dolphin sddm brightnessctl wireplumber grim flameshot breeze wshowkeys-git fcitx5 fcitx5-qt fcitx5-chinese-addons blueman noto-fonts libnotify pipewire pipewire-pulse
yay -S noctalia-shell vicinae ttf-jetbrains-mono misans 

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;安装必要的软件包。&lt;/p&gt;
&lt;p&gt;Noctalia Shell 是一个使用 Material Design 的用户界面。它可以接管系统通知，声音和显示亮度调节，并在最上方显示一个很他吗炫酷的状态栏。&lt;/p&gt;
&lt;p&gt;Vicinae 是一个 App 启动器，可以把它理解为 Windows 上的开始菜单。在我的配置中，所有不在快捷键配置里的程序都需要从这里启动。&lt;/p&gt;
&lt;h2&gt;配置&lt;/h2&gt;
&lt;h2&gt;SDDM&lt;/h2&gt;
&lt;p&gt;Niri 安装完成后，会自动创建 &lt;code&gt;.desktop&lt;/code&gt; 文件。这个 &lt;code&gt;.desktop&lt;/code&gt; 文件会被 SDDM 识别并提供登录到会话的选项。如果你还没有使用 SDDM 作为登录管理器，请先启用服务。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl enable sddm.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样在系统开机时会自动运行 SDDM，以便启动 Niri 会话。&lt;/p&gt;
&lt;h2&gt;编辑 niri.service 的 wants&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;systemctl --user add-wants niri swayidle
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样做可以让 &lt;code&gt;swayidle&lt;/code&gt; 软件包接管锁屏、睡眠等系统操作。
:::note
不需要照着官方文档加上 &lt;code&gt;waybar&lt;/code&gt; 和 &lt;code&gt;mako&lt;/code&gt;！我的配置没装这两个软件包，Shell 和通知全由 Noctalia Shell 接管！
:::&lt;/p&gt;
&lt;p&gt;编辑 &lt;code&gt;~/.config/systemd/user/niri.service.wants/swayidle.service&lt;/code&gt;。
填入以下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Unit]
PartOf=graphical-session.target
After=graphical-session.target
Requisite=graphical-session.target

[Service]
ExecStart=/usr/bin/swayidle -w timeout 601 &apos;niri msg action power-off-monitors&apos; timeout 600 &apos;hyprlock&apos; before-sleep &apos;hyprlock&apos;
Restart=on-failure
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个配置是为了无操作 600 秒后用 &lt;code&gt;hyprlock&lt;/code&gt; 锁屏，601 秒后关闭显示器。
如果有睡眠、休眠等需求，请查阅 Swaylock 官方文档。&lt;/p&gt;
&lt;h2&gt;修改 Niri 配置文件&lt;/h2&gt;
&lt;p&gt;创建 &lt;code&gt;~/.config/niri/config.kdl&lt;/code&gt; 文件并写入配置。
除了显示器配置，其他你可以抄我的。显示器配置请根据注释自行修改。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 键盘鼠标触摸板等输入设备相关配置
input {
    keyboard {
        xkb {
            layout &quot;us&quot;
        }

        // 在启动上启用numlock，省略此设置会禁用它。
        numlock
    }

    touchpad {
        tap
        natural-scroll
        scroll-method &quot;two-finger&quot;
    }

    mouse {
        // 设置鼠标移动速度,-1到1之间由慢到快
        accel-speed 1
    }

    // niri默认接管电源按钮的功能是sleep,这里禁用以使用关机功能
    disable-power-key-handling
    // 切换mod键：正常使用alt，嵌套窗口内使用Super。
    mod-key &quot;Super&quot;
    mod-key-nested &quot;Alt&quot;
}

// 可以在niri实例中运行`niri msg outputs`找到显示器名称。
output &quot;HDMI&quot; {
    // 取消注释以禁用此显示器。
    off

    // 默认聚焦在这个显示器
    focus-at-startup

    // 格式为&quot;&amp;lt;width&amp;gt;x&amp;lt;height&amp;gt;&quot; 或者 &quot;&amp;lt;width&amp;gt;x&amp;lt;height&amp;gt;@&amp;lt;refresh rate&amp;gt;&quot;.
    // 如果省略了刷新率，niri将为分辨率选择最高的刷新率。
    mode &quot;3840x2160@60.000&quot;

    // 您可以使用整数或分数量表，例如，比例为150％。
    scale 2

    // transform允许逆时针旋转显示，有效值为:
    // normal, 90, 180, 270, flipped, flipped-90, flipped-180 and flipped-270.
    transform &quot;normal&quot;

    // 输出在所有显示器坐标空间中的位置。未明确配置位置的显示器将放置在所有已放置的显示器右侧。
    // position x=1280 y=0
}

// 如果 eDP-2 没有连接，将会默认聚焦在这个显示器
output &quot;eDP-2&quot; {
    // off
    focus-at-startup
    mode &quot;2560x1600@300.000&quot;
    transform &quot;normal&quot;
    position x=0 y=0
}

// 可以使用wev来查询特定的按键对应的XKB名称
binds {
    Alt+Tab { spawn &quot;niri-switch&quot;; }
    // Mod-Shift-/显示重要的热键列表(通常与 Mod-? 相同)。
    Mod+Shift+Slash { show-hotkey-overlay; }
    Mod+D hotkey-overlay-title=&quot;Open the File Manager&quot; { spawn &quot;/usr/bin/dolphin&quot;; } 
    // Mod+L hotkey-overlay-title=&quot;Lock the Screen: swaylock&quot; { spawn &quot;/usr/bin/swaylock&quot; &quot;-f&quot; &quot;-i&quot; &quot;$HOME/.dotfiles/sway/.config/sway/lock.png&quot;; }
    Mod+L hotkey-overlay-title=&quot;Lock the Screen: hyprlock&quot; { spawn &quot;/usr/bin/hyprlock&quot;; }
    Mod+Return hotkey-overlay-title=&quot;Open a Terminal&quot; { spawn &quot;/usr/bin/alacritty&quot;; }
   // Mod+A hotkey-overlay-title=&quot;Run an Application&quot; { spawn &quot;/usr/bin/fuzzel&quot;; }
    Mod+A hotkey-overlay-title=&quot;Run an Application&quot; { spawn &quot;/usr/bin/vicinae&quot; &quot;toggle&quot;; }
    Mod+X hotkey-overlay-title=&quot;Open a browser: zen&quot; { spawn &quot;/usr/bin/google-chrome-stable&quot;; }
    // Mod+D hotkey-overlay-title=&quot;同步切换obs和mpv状态&quot; { spawn &quot;/usr/bin/touch&quot; &quot;/tmp/obs_mpv_toggle_pause&quot;; }
    Mod+K hotkey-overlay-title=&quot;打开screenkey&quot; { spawn &quot;/usr/bin/wshowkeys&quot; &quot;-a&quot; &quot;right&quot; &quot;-a&quot; &quot;bottom&quot; &quot;-F&quot; &quot;ComicShannsMono Nerd Font 30&quot;; }
    Mod+Shift+K hotkey-overlay-title=&quot;关闭screenkey&quot; { spawn &quot;/usr/bin/killall&quot; &quot;wshowkeys&quot;; }
    // Mod+Shift+C hotkey-overlay-title=&quot;重启waybar&quot; { spawn-sh &quot;pkill waybar &amp;amp;&amp;amp; waybar&quot;; }

    // 音量控制 allow-when-locked=true 在锁屏时的按键也会生效。这里的wpctl是wireplumber包中附带的
    XF86AudioRaiseVolume allow-when-locked=true { spawn-sh &quot;wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1+&quot;; }
    XF86AudioLowerVolume allow-when-locked=true { spawn-sh &quot;wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.1-&quot;; }
    XF86AudioMute        allow-when-locked=true { spawn-sh &quot;wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle&quot;; }
    XF86AudioMicMute     allow-when-locked=true { spawn-sh &quot;wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle&quot;; }

    // 亮度控制。brightnessctl 有独立的包
    XF86MonBrightnessUp allow-when-locked=true { spawn &quot;brightnessctl&quot; &quot;set&quot; &quot;+10%&quot;; }
    XF86MonBrightnessDown allow-when-locked=true { spawn &quot;brightnessctl&quot; &quot;set&quot; &quot;10%-&quot;; }

    // 开关overview
    Mod+Tab repeat=false { toggle-overview; }
    // 关闭窗口
    Mod+Q repeat=false { close-window; }

    // 窗口焦点切换，位置移动
    Mod+Left  { focus-column-left; }
    Mod+Down  { focus-window-down; }
    Mod+Up    { focus-window-up; }
    Mod+Right { focus-column-right; }
    Mod+N     { focus-column-left; }
    Mod+i     { focus-column-right; }
    Mod+Alt+Left { consume-or-expel-window-left; }
    Mod+Alt+Right {consume-or-expel-window-right; }
    // Mod+N     { spawn-sh &quot;niri msg action focus-column-left &amp;amp;&amp;amp; niri msg action center-column&quot;; }
    // Mod+i     { spawn-sh &quot;niri msg action focus-column-right &amp;amp;&amp;amp; niri msg action center-column&quot;; }
    Mod+Shift+Left  { move-column-left; }
    Mod+Shift+Down  { move-window-down; }
    Mod+Shift+Up    { move-window-up; }
    Mod+Shift+Right { move-column-right; }
    Mod+Shift+N     { move-column-left; }
    Mod+Shift+I     { move-column-right; }

    Mod+Home { focus-column-first; }
    Mod+End  { focus-column-last; }
    Mod+Shift+Home { move-column-to-first; }
    Mod+Shift+End  { move-column-to-last; }

    // workspace焦点切换，窗口在workspace之间移动
    Mod+Page_Down      { focus-workspace-down; }
    Mod+Page_Up        { focus-workspace-up; }
    Mod+Ctrl+Page_Down { move-column-to-workspace-down; }
    Mod+Ctrl+Page_Up   { move-column-to-workspace-up; }
    // 上下移动整个workspace
    Mod+Shift+Page_Down { move-workspace-down; }
    Mod+Shift+Page_Up   { move-workspace-up; }

    // 上下方向共用的窗口、工作空间的焦点切换和位置移动
    Mod+E     { focus-window-or-workspace-down; }
    Mod+U     { focus-window-or-workspace-up; }
    Mod+Shift+E     { move-window-down-or-to-workspace-down; }
    Mod+Shift+U     { move-window-up-or-to-workspace-up; }

    // 显示器焦点切换
    Mod+Ctrl+Left  { focus-monitor-left; }
    Mod+Ctrl+Down  { focus-monitor-down; }
    Mod+Ctrl+Up    { focus-monitor-up; }
    Mod+Ctrl+Right { focus-monitor-right; }
    Mod+Ctrl+N     { focus-monitor-left; }
    Mod+Ctrl+E     { focus-monitor-down; }
    Mod+Ctrl+U     { focus-monitor-up; }
    Mod+Ctrl+I     { focus-monitor-right; }

    // 跨显示器移动窗口
    Mod+Shift+Ctrl+Left  { move-column-to-monitor-left; }
    Mod+Shift+Ctrl+Down  { move-column-to-monitor-down; }
    Mod+Shift+Ctrl+Up    { move-column-to-monitor-up; }
    Mod+Shift+Ctrl+Right { move-column-to-monitor-right; }
    Mod+Shift+Ctrl+N     { move-column-to-monitor-left; }
    Mod+Shift+Ctrl+E     { move-column-to-monitor-down; }
    Mod+Shift+Ctrl+U     { move-column-to-monitor-up; }
    Mod+Shift+Ctrl+I     { move-column-to-monitor-right; }

    // 鼠标相关快捷键
    Mod+WheelScrollDown      cooldown-ms=150 { focus-workspace-down; }
    Mod+WheelScrollUp        cooldown-ms=150 { focus-workspace-up; }
    Mod+Ctrl+WheelScrollDown cooldown-ms=150 { move-column-to-workspace-down; }
    Mod+Ctrl+WheelScrollUp   cooldown-ms=150 { move-column-to-workspace-up; }

    Mod+WheelScrollRight      { focus-column-right; }
    Mod+WheelScrollLeft       { focus-column-left; }
    Mod+Ctrl+WheelScrollRight { move-column-right; }
    Mod+Ctrl+WheelScrollLeft  { move-column-left; }

    Mod+Shift+WheelScrollDown      { focus-column-right; }
    Mod+Shift+WheelScrollUp        { focus-column-left; }
    Mod+Ctrl+Shift+WheelScrollDown { move-column-right; }
    Mod+Ctrl+Shift+WheelScrollUp   { move-column-left; }

    Mod+TouchpadScrollDown { spawn-sh &quot;wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02+&quot;; }
    Mod+TouchpadScrollUp   { spawn-sh &quot;wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.02-&quot;; }

    Mod+1 { focus-workspace 1; }
    Mod+2 { focus-workspace 2; }
    Mod+3 { focus-workspace 3; }
    Mod+4 { focus-workspace 4; }
    Mod+5 { focus-workspace 5; }
    Mod+6 { focus-workspace 6; }
    Mod+7 { focus-workspace 7; }
    Mod+8 { focus-workspace 8; }
    Mod+9 { focus-workspace 9; }
    Mod+0 { focus-workspace 10; }
    Mod+Shift+1 { move-column-to-workspace 1; }
    Mod+Shift+2 { move-column-to-workspace 2; }
    Mod+Shift+3 { move-column-to-workspace 3; }
    Mod+Shift+4 { move-column-to-workspace 4; }
    Mod+Shift+5 { move-column-to-workspace 5; }
    Mod+Shift+6 { move-column-to-workspace 6; }
    Mod+Shift+7 { move-column-to-workspace 7; }
    Mod+Shift+8 { move-column-to-workspace 8; }
    Mod+Shift+9 { move-column-to-workspace 9; }
    Mod+Shift+0 { move-column-to-workspace 10; }

    // 最大化和全屏
    Mod+W { toggle-windowed-fullscreen; }
    Mod+F { expand-column-to-available-width; }
    Mod+Shift+F { fullscreen-window; }

    // 未最大化的窗口居中
    Mod+C { center-column; }
    Mod+Ctrl+C { center-visible-columns; }

    // 在layout中预设的宽度和高度之间切换
    Mod+R { switch-preset-column-width; }
    Mod+Shift+R { switch-preset-window-height; }
    // 改变宽度单位可以有pixels、百分比
    Mod+Minus { set-column-width &quot;-10%&quot;; }
    Mod+Equal { set-column-width &quot;+10%&quot;; }

    // 改变高度
    Mod+Shift+Minus { set-window-height &quot;-10%&quot;; }
    Mod+Shift+Equal { set-window-height &quot;+10%&quot;; }

    // 切换悬浮窗，改变平铺和悬浮窗焦点
    Mod+Shift+Space       { toggle-window-floating; }
    Mod+Space { switch-focus-between-floating-and-tiling; }

    // 截图
    Alt+J { spawn-sh &quot;grim -g \&quot;$(slurp)\&quot; - | satty --filename - --output-filename ~/$(date &apos;+%Y%m%d-%H:%M:%S&apos;).png&quot;; }
    Alt+Shift+J { spawn &quot;flameshot&quot; &quot;gui&quot;; }
    Print { screenshot show-pointer=false; }
    Ctrl+Print { screenshot-screen write-to-disk=true; }
    Alt+Print { screenshot-window write-to-disk=true; }

    // 针对虚拟机软件可能需要键盘控制权。allow-inhibiting=false 忽略当前快捷键本身
    Mod+Escape allow-inhibiting=false { toggle-keyboard-shortcuts-inhibit; }

    // 退出niri将显示一个确认对话框，以避免意外退出。
    Mod+Shift+Q { quit; }

    // 关闭显示器。移动鼠标或按下任意按键恢复
    Mod+Shift+P { power-off-monitors; }
}

// 影响窗口的位置和尺寸的设置。
layout {
    // 在逻辑像素中设置Windows周围的缝隙。
    gaps 10
    background-color &quot;transparent&quot;
    // 存在多个窗口时，未最大化的窗口不自动居中，方便分屏
    center-focused-column &quot;never&quot;
    // 只有一个窗口时自动居中显示
    always-center-single-column

    // mod+r在预设之间切换的宽度。
    preset-column-widths {
        proportion 0.5
        proportion 0.2444
        proportion 0.7556
        // 固定设置逻辑像素的宽度精确设置。（受scale影响）
        // fixed 1920
    }

    preset-window-heights {
        proportion 0.5
        proportion 0.8
        proportion 1.0
    }
    // 关闭聚焦框
    focus-ring {
        // off
    }

    // 关闭边框
    border {
        off
    }
}

// 覆盖由niri启动的进程的环境变量
environment {
    QT_QPA_PLATFORMTHEME &quot;qt5ct&quot;
    ALL_PROXY &quot;http://127.0.0.1:7890&quot;
    LANG &quot;zh_CN.UTF-8&quot;
    LC_CTYPE &quot;zh_CN.UTF-8&quot;
    LC_NUMERIC &quot;zh_CN.UTF-8&quot;
    LC_TIME &quot;zh_CN.UTF-8&quot;
    LC_COLLATE &quot;zh_CN.UTF-8&quot;
    LC_MONETARY &quot;zh_CN.UTF-8&quot;
    LC_MESSAGES &quot;zh_CN.UTF-8&quot;
    LC_PAPER &quot;zh_CN.UTF-8&quot;
    LC_NAME &quot;zh_CN.UTF-8&quot;
    LC_ADDRESS &quot;zh_CN.UTF-8&quot;
    LC_TELEPHONE &quot;zh_CN.UTF-8&quot;
    LC_MEASUREMENT &quot;zh_CN.UTF-8&quot;
    LC_IDENTIFICATION &quot;zh_CN.UTF-8&quot;
    LC_ALL null
    // XDG_DATA_DIRS &quot;$HOME/.local/share&quot; &quot;$XDG_DATA_DIRS&quot;
    // GTK_IM_MODULE &quot;fcitx&quot;
    QT_IM_MODULE &quot;fcitx&quot;
    // https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland#Sway
    XMODIFIERS &quot;@im=fcitx&quot;
    QT_IM_MODULES &quot;wayland;fcitx&quot;
    GTK_IM_MODULE null
    SDL_IM_MODULE null
    GLFW_IM_MODULE null
}
spawn-at-startup &quot;niri-switch-daemon&quot;

// 启动niri时自动启动的软件
spawn-at-startup &quot;/usr/bin/fcitx5&quot;
// spawn-at-startup &quot;/usr/bin/v2rayn&quot;
// spawn-at-startup &quot;/usr/bin/waybar&quot;
spawn-at-startup &quot;/usr/bin/vicinae&quot; &quot;server&quot;
spawn-at-startup &quot;~/.cargo/bin/soteria&quot;
spawn-at-startup &quot;~/Desktop/tools/update_repositories.sh&quot;
spawn-at-startup &quot;qs&quot; &quot;-c&quot; &quot;noctalia-shell&quot;
spawn-at-startup &quot;/usr/bin/hyprlock&quot;
// 要运行shell命令（带有变量，管道等），请使用spawn-sh-at-at-startup：
spawn-sh-at-startup &quot;swaybg -i /path/to/your/wallpaper.png -m fill&quot;

hotkey-overlay {
    // 跳过“重要的热键”弹出窗口。
    skip-at-startup
}

// 设置截图保存的路径，null将会禁止保存到磁盘
screenshot-path &quot;~/Pictures/ScreenShot/%Y-%m-%d %H-%M-%S.png&quot;

// 忽略软件自带的装饰(例如标题栏)
prefer-no-csd

// 指定光标的主题和大小，打字时隐藏光标
cursor {
    // xcursor-theme &quot;Dracula-cursors&quot;
    xcursor-theme &quot;breeze&quot;
    xcursor-size 24
    hide-when-typing
}

// 使用`niri msg windows`查看Title和App ID等信息
window-rule {
    open-on-output &quot;eDP-2&quot;
    // default-window-height { proportion 0.9; }
    // default-floating-position x=100 y=200 relative-to=&quot;bottom-left&quot;
    // default-column-width { proportion 0.7556; }
    geometry-corner-radius 20 
    clip-to-geometry true
    border {
        // off
        on
        width 4
        active-gradient from=&quot;#bd93f9&quot; to=&quot;#94b9fa&quot; angle=135
        inactive-color &quot;#505050&quot;
        urgent-color &quot;#9b0000&quot;
        // active-gradient from=&quot;#80c8ff&quot; to=&quot;#bbddff&quot; angle=45
        // inactive-gradient from=&quot;#505050&quot; to=&quot;#808080&quot; angle=45 relative-to=&quot;workspace-view&quot;
        // urgent-gradient from=&quot;#800&quot; to=&quot;#a33&quot; angle=45
    }

    focus-ring{
        off
    }
    // opacity 0.75
}
window-rule {
    open-on-output &quot;eDP-2&quot;
    match app-id=&quot;scrcpy&quot;
    default-column-width { proportion 0.2444; }
}
window-rule {
    open-on-output &quot;eDP-2&quot;
    match app-id=r#&quot;chrome&quot;#
    default-column-width { proportion 0.8; }
    // border {
    //    on
    //    width 4
    //    active-color &quot;#61AFEF&quot;
    // }
    // open-focused false
}
window-rule {
    match app-id=&quot;com.gabm.satty&quot; title=&quot;satty&quot;
    border {
        on
        width 2
        active-color &quot;#61AFEF&quot;
    }
}

// `niri msg layers`显示有namespace可以在这里配置waybar透明度
layer-rule {
    match namespace=&quot;^quickshell-overview$&quot;
    place-within-backdrop true
    //     opacity 0.75
}

// Put swaybg inside the overview backdrop.
layer-rule {
    match namespace=&quot;^wallpaper$&quot;
    place-within-backdrop true
}

debug {
    honor-xdg-activation-with-invalid-serial
}
// 禁用鼠标左上角热脚
gestures {
    hot-corners {
        // off
    }
}

animations {
    // Uncomment to turn off all animations.
    // You can also put &quot;off&quot; into each individual animation to disable it.
    // off

    // Slow down all animations by this factor. Values below 1 speed them up instead.
    // slowdown 3.0

    // Individual animations.

    workspace-switch {
        spring damping-ratio=1.0 stiffness=1000 epsilon=0.0001
    }

    window-open {
        duration-ms 150
        curve &quot;ease-out-expo&quot;
    }

    window-close {
        duration-ms 150
        curve &quot;ease-out-quad&quot;
    }

    horizontal-view-movement {
        spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
    }

    window-movement {
        spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
    }

    window-resize {
        spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
    }

    config-notification-open-close {
        spring damping-ratio=0.6 stiffness=1000 epsilon=0.001
    }

    exit-confirmation-open-close {
        spring damping-ratio=0.6 stiffness=500 epsilon=0.01
    }

    screenshot-ui-open {
        duration-ms 200
        curve &quot;ease-out-quad&quot;
    }

    overview-open-close {
        spring damping-ratio=1.0 stiffness=800 epsilon=0.0001
    }
}


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里面热键配置部分的 &lt;code&gt;Mod&lt;/code&gt; 在 SDDM 启动的 Niri 下全部代指 Super 键（也就是印刷着 Windows 徽标的那个键）。&lt;/p&gt;
&lt;p&gt;以下是几个常用热键：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;热键&lt;/th&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Shift + /(?)&lt;/td&gt;
&lt;td&gt;显示热键菜单&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + A&lt;/td&gt;
&lt;td&gt;打开 Vicinae (App 启动器)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + D&lt;/td&gt;
&lt;td&gt;打开 Dolphin（文件管理器）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + X&lt;/td&gt;
&lt;td&gt;打开 &lt;code&gt;google-chrome-stable&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Enter&lt;/td&gt;
&lt;td&gt;打开 Konsole （终端）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + R&lt;/td&gt;
&lt;td&gt;在预设的列宽中切换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Shift + R&lt;/td&gt;
&lt;td&gt;在预设的列高中切换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + F&lt;/td&gt;
&lt;td&gt;将当前列的宽度扩展到最大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + L&lt;/td&gt;
&lt;td&gt;用 Hyprlock 锁屏&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + 左右箭头&lt;/td&gt;
&lt;td&gt;切换窗口左右焦点&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Shift + 左右箭头&lt;/td&gt;
&lt;td&gt;将当前列和左右列互换位置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Alt + 左右箭头&lt;/td&gt;
&lt;td&gt;将该窗口吸收进左右列中或从当前列释放出去&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + PgUp / PgDn&lt;/td&gt;
&lt;td&gt;上下切换工作区&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Ctrl + PgUp / PgDn&lt;/td&gt;
&lt;td&gt;将当前列移动到上下工作区&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mod + Tab&lt;/td&gt;
&lt;td&gt;进入 Overview （缩小整个屏幕以显示工作区概览）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PrtSc&lt;/td&gt;
&lt;td&gt;截屏并复制到剪贴板以及保存到 ~&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ctrl + PrtSc&lt;/td&gt;
&lt;td&gt;截全屏，操作同上&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;三指滑动触摸板&lt;/td&gt;
&lt;td&gt;切换窗口以及工作区&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;四指滑动触摸板&lt;/td&gt;
&lt;td&gt;操作同 Mod + Tab&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;还有不少热键，懒得打了，看上面的配置吧。个人用得比较多的就这几个了。&lt;/p&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 要运行shell命令（带有变量，管道等），请使用spawn-sh-at-at-startup：
spawn-sh-at-startup &quot;swaybg -i /path/to/your/wallpaper.png -m fill&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这一行请务必填入自己的壁纸位置，否则壁纸是灰的！&lt;/p&gt;
&lt;p&gt;:::note
本配置使用 &lt;code&gt;swaybg&lt;/code&gt; 接管壁纸，所以无需在 Noctalia Shell 里面设置壁纸。
:::&lt;/p&gt;
&lt;h2&gt;修改 Hyprlock 配置文件&lt;/h2&gt;
&lt;p&gt;&lt;s&gt;（我喜欢混搭）&lt;/s&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;~/.config/hypr
├── hyprlock.conf
└── mocha
    └── mocha.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请创建如上所示的目录结构，即运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mkdir ~/.config/hypr
mkdir ~/.config/hypr/mocha
touch ~/.config/hypr/hyprlock.conf
touch ~/.config/hypr/mocha/mocha.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请编辑 &lt;code&gt;~/.config/hypr/hyprlock.conf&lt;/code&gt;，填入以下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;source = $HOME/.config/hypr/mocha/mocha.conf

$accent = $mauve
$accentAlpha = $mauveAlpha
$font = JetBrains Mono

# GENERAL
general {
  hide_cursor = true
}

# BACKGROUND
background {
  monitor =
  path = /path/to/your/lock/screen/wallpaper.png
  blur_passes = 2
  color = $base
}

# LAYOUT
label {
  monitor =
  text = 键盘布局: $LAYOUT
  color = $text
  font_size = 25
  font_family = $font
  position = 30, -30
  halign = left
  valign = top
}

# TIME
label {
  monitor =
  text = $TIME
  color = $text
  font_size = 90
  font_family = $font
  position = -30, 0
  halign = right
  valign = top
}

# DATE
label {
  monitor =
  text = cmd[update:43200000] date +&quot;%Y年 %m月 %d日, %A&quot;
  color = $text
  font_size = 25
  font_family = $font
  position = -30, -150
  halign = right
  valign = top
}

# FINGERPRINT
{
  monitor = &quot;&quot;;
  text = &quot;$FPRINTPROMPT&quot;;
  color = &quot;$text&quot;;
  font_size = 14;
  font_family = $font;
  position = &quot;0, -107&quot;;
  halign = &quot;center&quot;;
  valign = &quot;center&quot;;
}

# USER AVATAR
image {
  monitor =
  path = $HOME/.face
  # size = 100
  size = 200
  border_color = $accent
  position = 0, 90
  # position = 0, 75
  halign = center
  valign = center
}

# INPUT FIELD
input-field {
  monitor =
  size = 300, 60
  outline_thickness = 4
  dots_size = 0.2
  dots_spacing = 0.2
  dots_center = true
  outer_color = $accent
  inner_color = $surface0
  font_color = $text
  fade_on_empty = false
  # placeholder_text = &amp;lt;span foreground=&quot;##$textAlpha&quot;&amp;gt;&amp;lt;i&amp;gt;󰌾 Logged in as &amp;lt;/i&amp;gt;&amp;lt;span foreground=&quot;##$accentAlpha&quot;&amp;gt;$USER&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
  placeholder_text = &amp;lt;span foreground=&quot;##$textAlpha&quot;&amp;gt;󰌾 &amp;lt;span foreground=&quot;##$accentAlpha&quot;&amp;gt;$USER&amp;lt;/span&amp;gt; 已登录 &amp;lt;/span&amp;gt;
  hide_input = false
  check_color = $accent
  fail_color = $red
  fail_text = &amp;lt;i&amp;gt; 已失败 &amp;lt;b&amp;gt;($ATTEMPTS)&amp;lt;/b&amp;gt; 次 &amp;lt;/i&amp;gt;
  capslock_color = $yellow
  # position = 0, -47
  position = 0, -80
  halign = center
  valign = center


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请在&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# BACKGROUND
background {
  monitor =
  path = /path/to/your/lock/screen/wallpaper.png
  blur_passes = 0
  color = $base
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;填入锁屏壁纸的位置。&lt;/p&gt;
&lt;p&gt;并请复制一份你的头像到 &lt;code&gt;~/.face&lt;/code&gt;。（注意：是创建一个&lt;code&gt;.face&lt;/code&gt;文件，而不是在 &lt;code&gt;.face&lt;/code&gt; 文件夹里面放上自己的头像图片！）&lt;/p&gt;
&lt;p&gt;编辑 &lt;code&gt;~/.config/hypr/mocha/mocha.conf&lt;/code&gt;，填入以下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$rosewater = rgb(f5e0dc)
$rosewaterAlpha = f5e0dc

$flamingo = rgb(f2cdcd)
$flamingoAlpha = f2cdcd

$pink = rgb(f5c2e7)
$pinkAlpha = f5c2e7

$mauve = rgb(cba6f7)
$mauveAlpha = cba6f7

$red = rgb(f38ba8)
$redAlpha = f38ba8

$maroon = rgb(eba0ac)
$maroonAlpha = eba0ac

$peach = rgb(fab387)
$peachAlpha = fab387

$yellow = rgb(f9e2af)
$yellowAlpha = f9e2af

$green = rgb(a6e3a1)
$greenAlpha = a6e3a1

$teal = rgb(94e2d5)
$tealAlpha = 94e2d5

$sky = rgb(89dceb)
$skyAlpha = 89dceb

$sapphire = rgb(74c7ec)
$sapphireAlpha = 74c7ec

$blue = rgb(89b4fa)
$blueAlpha = 89b4fa

$lavender = rgb(b4befe)
$lavenderAlpha = b4befe

$text = rgb(cdd6f4)
#$text = rgb(6c8cf5)
#$textAlpha = 6c8cf5
$textAlpha = cdd6f4

$subtext1 = rgb(bac2de)
$subtext1Alpha = bac2de

$subtext0 = rgb(a6adc8)
$subtext0Alpha = a6adc8

$overlay2 = rgb(9399b2)
$overlay2Alpha = 9399b2

$overlay1 = rgb(7f849c)
$overlay1Alpha = 7f849c

$overlay0 = rgb(6c7086)
$overlay0Alpha = 6c7086

$surface2 = rgb(585b70)
$surface2Alpha = 585b70

$surface1 = rgb(45475a)
$surface1Alpha = 45475a

$surface0 = rgb(313244)
$surface0Alpha = 313244

$base = rgb(1e1e2e)
$baseAlpha = 1e1e2e

$mantle = rgb(181825)
$mantleAlpha = 181825

$crust = rgb(11111b)
$crustAlpha = 11111b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;左右上角的文字颜色定义在&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$text = rgb(cdd6f4)
#$text = rgb(6c8cf5)
#$textAlpha = 6c8cf5
$textAlpha = cdd6f4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若觉得和壁纸不搭，可以直接替换成喜欢的 RGB 色值。&lt;/p&gt;
&lt;h2&gt;配置 Alacritty&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;git clone https://github.com/catppuccin/alacritty.git ~/.config/alacritty/catppuccin
touch ~/.config/alacritty/alacritty.toml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;~/.config/alacritty/alacritty.toml&lt;/code&gt; 填入以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[env]
TERM = &quot;xterm-256color&quot;

[general]
live_config_reload = true
import = [&quot;~/.config/alacritty/catppuccin/catppuccin-mocha.toml&quot;]

[window]
decorations = &quot;buttonless&quot;
dynamic_padding = false
opacity = 1.0

[window.padding]
x = 25
y = 20

[font]
size = 12.0

[font.bold]
family = &quot;JetBrains Mono&quot;
style = &quot;Heavy&quot;

[font.bold_italic]
family = &quot;JetBrains Mono&quot;
style = &quot;Heavy Italic&quot;

[font.italic]
family = &quot;JetBrains Mono&quot;
style = &quot;Medium Italic&quot;

[font.normal]
family = &quot;JetBrains Mono&quot;
style = &quot;Medium&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;配置 SDDM 自动登录&lt;/h2&gt;
&lt;p&gt;上面 Niri 配置中我们写到了&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;spawn-at-startup &quot;/usr/bin/hyprlock&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;为了跳过 SDDM 之后仍保证系统安全，这里会在启动 Niri 时自动锁屏。所以我们现在来配置 SDDM 自动登录。&lt;/p&gt;
&lt;p&gt;编辑 &lt;code&gt;/etc/sddm.conf.d/autologin.conf&lt;/code&gt; ，在里面加入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Autologin]
User=#your_username
Session=niri
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;请将 &lt;code&gt;#your_username&lt;/code&gt; 改成你的用户名。&lt;/p&gt;
&lt;h2&gt;重启，拥抱 Niri!&lt;/h2&gt;
&lt;p&gt;不出意外的话，重启之后，输入密码，你就能看到 Noctalia Shell 的欢迎界面了！&lt;/p&gt;
&lt;p&gt;拥抱 Niri 吧！拥抱一个比 KDE Plasma 占用少得多且美观的 WM ！&lt;/p&gt;
&lt;h1&gt;疑难解答&lt;/h1&gt;
&lt;p&gt;由于我是中途从 KDE 转向了 Niri 而非全新安装，所以这篇教程很有可能有软件包依赖以及其他大大小小的问题。如果遇到了问题，欢迎在评论区提出！&lt;/p&gt;
&lt;h2&gt;为什么我的输入法在 QQ 里面坏掉了？&lt;/h2&gt;
&lt;p&gt;你需要创建 &lt;code&gt;~/.config/qq-flags.conf&lt;/code&gt;，在里面填入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;--ozone-platform=wayland
--enable-wayland-ime
--wayland-text-input-version=3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;为什么右上角的应用图标这么丑？&lt;/h2&gt;
&lt;p&gt;我不到啊我也很难受！我会想办法的（跪）&lt;/p&gt;
&lt;h2&gt;为什么有些 GTK 软件是亮色的？这与我的主题不搭！&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;dconf write /org/gnome/desktop/interface/color-scheme &apos;&quot;prefer-dark&quot;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;... ？&lt;/h2&gt;
&lt;p&gt;留言吧求求了！！&lt;/p&gt;
&lt;h1&gt;最后&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;sudo pacman -S fastfetch hyfetch
hyfetch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;盯着你的电脑屏幕看几分钟，享受你的艺术品吧！&lt;/p&gt;
</content:encoded></item><item><title>如何成为黑客</title><link>https://sakimidare.top/posts/how-to-become-a-hacker/</link><guid isPermaLink="true">https://sakimidare.top/posts/how-to-become-a-hacker/</guid><description>How To Become A Hacker, Eric Steven Raymond, Thyrsus Enterprises, &lt; esr@thyrsus.com &gt;</description><pubDate>Wed, 10 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;How To Become A Hacker&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Eric Steven Raymond, &lt;a href=&quot;http://catb.org/~esr/&quot;&gt;Thyrsus Enterprises&lt;/a&gt;, &amp;lt; &lt;a href=&quot;mailto:esr@thyrsus.com&quot;&gt;esr@thyrsus.com&lt;/a&gt; &amp;gt;&lt;/p&gt;
&lt;p&gt;Copyright © 2001 Eric S. Raymond&lt;/p&gt;
&lt;p&gt;翻译：柯非, &amp;lt; &lt;a href=&quot;mailto:zer4tul@gmail.com&quot;&gt;zer4tul@gmail.com&lt;/a&gt; &amp;gt;&lt;/p&gt;
&lt;p&gt;这篇译文基于2020.01.03更新的&lt;a href=&quot;http://catb.org/~esr/faqs/hacker-howto.html&quot;&gt;原文&lt;/a&gt;修订版1.52。&lt;/p&gt;
&lt;p&gt;如果对译文有任何意见或者建议，&lt;strong&gt;请&lt;a href=&quot;https://github.com/zer4tul/hacker-howto/issues/new&quot;&gt;发Issue&lt;/a&gt;，或直接&lt;a href=&quot;https://github.com/zer4tul/hacker-howto/compare/&quot;&gt;发Pull Request&lt;/a&gt;给原仓库维护者。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原仓库：
:::github{repo=&quot;zer4tul/hacker-howto&quot;}
:::&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;为何会有这篇文档&lt;/h1&gt;
&lt;p&gt;身为&lt;a href=&quot;http://www.catb.org/jargon&quot;&gt;新黑客词典（The Jargon File）&lt;/a&gt;和许多其他广为人知的同类文章的作者，我常收到热心的网络新人的电子邮件，问及（大意上是）“如何成为一名魔法师似的黑客？”。1996年的时候我注意到这个重要的问题并没有相关的FAQ或文档页面，所以我写了一份。许多黑客认为这篇文章是权威的，我觉得它应该是吧。此外，我不会寻求在这个话题上的独立著作权，如果你不喜欢在这里读到的内容，自己写一篇吧。&lt;/p&gt;
&lt;p&gt;如果你是在离线阅读本文，可以在&lt;a href=&quot;http://catb.org/~esr/faqs/hacker-howto.html&quot;&gt;http://catb.org/~esr/faqs/hacker-howto.html&lt;/a&gt;找到本文的最新版本。（译注：本文的最新中文版可以在&lt;a href=&quot;https://github.com/zer4tul/hacker-howto&quot;&gt;这里&lt;/a&gt;找到）&lt;/p&gt;
&lt;p&gt;注意：本文的末尾有一系列&lt;a href=&quot;#%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98&quot;&gt;常见问题&lt;/a&gt;。请在向我发邮件询问关于本文的任何问题前 &lt;strong&gt;再三阅读&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;目前本文有许多语言的翻译版：&lt;a href=&quot;http://www.slashproc.net/doc/howto-ar.html&quot;&gt;阿拉伯语&lt;/a&gt;，&lt;a href=&quot;http://moneyaisle.com/worldwide/how-to-become-a-hacker-be&quot;&gt;白俄罗斯语&lt;/a&gt;, &lt;a href=&quot;http://www.0x08.org/docs/hacker-howto.html&quot;&gt;中文&lt;/a&gt;，&lt;a href=&quot;http://jjk.kybli.net/projekty/jakse-stat-hackerem.html&quot;&gt;捷克语&lt;/a&gt;，&lt;a href=&quot;http://www.olemichaelsen.dk/hacker-howto.html&quot;&gt;丹麦语&lt;/a&gt;，&lt;a href=&quot;http://www.knudde.be/index.php?page_name=hacker_howto&quot;&gt;荷兰语&lt;/a&gt;，&lt;a href=&quot;http://www.kakupesa.net/hacker/&quot;&gt;爱沙尼亚语&lt;/a&gt;，&lt;a href=&quot;http://www.linuxtaskforce.de/hacker-howto-ger.html&quot;&gt;德语&lt;/a&gt;，&lt;a href=&quot;http://users.otenet.gr/~indy90/hacker-howto-gr/&quot;&gt;希腊语&lt;/a&gt;，&lt;a href=&quot;http://www.victorfleur.com/documents/hacker.html&quot;&gt;意大利语&lt;/a&gt;，&lt;a href=&quot;http://he.wikisource.org/wiki/%D7%90%D7%99%D7%9A_%D7%9C%D7%94%D7%99%D7%95%D7%AA_%D7%94%D7%90%D7%A7%D7%A8&quot;&gt;希伯来语&lt;/a&gt;，&lt;a href=&quot;http://stian.atlantiscrew.net/doc/hacker-howto.html&quot;&gt;挪威语&lt;/a&gt;, &lt;a href=&quot;http://ashiyane.org/forums/showthread.php?t=20570&quot;&gt;波斯语&lt;/a&gt;，&lt;a href=&quot;http://jvdm.sdf1.org/pt/raquer-howto/&quot;&gt;巴西葡萄牙语&lt;/a&gt;，&lt;a href=&quot;http://garaj.xhost.ro/hacker-howto/hacker-howto.ro.htm&quot;&gt;罗马尼亚语&lt;/a&gt;，&lt;a href=&quot;http://www.sindominio.net/biblioweb/telematica/hacker-como.html&quot;&gt;西班牙语&lt;/a&gt;，&lt;a href=&quot;http://www.belgeler.org/howto/hacker-howto/hacker-howto.html&quot;&gt;土耳其语&lt;/a&gt;，&lt;a href=&quot;http://www1.tripnet.se/~mly/open/faqs/hacker-howto.se.html&quot;&gt;瑞典语&lt;/a&gt;。请注意，由于本文不定期更新，这些翻译版可能存在不同程度的过时。&lt;/p&gt;
&lt;p&gt;本文里九宫格中的5个黑点的装饰图被称作glider。这是一个使很多黑客多年痴迷的被称作&lt;a href=&quot;http://dmoz.org/Computers/Artificial_Life/Cellular_Automata/&quot;&gt;康威生命游戏（LIFE）&lt;/a&gt;中，具有令人惊奇特性的简单图案。我认为它是很好的黑客精神徽章 —— 抽象，初见的时候感觉有点神秘，通过它复杂的逻辑可以通向整个世界。如果你想了解更多关于glider的信息，请看&lt;a href=&quot;http://www.catb.org/~esr/hacker-emblem/&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;如果你觉得这篇文章有价值，请在&lt;a href=&quot;http://patreon.com/esr&quot;&gt;Patreon&lt;/a&gt;或者&lt;a href=&quot;https://www.subscribestar.com/esr&quot;&gt;SubscribeStar&lt;/a&gt;上给我一点赞助。也请考虑通过&lt;a href=&quot;http://www.catb.org/esr/loadsharers/&quot;&gt;Loadsharers&lt;/a&gt;赞助其他为你提供了有价值代码的黑客。小额的赞助也能够聚小流成江海，使为你提供帮助的人从繁重的劳动中解放出来，创造更多的价值。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;什么是黑客&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;http://www.catb.org/jargon&quot;&gt;新黑客词典（Jargon File）&lt;/a&gt;中有数个“黑客”的定义，主要形容&quot;技术专才&quot;或&quot;有志解决问题及超越极限之人&quot;。要成为黑客，有两个要点。&lt;/p&gt;
&lt;p&gt;这可以追溯到几十年前第一台分时小型电脑诞生, ARPAnet 实验也刚展开的年代，那时有一个由程序设计专家和网络名人所组成的, 具有分享特点的文化社群。 这种文化的成员创造了 “hacker” 这个词。他们建立了互联网，他们发明了现在使用的Unix操作系统。他们管理Usenet讨论组。他们令WWW运作。因此，若你有上述的特性及参与同类的社区，亦有对以上种种作出贡献，同时社区的人知你是谁又称你为“hacker”，你便是黑客。&lt;/p&gt;
&lt;p&gt;然而，黑客的理念并非只局限于软件社区。有很多人将黑客的态度应用于其他事物，如电子或音乐上——实际上，黑客的理念存在于任何科学及文学。由于了解黑客的理念及精神，软件社区的黑客亦会称后者为黑客。有些人亦认为黑客的理念是独立于黑客所从事的媒体。然而，我们将在这篇文章专注讨论软件黑客的技巧，态度及传统。&lt;/p&gt;
&lt;p&gt;另外，有一群人亦称自已为“黑客”，他们（多数是年青人）用电脑侵入其他电脑的系统作出破坏。黑客们称这群人为“Cracker（破坏者）”，亦不认同他们为黑客。多数黑客会认为Cracker是懒惰, 不负责任，不杰出的人。有能力侵入安全系统并不能使你成为黑客，正如可以用铁丝来偷车并不能使你成为汽车工程师一样。不幸的是很多作家及报道均称这群人为“黑客”。这一直使黑客们非常恼火。&lt;/p&gt;
&lt;p&gt;黑客与Cracker的主要区别在于，前者搞建设，后者搞破坏。&lt;/p&gt;
&lt;p&gt;如果你想成为一个黑客，请继续读下去。如果你只想做一个Cracker，请到&lt;a&gt;alt.2600&lt;/a&gt;讨论组，并做好当你发现自己不如想象中聪颖的时候进5到10次监狱的准备。关于Cracker我就说这么多。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;黑客的精神&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E4%B8%96%E4%B8%8A%E4%BB%8D%E6%9C%89%E5%A4%A7%E9%87%8F%E8%BF%B7%E4%BA%BA%E7%9A%84%E4%BA%8B%E6%83%85%E7%AD%89%E5%BE%85%E8%A7%A3%E5%86%B3&quot;&gt;世上仍有大量迷人的事情等待解决&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%90%8C%E6%A0%B7%E7%9A%84%E9%97%AE%E9%A2%98%E4%B8%8D%E5%BA%94%E8%A2%AB%E9%87%8D%E5%A4%8D%E5%A4%84%E7%90%86%E4%B8%A4%E6%AC%A1&quot;&gt;同样的问题不应被重复处理两次&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E6%8B%92%E7%BB%9D%E9%87%8D%E5%A4%8D%E5%92%8C%E6%B2%89%E9%97%B7%E7%9A%84%E4%BA%8B%E6%83%85&quot;&gt;拒绝重复和沉闷的事情&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E8%87%AA%E7%94%B1%E4%B8%87%E5%B2%81&quot;&gt;自由万岁&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%B2%BE%E7%A5%9E%E4%B8%8D%E8%83%BD%E4%BB%A3%E6%9B%BF%E8%83%BD%E5%8A%9B&quot;&gt;精神不能代替能力&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;黑客们解决问题，建设事物，他们崇尚自由和无私的双向帮助。要被他人承认是一名黑客，你必须表现得你具备了这样的态度。而要表现得你具备了这种态度，你必须彻彻底底的坚持它。&lt;/p&gt;
&lt;p&gt;如果你认为培养黑客的态度只是一条在这个文化圈中得到认同的路子，那就错了。成为具备这种素质的人对 &lt;strong&gt;你&lt;/strong&gt; ¸非常重要 —— 使你保持学习和成为黑客的自发性。正如所有创造性艺术一样，成为大师的最有效途径就是效仿大师的精神——不仅从理念上，还要从态度上效仿。&lt;/p&gt;
&lt;p&gt;或许下面的这首现代禅诗很好的阐述了这个意思：&lt;/p&gt;
&lt;p&gt;:::tip
To follow the path:&lt;br /&gt;
沿着这样一条道路：&lt;/p&gt;
&lt;p&gt;look to the master,&lt;br /&gt;
关注大师，&lt;/p&gt;
&lt;p&gt;follow the master,&lt;br /&gt;
跟随大师，&lt;/p&gt;
&lt;p&gt;walk with the master,&lt;br /&gt;
与大师同行，&lt;/p&gt;
&lt;p&gt;see through the master,&lt;br /&gt;
洞察大师，&lt;/p&gt;
&lt;p&gt;become the master.&lt;br /&gt;
成为大师。&lt;br /&gt;
:::&lt;/p&gt;
&lt;p&gt;如果你想成为一名黑客，反复阅读以下内容直到你相信它们：&lt;/p&gt;
&lt;h2&gt;世上仍有大量迷人的事情等待解决&lt;/h2&gt;
&lt;p&gt;作为一名黑客可以享受很多乐趣，同时需要付出相当多的努力。努力需要动力。成功的运动员从锻炼身体、超越身体极限中获得精神愉悦。类似的，作为一名黑客，你可以从解决问题、磨练技术和锻炼智力中获得乐趣。&lt;/p&gt;
&lt;p&gt;如果你天生不是这样的人，那你需要设法变成这样的人以使你能够成为一名黑客。否则你将会发现你的精力会被诸如性、金钱、社会上的虚名之类让人分心的东西所消磨掉。&lt;/p&gt;
&lt;p&gt;（你还需要对自己的学习能力树立信心——相信尽管你对某一问题了解得不多，只要你能解决其中一部分，并从中学习，你可以解决其他的部分——直到解决它。）&lt;/p&gt;
&lt;h2&gt;同样的问题不应被重复处理两次&lt;/h2&gt;
&lt;p&gt;创造性的智慧是非常有价值且稀缺的资源。它们不应当被浪费在重复发明轮子上，世上仍有大量迷人的新问题等着解决。&lt;/p&gt;
&lt;p&gt;作为一名黑客，你应该坚信其他黑客的时间非常宝贵——所以你有义务共享信息，解决问题之后公布方案，这样其他人可以去解决新的问题，而不是忙于应付旧问题。&lt;/p&gt;
&lt;p&gt;注意，“同一个问题不应该被重复处理两次”并不是说你必须认为所有已有方案都是最优的，或每个问题只有唯一的解决方案。通常我们从一个问题的最初解决方案中能够学习到很多东西。这很好，并且对于我们思考如何能做得更好来说，这通常是必要的。我们反对的是人为的技术、法律上的，或者机构性的设置障碍（例如闭源软件），使得一个好的方案不能被重复使用，逼得人们重造轮子。&lt;/p&gt;
&lt;p&gt;（你不必认为你必须将 &lt;strong&gt;所有&lt;/strong&gt; 你的创造发明都公布出去，虽然这样做的黑客将会赢得大家极度尊重。适当卖一些钱来换取足够的食物、租金和电脑并不违反黑客的价值观。用你的技能来养家糊口甚至致富都可以，只要你在做这些的时候别忘记你是一名黑客。）&lt;/p&gt;
&lt;h2&gt;拒绝重复和沉闷的事情&lt;/h2&gt;
&lt;p&gt;黑客（以及富有创造力的所有人）不应当被愚蠢的重复性劳动所困扰，因为这意味着他们并没有在做只有他们才能做的事情——解决新问题。这样的浪费会伤害所有人。因此，无聊和乏味的工作不仅仅是令人不爽，而是罪恶。&lt;/p&gt;
&lt;p&gt;作为一个黑客，你应该坚信这一点并尽可能的将枯燥的工作自动化，这不仅仅是为了你自己，也为了其他人（尤其是其他黑客）。&lt;/p&gt;
&lt;p&gt;（这里有一个例外。黑客有时会做一些看起来重复或枯燥的事情以进行脑力休息，或以此来锻炼一种技能，或以此获得某种除此以外无法获取的经验。但这是有选择的——有脑子的人不该被强迫做枯燥的事。）&lt;/p&gt;
&lt;h2&gt;自由万岁&lt;/h2&gt;
&lt;p&gt;黑客是天生的反独裁主义者。 任何能向你发号施令的人能够迫使你停止解决令你着迷的问题。 同时，按照独裁者的一般思路，他通常会给出一些极端愚昧的理由。因此，不论何处，任何独裁主义的作法，只要它压迫你和其他黑客，你就要和它斗到底。&lt;/p&gt;
&lt;p&gt;（这并非向所有权威挑战。儿童需要监护，罪犯要被看管起来。如果服从命令得到某种东西比起用其他方式得到它更节约时间，黑客可以同意 接受某种形式的权威。但这是一个有限度的，有意的交易；那种权威想要的个人服从不是你应该同意给予的。）&lt;/p&gt;
&lt;p&gt;权威喜欢审查和保密。他们不信任自愿的合作和信息共享——他们只喜欢由他们控制的所谓“合作”。因此，作为一个黑客，你得对审查、保密，以及使用武力或欺骗去压迫有行为能力的人们的做法有一种本能的敌意。 同时你要有为此信念斗争的意愿。&lt;/p&gt;
&lt;h2&gt;精神不能代替能力&lt;/h2&gt;
&lt;p&gt;作为一个黑客，你必须培养起这些精神。但是仅仅有精神并不能使你成为黑客，也不能使你成为运动健将或摇滚明星。成为一名黑客还需要智力，实践，奉献精神和辛勤工作。&lt;/p&gt;
&lt;p&gt;因此，你需要学会有怀疑态度和尊重任何能力。黑客不会为装模作样的人浪费时间，但他们尊重能力——尤其是从事黑客工作的能力，不过任何能力都是好的。很少人能具备的高要求能力尤其好，其中涉及脑力，技巧和专注方面的能力最好。&lt;/p&gt;
&lt;p&gt;尊重能力，你就会享受到提高自己的能力所带来的乐趣——辛苦的工作和奉献将不再是苦差而是一种高度娱乐。想要成为一名黑客，这一点尤其重要。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;基本黑客技能&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B&quot;&gt;学习编程&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E8%8E%B7%E5%8F%96%E4%B8%80%E4%B8%AA%E5%BC%80%E6%BA%90%E7%9A%84Unix%E5%B9%B6%E5%AD%A6%E4%B9%A0%E8%BF%90%E8%A1%8C%E5%92%8C%E4%BD%BF%E7%94%A8%E5%AE%83&quot;&gt;获取一个开源的Unix并学习运行和使用它&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%AD%A6%E4%B9%A0%E4%BD%BF%E7%94%A8%E4%B8%87%E7%BB%B4%E7%BD%91world-wide-webwww%E5%92%8Chtml%E8%B6%85%E6%96%87%E6%9C%AC%E6%A0%87%E8%AE%B0%E8%AF%AD%E8%A8%80&quot;&gt;学习使用万维网（World Wide Web，WWW）和HTML（超文本标记语言）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%AD%A6%E4%B9%A0%E5%AE%9E%E7%94%A8%E8%8B%B1%E8%AF%AD&quot;&gt;学习实用英语&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;黑客的态度很重要，但技能更重要。态度不能替代能力，在被别的黑客称你为黑客之前，你有一些基本技能需要掌握。&lt;/p&gt;
&lt;p&gt;这些基本技能随着时间的推移和技术的革新也缓慢的变化着。例如以前的内容中包括了使用机器语言编程，最近包含进了HTML。总的来说当前包括以下内容：&lt;/p&gt;
&lt;h2&gt;学习编程&lt;/h2&gt;
&lt;p&gt;理所当然，这是最基本的黑客技能。如果你一门计算机语言都不懂，我建议你从Python学起。它设计良好，文档详尽，并且对新人十分友好。尽管它是一门很好的入门语言，但它不只是玩具水平。它非常强大灵活，并且适用于大型项目。我写过一篇详细的&lt;a href=&quot;http://www.linuxjournal.com/article/3882&quot;&gt;对Python的评价&lt;/a&gt;。在&lt;a href=&quot;http://docs.python.org/tutorial/index.html&quot;&gt;Python的网站&lt;/a&gt;可以找到很好的&lt;a href=&quot;http://docs.python.org/tutorial/index.html&quot;&gt;教程&lt;/a&gt;。在&lt;a href=&quot;http://cscircles.cemc.uwaterloo.ca/&quot;&gt;Computer Science Circles&lt;/a&gt;也有一篇不错的第三方教程。&lt;/p&gt;
&lt;p&gt;我早前曾经建议使用Java作为入门语言，但&lt;a href=&quot;http://www.crosstalkonline.org/storage/issue-archives/2008/200801/200801-Dewar.pdf&quot;&gt;这篇评价&lt;/a&gt;改变了我的看法（请在文档中搜索“The Pitfalls of Java as a First Programming Language”）。如同文中尖锐指出的一样，一个黑客不能“像五金店中的管道工一样处理问题”。你需要知道所有的组件事实上都 &lt;strong&gt;干了什么&lt;/strong&gt;。现在，我认为最好先学C和Lisp，然后再学Java。&lt;/p&gt;
&lt;p&gt;比Java更好的选择是学习Go。这种相对较新的语言很容易从Python上手，而且学习它可以使你在可能的下一步（学习C语言）中得到很大的帮助。此外，未来几年的一个未知数是Go将在多大程度上取代C语言成为真正的系统编程语言。在未来，这种情况可能会在C语言的大部分传统领域内发生。&lt;/p&gt;
&lt;p&gt;另外有一点需要注意。如果一门语言帮你做了太多工作，它会同时是一个好的生产工具和一个不好的初学对象。不仅语言有这个问题，Web框架比如RubyOnRails，CakePHP，Django也很容易让你流于表面，面对困难问题的时候束手无策，甚至无法对一个简单问题进行追查并给出解决方案。&lt;/p&gt;
&lt;p&gt;如果你需要做一些重要的编程工作，你需要学习C语言，它是Unix的核心语言。C++跟C关系密切。如果你了解其中一种，学习另外一种应该不难。但是这两种语言都不适合作为入门学习。此外，如果你越避免用C编程，你的工作效率会越高。&lt;/p&gt;
&lt;p&gt;C的执行效率非常高，并且非常节省机器资源。不幸的是C的高效是通过让你手动进行许多底层资源（例如内存）管理来获得的。底层代码复杂并且容易出bug，你需要花费很多时间来进行调试。鉴于当今的机器性能如此之高，这样的做法通常很不划算——通常更好的做法是使用一种稍微慢一些，不那么高效，但是能够 &lt;strong&gt;大幅&lt;/strong&gt; 节省你的时间的语言。那便是Python。&lt;/p&gt;
&lt;p&gt;其他对黑客而言比较重要的语言包括Perl和LISP。Perl很实用，它广泛应用于动态网页和系统管理方面，因此即使你从不写Perl代码，至少也得能看懂。许多人使用Perl的理由和我建议你使用Python的理由一样，都是为了避免用C完成那些执行效率需求不那么高的工作。你需要能够看懂他们的代码。&lt;/p&gt;
&lt;p&gt;LISP之所以值得一学是基于另外的理由——当你最终掌握了它的时候，你将会获得巨大的启迪。它将使你在今后成为一个更好的程序员，即使你实际上很少使用LISP本身。（你可以通过为Emacs文本编辑器或者GIMP的Script-Fu编写插件或修改现有插件来很容易的学习LISP。）&lt;/p&gt;
&lt;p&gt;当然，你最好五种语言都会（Python，C/C++，Java，Perl和LISP）。除了是重要的黑客语言之外，它们也代表了截然不同的编程思路和方法，每一种都能让你受益匪浅。&lt;/p&gt;
&lt;p&gt;但是单纯的堆砌语言是不可能成为一个黑客，甚至程序员的。你需要学会如何独立于任何具体的语言之外来思考编程问题。作为一名真正的黑客，你需要通过手册和你已有的知识掌握到在几天之内学会一门语言的要点。这意味着你需要学习许许多多不同的语言。&lt;/p&gt;
&lt;p&gt;这里我无法给你完完全全的指导教会你如何编程——这是个复杂的技能。但我可以告诉你，书本和课程也不能做到（最好的黑客中，有许多，也许 &lt;strong&gt;几乎&lt;/strong&gt; 都是自学成才的）。 你可以从书本上学到语言的特点——这只是皮毛，但要使书面知识成为自身技能只能通过实践和虚心向他人学习。因此要做到（1）&lt;strong&gt;读&lt;/strong&gt; 代码及（2）&lt;strong&gt;写&lt;/strong&gt; 代码。&lt;/p&gt;
&lt;p&gt;Peter Norvig，Google最顶级的黑客之一，也是世界上最受欢迎的AI教材（译注：指“人工智能：一种现代方法”和“人工智能程序设计范例：通用Lisp语言的案例研究”等）的共同作者。他写了一篇名为&lt;a href=&quot;http://www.norvig.com/21-days.html&quot;&gt;Teach Yourself Programming in Ten Years&lt;/a&gt;的短文。他在文中提到的“编程成功的诀窍（recipe for programming success）”特别值得留意。&lt;/p&gt;
&lt;p&gt;学习编程就像学习用优美的自然语言书写一样。最好的办法就是阅读大师的名著，试着自己写点东西，再读一些，再写一点，再读一些，再写一点……如此往复，直到你的作品达到如你在范文中所见的简洁和健壮。&lt;/p&gt;
&lt;p&gt;我必须再提一下&lt;a href=&quot;http://catb.org/~esr/faqs/hacking-howto.html&quot;&gt;How To Learn Hacking&lt;/a&gt;，这是一些简单的说明，但是学起来并不容易。&lt;/p&gt;
&lt;p&gt;以前很难找到适合阅读的好代码，因为几乎没有大型程序的代码能够供新人阅读和练手。这种情况已经发生戏剧性的变化。开源软件，编程工具和操作系统（都是由黑客创造的）现在随处可见。这刚好带我们到下一个话题……&lt;/p&gt;
&lt;h2&gt;获取一个开源的Unix并学习运行和使用它&lt;/h2&gt;
&lt;p&gt;我假定你拥有或者能使用一台个人电脑（现在的孩子真幸福。黑客文化建立之初电脑贵得要死，没人买得起）。新手们向黑客技能迈出的最重要一步就是获取一份Linux或BSD-Unix的拷贝，将其安装在个人电脑上，并运行它。&lt;/p&gt;
&lt;p&gt;没错，世上除了Unix还有其他操作系统。但它们都是以二进制形式发布的——你读不到源码，你也不能修改代码。在类似Microsoft Windows那样的闭源操作系统上学习黑客技术就像戴着脚镣学跳舞。&lt;/p&gt;
&lt;p&gt;在Mac OS X上倒是可以，不过它只有一部分是开源的——你可能会撞墙，也必须很小心的避免养成依赖Apple专有代码的坏习惯。如果你专注于底层的Unix，你可以学到一些有用的东西。&lt;/p&gt;
&lt;p&gt;Unix是互联网上的操作系统。虽然你不懂Unix仍然可以学会使用互联网，但若你不懂Unix，你将不能在互联网上从事黑客活动。因此，现今的黑客文化是严重以Unix为中心的。（曾经不是这样，并且有一些老派的黑客对此仍然感到不太高兴。但是现今Unix和互联网的羁绊如此之强，连Microsoft也无法撼动分毫。）&lt;/p&gt;
&lt;p&gt;所以，请安装一套Unix - 我个人喜爱Linux但还有其他种类的（并且，你 &lt;strong&gt;可以&lt;/strong&gt; 在同一台电脑上运行Linux和Windows）。学习它，使用它，调教它。用它在互联网上冲浪。阅读它的代码，修改它的代码。你将获得比Windows操作系统上更好的编程工具（包括C，LISP，Python和Perl）。你会觉得其乐无穷，学到比你想像更多更好的知识。&lt;/p&gt;
&lt;p&gt;想要获取更多和学习Unix相关的信息，请参考&lt;a href=&quot;http://catb.org/~esr/faqs/loginataka.html&quot;&gt;Loginataka&lt;/a&gt;。你或许还想看看&lt;a href=&quot;http://catb.org/~esr/writings/taoup/&quot;&gt;Unix编程艺术&lt;/a&gt;（译注：这里给出的是原文链接。国内有翻译版出售）。&lt;/p&gt;
&lt;p&gt;我认为博客&lt;a href=&quot;https://letsgolarval.wordpress.com&quot;&gt;Let&apos;s Go Larval!&lt;/a&gt;对于处在学习Linux阶段中的用户是非常易懂和有用的。 这篇文章&lt;a href=&quot;https://letsgolarval.wordpress.com/2015/06/23/how-i-learned-linux&quot;&gt;How I Learned Linux&lt;/a&gt; 就是一个很好的起点。&lt;/p&gt;
&lt;p&gt;想开始Linux之旅，请参考&lt;a href=&quot;http://www.linux.org/&quot;&gt;Linux Online!&lt;/a&gt;。你可以从那里下载Linux或者（更好的主意是）找到一个当地的Linux用户群为你的安装过程提供帮助。&lt;/p&gt;
&lt;p&gt;在本文最初的10年间，我认为从一个初学者的角度来说，所有Linux发行版都差不多。不过在2006~2007年间，一个事实上最好的选择出现了：&lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt;。其他发行版各有所长，而Ubuntu对初学者最友好。注意，相比Ubuntu默认那个丑陋的几乎不可用的“Unity”桌面，Xubuntu和Kubuntu更好用一点。&lt;/p&gt;
&lt;p&gt;你可以在&lt;a href=&quot;http://www.bsd.org&quot;&gt;www.bsd.org&lt;/a&gt;找到BSD相关的帮助和资源。&lt;/p&gt;
&lt;p&gt;一个试水的好办法是试试被Linux爱好者称为“Live CD”的东西，那是一个完全在光盘或者U盘上运行，而不修改你硬盘的发行版。它运行起来比较慢，因为光盘很慢，但是这是一个在做出任何不可挽救的改变前看看可行性的办法。&lt;/p&gt;
&lt;p&gt;我写过一篇关于&lt;a href=&quot;http://en.tldp.org/HOWTO/Unix-and-Internet-Fundamentals-HOWTO/index.html&quot;&gt;Unix和互联网基础&lt;/a&gt;的入门文章。&lt;/p&gt;
&lt;p&gt;我曾经不建议新手独自安装Linux或者BSD。现在它们的安装程序已经做得足够好，你作为新人也完全搞得定。尽管如此，我仍然建议和你当地的Linux用户群取得联系并寻求帮助。这没坏处，并且可以让整个过程更顺利。&lt;/p&gt;
&lt;h2&gt;学习使用万维网（World Wide Web，WWW）和HTML（超文本标记语言）&lt;/h2&gt;
&lt;p&gt;大多数的黑客造物在你所不知的地方发挥着作用，帮助工厂、办公室和学校运转，这看上去跟普通人没太大关系。Web是一个大大的例外，即便 &lt;strong&gt;政客&lt;/strong&gt; 也承认这个巨大耀眼的黑客玩具正在改变着世界。单就这一个原因（当然还有其他理由）你就需要学习掌握Web。&lt;/p&gt;
&lt;p&gt;这并不仅仅意味着如何使用浏览器（谁都会），而是要学会如何写HTML，Web的标记语言。如果你不会编程，写HTML会教你一些有助于学习的思考习惯。因此，先完成一个主页。尝试坚持使用XHTML，一种比标准HTML更清晰的语言。（Web上有很多很好的初学者指南，例如&lt;a href=&quot;http://htmldog.com/&quot;&gt;这个&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;但仅仅拥有一个主页不能使你成为一名黑客。Web里充满了各种网页。大多数是毫无意义的，零信息量的垃圾——界面时髦，能夺人眼球的垃圾还是垃圾（更多信息访问&lt;a href=&quot;http://catb.org/~esr/html-hell.html&quot;&gt;The HTML Hell Page&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;所以，你的页面必须有内容——得是有趣并且/或者对其他黑客来说有用的内容。这是我们下一个议题要说的……&lt;/p&gt;
&lt;h2&gt;学习实用英语&lt;/h2&gt;
&lt;p&gt;作为一个美国人和一个以英语为母语的人，我以前很不情愿提到这点，免得成为一种文化上的帝国主义。但相当多以其他语言为母语的人一直劝我指出这一点，那就是英语是黑客文化和Internet的工作语言，你需要懂得以便在黑客社区顺利工作。&lt;/p&gt;
&lt;p&gt;大概1991年的时候我了解到许多黑客在技术讨论中使用英语，即使在他们的母语都相同，英语对他们而言只是第二语言的时候也常如此。据我所知，当前英语有着比其他语言丰富得多的技术词汇，因此是一个对于工作来说相当好的工具。基于同样的理由，英文技术书籍的翻译（如果有的话）通常都不能令读者满意。&lt;/p&gt;
&lt;p&gt;芬兰人Linus Torvalds用英语注释他的代码（很明显这不是凑巧）。他流利的英语成为他能够管理全球范围的Linux开发人员社区的重要因素。这是一个值得学习的例子。&lt;/p&gt;
&lt;p&gt;即使作为一个以英语为母语的人也不代表你就具备了成为黑客所需的语言技能。一般而言，如果你写得像个半文盲似的，文中充斥着各种语法、拼写错误，多半得不到理睬。虽然不严谨的文笔并不总是意味着不严谨的思维，但我们发现这两者之间的关联还是挺紧密的。而我们不需要这种思维不严谨的人。如果你现在还没有具备这样的书写能力，赶紧培养。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;在黑客社区中立足&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;#%E7%BC%96%E5%86%99%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6&quot;&gt;编写开源软件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%B8%AE%E5%8A%A9%E6%B5%8B%E8%AF%95%E5%92%8C%E8%B0%83%E8%AF%95%E5%BC%80%E6%BA%90%E8%BD%AF%E4%BB%B6&quot;&gt;帮助测试和调试开源软件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%8F%91%E5%B8%83%E6%9C%89%E7%94%A8%E7%9A%84%E4%BF%A1%E6%81%AF&quot;&gt;发布有用的信息&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E5%B8%AE%E5%8A%A9%E7%BB%B4%E6%8A%A4%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD%E8%BF%90%E8%BD%AC&quot;&gt;帮助维护基础设施运转&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#%E4%B8%BA%E9%BB%91%E5%AE%A2%E7%A4%BE%E5%8C%BA%E6%9C%8D%E5%8A%A1&quot;&gt;为黑客社区服务&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;像大部分非盈利社区一样，黑客社区靠声誉运转。你设法解决有趣的问题，但问题是否有趣及解决方法是否有效，需要由那些和你具有同样甚至更高技术水平的人去评判。&lt;/p&gt;
&lt;p&gt;因此，要玩黑客这个游戏，你需要以其他黑客对你技能的评判作为对自己的评价（所以我说，在其他黑客称你为黑客之前，你不是一个真正的黑客）。这个事实常被人误解（从1990年代后有所好转，但还是很严重），人们认为黑客都是不在乎别人的评价，孤僻的人。这实际上是一个黑客文化的禁忌。&lt;/p&gt;
&lt;p&gt;特别地，黑客被人类学家们称为 &lt;strong&gt;奉献社区&lt;/strong&gt;。在这里你不是凭借你对别人的统治来建立地位和名望，也不是靠美貌，或拥有其他人想要的东西，而是靠你的奉献。尤其是奉献你的时间，你的创造力和你的技术成果。&lt;/p&gt;
&lt;p&gt;要想获得黑客的尊重，你基本上有5件事情可干：&lt;/p&gt;
&lt;h2&gt;编写开源软件&lt;/h2&gt;
&lt;p&gt;首先（也是最传统和最重要的）是写一些其他黑客觉得有趣或有用的程序，并且开放源代码。&lt;/p&gt;
&lt;p&gt;（我们曾经把这些程序称为“自由软件（free software）”，但是太多人不能确定这里的“free”是什么意思。现在我们通常使用“&lt;a href=&quot;http://www.opensource.org/&quot;&gt;开源&lt;/a&gt;”软件这个词。&lt;/p&gt;
&lt;p&gt;黑客间最受尊敬的圣人是那些编写了大型的，功能强劲且满足了广泛需求的开源软件供他人使用的人。&lt;/p&gt;
&lt;p&gt;但是这里有段有趣的历史。虽然黑客一直敬重开源软件开发者，并且他们是我们社区的核心，但是直到1990年代中期，绝大部分黑客绝大多数时间是在闭源软件上工作的。在我1996年写本文的第一版的时候仍然如此。到1997年之后开源软件逐渐成为主流并改变了这一点。现在，“黑客社区”和“开源软件开发者”本质上是对同一文化和同一人群的两种表述——但值得记住的是，曾经不是如此。（想了解更多，请看“&lt;a href=&quot;#%E5%8E%86%E5%8F%B2%E8%AE%B0%E5%BD%95%EF%BC%9A%E9%BB%91%E5%AE%A2%E6%B4%BB%E5%8A%A8%EF%BC%8C%E5%BC%80%E6%BA%90%EF%BC%8C%E5%92%8C%E8%87%AA%E7%94%B1%E8%BD%AF%E4%BB%B6&quot;&gt;历史记录：黑客活动，开源，和自由软件&lt;/a&gt;”。）&lt;/p&gt;
&lt;h2&gt;帮助测试和调试开源软件&lt;/h2&gt;
&lt;p&gt;黑客也尊敬那些为开源软件进行测试和除错的人。在这个并非完美的世界上，我们不可避免地要花大多数的开发时间在调试阶段。 这就是为什么许多开源软件作者都会高度评价那些好的beta测试员 （知道如何清楚描述出错症状，很好地定位错误，能忍受快速发布中的bug，并且愿意使用一些简单的诊断工具），认为他们像红宝石一样珍贵。一个好的测试员可以使如恶梦的测试及除错工作变为一件值得经历的小烦恼。&lt;/p&gt;
&lt;p&gt;如果你是个新手，试着找一个你感兴趣的正在开发的程序，尝试做一个好的beta测试员。 你会自然地从帮着测试，进步到帮着抓bug，到最后帮着改程序。你会从中学到很多，并且与未来会帮到你的人结下友谊。&lt;/p&gt;
&lt;h2&gt;发布有用的信息&lt;/h2&gt;
&lt;p&gt;另一个好事是收集整理有用有趣的信息做成网页或文档如FAQ（常见问题）列表，且让他们容易获得。&lt;/p&gt;
&lt;p&gt;技术性FAQ的维护者往往如同开源软件作者一样很受人尊重。&lt;/p&gt;
&lt;h2&gt;帮助维护基础设施运转&lt;/h2&gt;
&lt;p&gt;黑客社区（也包括互联网发展）是靠自愿者组成的。有大量重要但平淡的事情需要处理——管理邮件列表，新闻组，维护大型软件归档库，开发RFC和其他技术标准等。&lt;/p&gt;
&lt;p&gt;做以上事情的人会得到很多人的尊敬，因为大家都知道这些事情需要大量的时间并且不如编写软件那么有趣。这类工作需要使命感。&lt;/p&gt;
&lt;h2&gt;为黑客社区服务&lt;/h2&gt;
&lt;p&gt;最后，你还可以为黑客社区做服务和宣扬（比如写一篇“如何成为黑客”的文章 :-)）。通常你不会做这些工作，直到你已经做了以上四种中的一样，并且取得了相当的知名度。&lt;/p&gt;
&lt;p&gt;黑客社区没有既定的领导者，但是有被人们尊重的英雄，长老级人物，史学家和发言人。当你在这个圈里足够久，你可能会成为他们中的一员。但请谨记，黑客对于自我夸耀的长老并不认同，因此不要尝试大举追求这种名誉。与其奋力追求，不如先摆正自己的位置，等它自己到你手中，那时需要做到谦虚和优雅。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;黑客与书呆子（Nerd）的关系&lt;/h1&gt;
&lt;p&gt;与流行的传说不同，黑客并不是书呆子。但这确实对你成为黑客有帮助，并且很多黑客确实是书呆子。做一个深居简出的人有助于使你更能集中精力做一些重要的事，例如思考和从事黑客活动。&lt;/p&gt;
&lt;p&gt;因此，许多黑客甚至以“极客（geek）”（译注：这个词原本在美国俚语中指“反常的人”）为名——这是一种宣布他们独立于普通社会的方式（此外，黑客也通常沉迷于其他一些事情例如科幻和战略游戏）。“书呆子”这个词通常在1990年代也被如此使用，那时候“书呆子”这个词略含贬义，而“极客”贬义更重。2000年以后这两个词的关系发生了转变，至少在美国流行文化上是如此，现在甚至在非技术专家中也出现了以标榜为极客为豪的情况。&lt;/p&gt;
&lt;p&gt;如果你能集中足够的精力做好黑客工作同时还能有正常的生活，这很好。现在做到这一点比我在1970年代还是新手的时候要容易的多；如今主流文化对技术怪人要友善的多。甚至有越来越多的人意识到黑客通常是很好的恋人和配偶侯选。&lt;/p&gt;
&lt;p&gt;如果你因为生活上的不如意而成为黑客，那也不错——至少你不用分神了。或许今后你能有一个不错的生活。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;风格&lt;/h1&gt;
&lt;p&gt;重申一下，作为一名黑客，你必须进入黑客式思维模式。当你不在电脑边的时候你仍然有很多有益的事情可做。它们不能替代真正的黑客活动（没有什么可以），但是很多黑客都这么干，并且感到它们与黑客精神存在某些根本的联系。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;学会流畅的使用母语写作。虽然认为程序员写不好文章的误解仍然很普遍，但是有数量令人惊讶的黑客（包括我所知造诣最高的那些）都是不错的写手。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;阅读科幻小说。参加科幻聚会（一个接触黑客和可能成为黑客的人的好方法）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;加入黑客空间（hackerspace）并做一些东西出来（另外一个接触黑客和可能成为黑客的人的好方法）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;习武。武术的精神修炼与黑客之道惊人的相似。黑客中比较常见的当然是亚洲的空手格斗技巧，例如跆拳道、空手道及其变种、中国功夫、合气道、柔术（译注：这里指的是日本传统武术，而不是柔身术或软功）。西方击剑和亚洲剑术也有相当的追随者。在持枪合法的地区，射击从1990年代起也越来越受欢迎。与黑客之道最契合的武术是那些强调精神修炼、放松意识，强调控制而不是单纯的蛮力的类型。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;学习一种冥想修炼。黑客中一直以来最受欢迎的是禅（很重要的是学禅并不要求你有特定的宗教信仰）（译注：这里指的是日本禅宗，而不是汉地佛教禅宗）。其他方式也可以，但是请注意一定选择那些不会要求你相信很疯狂东西的方式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修习音乐。学会鉴赏特别的音乐。学会玩某种乐器，或唱歌。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提高对双关语、文字游戏的鉴赏能力。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些事情，你已经在做的越多，你就越是天生做黑客的料。至于为什么偏偏是这些事情，原因并不完全清楚，但它们都涉及用到左右脑混合使用，这似乎是关键所在。黑客们既需要清晰的逻辑思维，有时又需要偏离逻辑跳出问题的表象。&lt;/p&gt;
&lt;p&gt;工作即娱乐，娱乐即工作。对于真正的黑客来说，“玩”，“工作”，“科学”和“艺术”之间没有界线，或者说，它们在一个高层面的创造性趣味里融合在一起。另外，不要对一点点技能就感到满足。虽然大多数黑客自称是程序员，他们实际上在其他相关的方面也很可能相当强悍——常见的是系统管理、页面设计和PC硬件故障处理。一个黑客，如果他是一名系统管理员，他很可能对脚本编程和页面设计也相当在行。黑客不会半途而废，如果他们要学习一门技能，他们会将其学好。&lt;/p&gt;
&lt;p&gt;最后，一些你 &lt;strong&gt;不应&lt;/strong&gt; 做的事。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;不要使用愚蠢，哗众取宠的ID或昵称。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要卷入Usenet（或其他任何地方）的骂战。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要自称为“赛博朋克（cyberpunk）”，也不要浪费时间跟他们打交道。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不要发送含有大量拼写和语法错误的email和帖子。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;做出以上事情只会招来嘲笑。黑客的记性都很好——你犯下的错误会令你将要经过多年才可以被其他黑客接受。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网名的问题值得深思。将身份隐藏在虚假的名字后是骇客、warez d00dz及其他低等生物幼稚愚蠢的行为特点。黑客不会做这些事；他们对他们所作的感到骄傲，而且乐于人们将作品与他们的 &lt;strong&gt;真名&lt;/strong&gt; 相联系。 因此, 若你现在用假名，放弃它。黑客社区里只会将用假名的人视为失败者。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;历史记录：黑客活动，开源，和自由软件&lt;/h1&gt;
&lt;p&gt;当我在1996年末刚开始写这篇文档的时候，很多情况跟现在是不同的。简单的介绍一下这个变化对于对开放源代码、自由软件和Linux跟黑客社区的关系感到困惑的人们可能会有所帮助。如果你对这些不感兴趣，可以直接跳过这里，前往FAQ和参考资料部分。&lt;/p&gt;
&lt;p&gt;我描述的黑客精神和黑客社区远早于1990年出现的Linux。我最初进入这个圈子大概是在1976年，其原因可以追溯到1960年代早期。但是在Linux出现前，多数黑客行为是在专有操作系统，或一些自主研发的实验性系统上，例如MIT的ITS，这个系统从未在实验室以外的地方使用过。虽然在早期（Linux出现之前）有过一些试图改变这种状况的努力，但是它们的影响都非常轻微，仅限于真正怀抱这样理想的人群，即使在当时的黑客社区这也是绝对少数，更不论对于世界范围内的通用软件群体的影响了。&lt;/p&gt;
&lt;p&gt;现在被称为“开放源代码”的行为，其历史与黑客社区一样久远，但是直到1985年这都只是一个无名的民间行为，没有相关的理论和宣言。这段史前时代在1985年结束，大黑客Richard Stallman（“RMS”）尝试给了它一个名字——“自由软件（Free Software）”。但是这个命名行为也是一个强制要求行为，他为“自由软件”标签加上了大多数已有的黑客社区从不接受的意识形态的包袱。“自由软件”的标签被黑客社区中的一部分重要人物（尤其是与BSD Unix有关联的社区）明确拒绝，并且其余的大部分人也在严肃并且持保留意见的情况下使用它（包括我本人）。&lt;/p&gt;
&lt;p&gt;除此之外，大约在1990年代中期以前，RMS想要在“自由软件”口号下定义和引领黑客社区。在Linux崛起之后，这受到了极大挑战。Linux为开放源代码开发活动提供了一个天然的环境。许多在现今被称为“开放源代码”条款下发布的项目纷纷从专有Unix向Linux迁移。围绕Linux的社区呈现爆炸式的增长，比在Linux出现前的黑客文化规模更大且更多样化。RMS想要将这些活动与他的“自由软件”运动关联起来，但是由于Linux社区爆炸式的多样性和该社区的创始人，Linus Torvalds的公开怀疑所阻碍。Torvalds仍然使用“自由软件”这一词汇，因为找不到更好的替代品，但他公开拒绝了RMS的意识形态观念。许多年轻黑客纷纷效仿。&lt;/p&gt;
&lt;p&gt;在1996年，当我第一次发布本文的时候，黑客社区正在围绕Linux和一些其他开放源代码的操作系统（尤其是BSD Unix的继承者）进行重组。我们中的许多人曾经在封闭源代码的操作系统上花费大量时间开发封闭源代码软件的集体记忆并没有因此褪色，但是这看起来已经是过去。黑客们将自己作为黑客的定义与开发源代码项目例如Linux和Apache越来越紧密的结合在一起。&lt;/p&gt;
&lt;p&gt;然而“开放源代码”这个词直到1998年初才出现。当它出现之后，多数黑客社区在6个月之内采用了它，除了与“自由软件”在意识形态层面绑定的极少数例外。自1998年起，尤其是2003年之后，“黑客”和“开放源代码（和自由软件）开发”越来越紧密相连。今天，几乎已经无法也没必要将它们区分开，并且这一点看起来在将来也不会改变。&lt;/p&gt;
&lt;p&gt;然而，曾经并不是这样，这一点值得我们记住。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;其他资源&lt;/h1&gt;
&lt;p&gt;Paul Graham写了一篇名为“&lt;a href=&quot;http://www.paulgraham.com/gh.html&quot;&gt;Great Hackers&lt;/a&gt;”和一篇名为“&lt;a href=&quot;http://www.paulgraham.com/college.html&quot;&gt;Undergraduation&lt;/a&gt;”的文章，有很多精妙的见解。&lt;/p&gt;
&lt;p&gt;年轻的黑客可能会发现&lt;a href=&quot;http://catb.org/~esr/faqs/things-every-hacker-once-knew&quot;&gt;Things Every Hacker Once Knew&lt;/a&gt;有趣并且有用。&lt;/p&gt;
&lt;p&gt;有一篇名为&lt;a href=&quot;http://samizdat.mines.edu/howto/HowToBeAProgrammer.html&quot;&gt;How To Be A Programmer&lt;/a&gt;的文章，对如何成为程序员做了详尽的说明。它的价值不仅限于代码及其相关能力上，对于如何在一个程序员团队中工作也有建设性价值。&lt;/p&gt;
&lt;p&gt;我写过一篇&lt;a href=&quot;http://catb.org/~esr/writings/hacker-history/hacker-history.html&quot;&gt;A Brief History Of Hackerdom&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;我写过一篇名为“&lt;a href=&quot;http://catb.org/~esr/writings/cathedral-bazaar/index.html&quot;&gt;大教堂与市集（The Cathedral and the Bazaar）&lt;/a&gt;”的文章，在文中解释了Linux和开源社区是如何运作的。在它的续集“&lt;a href=&quot;http://catb.org/~esr/writings/homesteading/&quot;&gt;开拓智域（Homesteading the Noosphere）&lt;/a&gt;”中，我进一步深入探讨了这个问题。&lt;/p&gt;
&lt;p&gt;Rick Moen写了一篇很棒的关于&lt;a href=&quot;http://linuxmafia.com/faq/Linux_PR/newlug.html&quot;&gt;如何运营一个Linux用户组&lt;/a&gt;的文章。&lt;/p&gt;
&lt;p&gt;Rick Moen和我共著了一篇关于&lt;a href=&quot;https://gist.github.com/zer4tul/95ffaa741c836dc6ab3b&quot;&gt;提问的智慧&lt;/a&gt;的文章。它将使你更容易获取到帮助。&lt;/p&gt;
&lt;p&gt;如果需要个人电脑、Unix 和互联网如何工作的基础知识，参阅&lt;a href=&quot;http://en.tldp.org/HOWTO/Unix-and-Internet-Fundamentals-HOWTO/&quot;&gt;Unix 和互联网工作的基本原理&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当你发布软件或补丁时，试着按&lt;a href=&quot;http://en.tldp.org/HOWTO/Software-Release-Practice-HOWTO/index.html&quot;&gt;软件发布实践&lt;/a&gt;操作。&lt;/p&gt;
&lt;p&gt;如果你对禅诗感兴趣，你可能会喜欢&lt;a href=&quot;http://catb.org/~esr//writings/unix-koans&quot;&gt;Rootless Root: The Unix Koans of Master Foo&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&amp;lt;p style=&quot;text-align:center;&quot;&amp;gt; &amp;lt;img  src=&quot;/images/glider.png&quot;&amp;gt; &amp;lt;/p&amp;gt;&lt;/p&gt;
&lt;h1&gt;常见问题&lt;/h1&gt;
&lt;p&gt;Q: &lt;a href=&quot;#hacker_already&quot;&gt;如何证明我已经是一名黑客了？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#teach_hack&quot;&gt;你能教我做黑客吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#getting_started&quot;&gt;我该如何开始？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#when_start&quot;&gt;我该什么时候开始学？现在会不会太迟了？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#how_long&quot;&gt;学会黑客之道要多长时间？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#closed_lang&quot;&gt;Visual Basic是一门好的入门语言吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#I_want_to_crack_and_Im_an_idiot&quot;&gt;你能教我“黑”掉一个网站，或者教我怎么黑它吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#passwords&quot;&gt;我怎么样才能得到别人帐号的密码？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#crackmail&quot;&gt;我如何入侵/查看/监视别人的email？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#crackop&quot;&gt;我如何才能盗取IRC的频道管理员权限？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#anti_crack&quot;&gt;我被人入侵了。你能帮我避免以后再被攻击吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#windows_grief&quot;&gt;我的Windows软件出现问题了。你能帮我吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#real_hackers&quot;&gt;我在哪里可以找到能与之交流的真正的黑客？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#books&quot;&gt;你能推荐一些有关黑客的好书吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;mathematics&quot;&gt;成为一名黑客我需要擅长数学吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#language_first&quot;&gt;我该从哪种语言开始学？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#hardware&quot;&gt;我需要什么样的机器配置？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#started2&quot;&gt;我想做贡献。你能帮我挑选一个问题来处理吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#MS_hater&quot;&gt;我得因此憎恨和反对Microsoft吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#no_living&quot;&gt;但开放源代码软件不会使程序员丢饭碗吗？&lt;/a&gt;&amp;lt;br&amp;gt;
Q: &lt;a href=&quot;#problems&quot;&gt;哪里有免费的Unix？&lt;/a&gt;&amp;lt;br&amp;gt;&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;hacker_already&quot;&amp;gt;如何证明我已经是一名黑客了？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 问自己以下三个问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;* 你能够流畅的编写代码吗？
* 你是否与黑客社区的目标和价值观产生共鸣？
* 是否有知名黑客称你为黑客？
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你对三个问题的回答都是肯定的，你就已经是一名黑客。哪怕只有一个回答是否定的也不行。&lt;/p&gt;
&lt;p&gt;第一个问题是关于技能的。如果你具备了前文提到的基本技能，就应该没问题。如果你已经有相当数量的代码被开源项目所接受，可以跳过这个问题。&lt;/p&gt;
&lt;p&gt;第二个问题是关于精神的。如果前面的&lt;a href=&quot;#%E9%BB%91%E5%AE%A2%E7%9A%84%E7%B2%BE%E7%A5%9E&quot;&gt;五条黑客的精神&lt;/a&gt;明显比其他地方的描述更贴近你的真实生活，你就已经通过了一半。这是内在的一半，外在的一半是你对黑客社区长期项目的贡献程度。&lt;/p&gt;
&lt;p&gt;这里有一个不完整但具有指示性的项目列表：Linux的改进和发展是否有你的贡献？你是否对软件自由充满激情？你是否反对垄断？你是否为了让计算机成为这个世界更丰富多彩、更人性化的工具而努力？&lt;/p&gt;
&lt;p&gt;请注意。黑客社区有一些特定的，主要是防御性的政治倾向——其中两条是维护言论自由和抵御可能使开放源代码非法的“知识产权”。有一些长期项目是公民自由组织，例如电子前哨基金会（EFF），外在的态度包括支持他们。除此之外，大多数企图将黑客精神系统化为一个具体的政治程序的黑客都值得怀疑。我们曾经为此付出过代价，并了解到这些想法通常会导致分裂并且令人心烦意乱。如果有人想要以黑客精神的名义来招揽你，那是他们搞错了重点。最好的回应恐怕是“闭嘴，给他们看代码（Shut up and show them the code）。”&lt;/p&gt;
&lt;p&gt;第三个问题是递归的。我在“&lt;a href=&quot;#%E4%BB%80%E4%B9%88%E6%98%AF%E9%BB%91%E5%AE%A2&quot;&gt;什么是黑客&lt;/a&gt;”中提到过，成为一名黑客，就是成为一个具有分享特点的文化社群的一员。很久之前，黑客相比现在是一个松散的，不自知的群体。但是近30年来，由于互联网使得黑客文化的核心更易发展和维护，人际网络方面取得了长足进步。这种改变最简单的代表就是，在这个世纪，我们有了自己的T恤。&lt;/p&gt;
&lt;p&gt;社会学家在研究类似黑客社区这样的被统称为“无形学院（invisible colleges）”的人际网络时注意到，这类网络通常都有门卫——具有社区授权的核心成员会审核新人的进入申请。由于黑客社区是“无形学院”中比较松散和非正式的一种，门卫的身份也是非正式的。但是所有黑客天生就知道并非每个黑客都是门卫。在取得门卫的头衔前需要具备特定的资历和成就。这很难度量，但是每个黑客在看到它的时候就能知道。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;teach_hack&quot;&amp;gt;你能教我做黑客吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 自从第一次发布这份文档，我每周都会收到一些请求，（通常一天几封）要我“教会他们做黑客”。遗憾的是，我没有时间和精力来做这个；我自己的黑客项目，及我作为一个开放源代码倡导者 的四处奔波已经占用了我110%的时间。&lt;/p&gt;
&lt;p&gt;即便我想教你，黑客也依然基本上是一项自行修炼的的态度和技术。当真正的黑客想帮助你的时候，如果你乞求他们一汤匙一汤匙“喂”你的话，你会发现他们不会尊重你。&lt;/p&gt;
&lt;p&gt;先去学一些东西。显示你在尝试，你能靠自己去学习。然后再去向你遇到的黑客请教特殊的问题。&lt;/p&gt;
&lt;p&gt;如果你发E-mail给一位黑客寻求他的帮助，有两件首要记住的事情。第一，写出来的文字显得懒且粗心的人通常非常懒于思考且非常马大哈，不能成为好黑客——因此注意拼写正确，使用正确的语法及发音，否则你可能会无人理睬。 第二，不要试图要求回复到与你的发信地址不同的另一个帐号。这样做的人一般是使用盗用帐号，不会有人有兴趣为虎作伥帮助窃贼的。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;getting_started&quot;&amp;gt;我该如何开始&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 对你而言最佳的入门方式也许是去参加LUG（Linux用户组）的聚会。 你可以在 &lt;a href=&quot;http://www.tldp.org/links/index.html&quot;&gt;LDP的综合Linux信息页面&lt;/a&gt;上找到类似的组织；也许有一个在你附近的，而且非常有可能与一所大学或学校挂钩。如果你提出要求，LUG 成员兴许会给你一套 Linux，当然此后会帮你安装并带你入门。&lt;/p&gt;
&lt;p&gt;下一步（如果你在附近找不到LUG的话，这是第一步）找一个你感兴趣的开放源代码项目。读它的代码，并且检查它的bug。学着做贡献，并从此入门。&lt;/p&gt;
&lt;p&gt;入门的唯一方式是提升你的技能。如果你还想问我关于如何开始的私人建议，我还是会给你相同的答案，因为没有捷径。我还会在心里认为你可能是个失败者——因为你没有耐性读完这个 FAQ，并且也没有足够的智商从文中理解到入门的唯一途径就是提升你的技能。你没救了。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;when_start&quot;&amp;gt;我该什么时候开始学？现在会不会太迟了？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 你有动力学的时候就可以。多数人是在15到20岁之间开始感兴趣的，但据我所知也有在这个年龄区间之外的例外。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;how_long&quot;&amp;gt;学会黑客之道要多长时间？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 这取决于你的聪明程度和努力程度。多数人如果足够专注的话，能在18个月到2年之间学会一套令人尊敬的技能。但是，不要以为这就结束了。在黑客领域（在其他很多领域也一样），需要10年时间精湛技艺。如果你是一个真正的黑客，你要用你的余生来学习和完善你的技术。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;closed_lang&quot;&amp;gt;Visual Basic是一门好的入门语言吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 你问这个问题，那通常意味着你想在Microsoft Windows下从事黑客活动。这本身就不是个好主意。我将在Windows下学习黑客技巧比喻为戴着脚镣学跳舞，这不是开玩笑。别这么做。Windows很糟糕，而且它从来没有变好一点。&lt;/p&gt;
&lt;p&gt;Visual Basic有一个很重要的问题，主要是源于它不可移植。虽然已经有Visual Basic的开源实现，但ECMA的可执行标准只覆盖了其编程接口的很小一部分。在Windows中，大多数函数库是由单一供应商（Microsoft）专有的。如果你不能非常小心的选择你所使用的特性（比任何新手所能做到的都更小心），你最终很可能被束缚在Microsoft决定支持的那些平台上。如果你从Unix系统开始，有更好的编程语言和更好的函数库可用。例如Python。&lt;/p&gt;
&lt;p&gt;此外，如同其他 Basic 语言一样，Visual Basic是一种设计糟糕的语言，它会教给你坏的编程习惯。别让我详细列举和解释它们，这够写一本书了。找一门设计优良的编程语言来学。&lt;/p&gt;
&lt;p&gt;坏习惯之一就是依赖单一厂商提供的函数库、控件和开发工具。通常，一门不能支持至少Linux或一种BSD，或其他第三方操作系统的语言，都不适合应付黑客工作。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;I_want_to_crack_and_Im_an_idiot&quot;&amp;gt;你能帮我“黑”掉一个网站，或者教我怎么黑它吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: No。任何读完这份FAQ后还问这个问题的人都是无药可救的蠢材，即使有时间我也不会理睬。任何发给我的此类e-mail都会被忽略掉或被痛骂一顿。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;passwords&quot;&amp;gt;我怎么样才能得到别人帐号的密码？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 这是破坏行为。滚开，白痴。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;crackmail&quot;&amp;gt;我如何入侵/查看/监视别人的email？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 这是破坏行为。从我面前消失，混蛋。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;crackop&quot;&amp;gt;我如何才能盗取IRC的频道管理员权限？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 这是破坏行为。去死，蠢货。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;anti_crack&quot;&amp;gt;我被人入侵了。你能帮我避免以后再被攻击吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 不能。每次问我这个问题的都是些运行Microsoft Windows的菜鸟。不可能有效保护Windows系统免受破坏行为攻击。代码和架构上的大量缺陷使保护Windows的努力犹如隔靴搔痒。唯一可靠的预防是换到Linux或者其他设计得至少足够安全的系统上。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;windows_grief&quot;&amp;gt;我的Windows软件出现问题了。你能帮我吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 是的。进入DOS模式，然后输入“format c:”。你遇到的问题将在几分钟内消失。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;real_hackers&quot;&amp;gt;我在哪里可以找到能与之交流的真正的黑客？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 最佳办法是在你附近找一个Unix或Linux的用户组，参加他们的聚会（你可以在ibiblio的&lt;a href=&quot;http://www.tldp.org/&quot;&gt;LDP&lt;/a&gt;站点找到一些指向用户组的链接）。&lt;/p&gt;
&lt;p&gt;我过去曾说过在IRC上找不到真正的黑客，但我发觉现在情况有所改变。显然一些真正的黑客的社区像GIMP及Perl，也有IRC频道了。）&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;books&quot;&amp;gt;你能推荐一些有关黑客的好书吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 我维护着一份&lt;a href=&quot;http://en.tldp.org/HOWTO/Reading-List-HOWTO/index.html&quot;&gt;Linux Reading List HOWTO&lt;/a&gt;，也许会对你有用。&lt;a href=&quot;http://catb.org/~esr/faqs/loginataka.html&quot;&gt;Loginataka&lt;/a&gt;也很有意思。&lt;/p&gt;
&lt;p&gt;关于Python的介绍，请访问Python官方站点上的&lt;a href=&quot;http://docs.python.org/tutorial/index.html&quot;&gt;入门资料&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;mathematics&quot;&amp;gt;成为一名黑客我需要擅长数学吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 不。黑客倒很少使用常规的数学或算术。
尤其是你不会用到三角学、微积分或数学分析（在特定领域，这些学科很有用，例如3D电脑图像）。一些有限数学（包括布尔代数，集合论，组合数学，图论）的背景知识会有帮助。了解一些系统的逻辑和布尔代数是有好处的。一些基础的离散数学（包括有限集合论、组合数学和图论）会有帮助。&lt;/p&gt;
&lt;p&gt;更重要的是：你需要能够像数学家一样进行逻辑性地思考和进行缜密的推理。在这一点上绝大部分数学理论帮不了你，你需要有能够应付数学的修养和智力。如果你不够聪明，你成为黑客的希望很渺茫。如果你的修养不够，最好培养起来。&lt;/p&gt;
&lt;p&gt;我认为一个好的了解你当前状况的办法是，找一本Rymond Smullyan的书 &lt;em&gt;What Is The Name Of This Book?&lt;/em&gt;。Smullyan那些有趣的逻辑题很符合黑客精神。如果你能解答它们，这是个很好的信号。如果你能享受解题的过程那就更好了。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;language_first&quot;&amp;gt;我该从哪种语言开始学？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: XHTML（最新的HTML方言）——如果你还不懂的话。市面上有一大堆的封面精美，宣传得天花乱坠的 糟糕的HTML书籍，不幸的是很少有好的。我最喜欢的是&lt;a href=&quot;http://www.oreilly.com/catalog/html5/&quot;&gt;HTML: The Definitive Guide&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;但HTML不完全是一种编程语言。当你准备开始编程时，我推荐从Python起步。 你会听到一大群人推荐Perl，并且Perl依然比Python流行得多，但是难学得多且（以我之见）设计得不是很好。&lt;/p&gt;
&lt;p&gt;C确实重要，但它要比Python或Perl难多了。不要尝试先学C。&lt;/p&gt;
&lt;p&gt;Windows用户不要满足于Visual Basic。它会教给你坏习惯，而且它不可以移植，只能在Windows下运行。避免它。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;hardware&quot;&amp;gt;我需要什么样的机器配置？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 过去个人电脑计算能力相当不够且内存小，给黑客的学习过程设置了人为的障碍。不过从1990年代以后就不是这样了，任何配置比一台Intel 486DX50好的机器都有足够的能力进行开发工作，跑Xorg，及进行Internet通讯，同时现在能买到的最小的磁盘都已经绰绰有余。&lt;/p&gt;
&lt;p&gt;选择用来学习的机器时重要的一点是注意配件是否是Linux兼容的（或BSD兼容，如果你选择学 BSD）。同刚才提到的一样，大多数现在的机器都是符合的；唯一的值得注意的地方在于 调制解调器和打印机；有些具备为Windows设计的配件的机器不会在Linux下工作。&lt;/p&gt;
&lt;p&gt;关于硬件兼容性有一个FAQ；最新版本在&lt;a href=&quot;http://en.tldp.org/HOWTO/Hardware-HOWTO/index.html&quot;&gt;这里&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;started2&quot;&amp;gt;我想做贡献。你能帮我挑选一个问题来处理吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 不行。因为我不知道你擅长什么，也不知道你对什么感兴趣。你需要做到自我驱动，否则无法进步。这也是为什么让别人帮你挑选方向几乎都不会有用。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;MS_hater&quot;&amp;gt;我得因此憎恨和反对Microsoft吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 不，你不必如此。不是因为Microsoft不令人讨厌，而是因为黑客文化早在Microsoft出现之前就存在了，且将在Microsoft成为历史后依然存在。你耗费在憎恨Microsoft的任何力气不如花在热爱你的技术上。写好的代码——那会相当有效地打击Microsoft又不会让你得到恶报。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;no_living&quot;&amp;gt;但开放源代码软件不会使程序员丢饭碗吗？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 看起来不太可能——目前为止，开放源代码软件产业似乎创造了更多的就业机会而不是减少就业机会。如果写一个程序比起不写来是纯经济收益的话，那么在写完后，程序员应该得到报酬不管程序是否是开放源代码。并且，无论写出多么“免费自由”的软件，都存在更多对新的，定制的软件的需求。我有这方面更多的论述，放在&lt;a href=&quot;http://www.opensource.org/&quot;&gt;Open Source&lt;/a&gt;网站资料中。&lt;/p&gt;
&lt;p&gt;Q: &amp;lt;a name=&quot;problems&quot;&amp;gt;哪里有免费的Unix？&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;A: 如果你的机器上还没有安装Unix，我在本文的其他地方已经指出了从哪里可以获取到常用的免费Unix。作为一名黑客，你需要自立自强，以及自学能力。现在开始吧……&lt;/p&gt;
</content:encoded></item><item><title>提问的智慧</title><link>https://sakimidare.top/posts/how-to-ask-questions-the-smart-way/</link><guid isPermaLink="true">https://sakimidare.top/posts/how-to-ask-questions-the-smart-way/</guid><description>问问题之前，看看这篇文章吧，求求了</description><pubDate>Tue, 26 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;How To Ask Questions The Smart Way&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Copyright © 2001,2006,2014 Eric S. Raymond, Rick Moen&lt;/p&gt;
&lt;p&gt;本指南英文版版权为 Eric S. Raymond, Rick Moen 所有。&lt;/p&gt;
&lt;p&gt;原文网址：&lt;a href=&quot;http://www.catb.org/~esr/faqs/smart-questions.html&quot;&gt;http://www.catb.org/~esr/faqs/smart-questions.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Copyleft 2001 by D.H.Grand(nOBODY/Ginux), 2010 by Gasolin, 2015 by Ryan Wu&lt;/p&gt;
&lt;p&gt;本中文指南是基于原文 3.10 版以及 2010 年由 &lt;a href=&quot;https://github.com/gasolin&quot;&gt;Gasolin&lt;/a&gt; 所翻译版本的最新翻译；&lt;/p&gt;
&lt;p&gt;请参阅简体中文原文件：&lt;/p&gt;
&lt;p&gt;:::github{repo=&quot;ryanhanwu/How-To-Ask-Questions-The-Smart-Way&quot;}
:::&lt;/p&gt;
&lt;h1&gt;声明&lt;/h1&gt;
&lt;p&gt;许多项目在他们网站的帮助文档中链接了本指南。这很好，这正是我们想要的用途。但如果你是该项目管理员并试图创建指向本指南的超链接，请在超链接附近的显著位置注明：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本指南不提供此项目的实际支持服务！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们已经深刻领教到缺少上述声明所带来的痛苦：我们将不停地被那些认为发布这本指南就意味着有责任解决世上所有技术问题的傻瓜苦苦纠缠。&lt;/p&gt;
&lt;p&gt;如果你因寻求某些帮助而阅读本指南，并在离开时还觉得可以从本文作者这里得到直接帮助，那你就是我们之前说的那些傻瓜之一。别问我们问题，我们只会忽略你。我们在这本指南中想教你如何从那些真正懂得你所遇到的软件或硬件问题的人处取得协助，而 99% 的情况下那不会是我们。除非你确定本指南的作者之一刚好是你所遇到的问题领域的专家，否则请不要打扰我们，这样大家都会开心一点。&lt;/p&gt;
&lt;h1&gt;简介&lt;/h1&gt;
&lt;p&gt;在&lt;a href=&quot;http://www.catb.org/~esr/faqs/hacker-howto.html&quot;&gt;黑客&lt;/a&gt;的世界里，你所提技术问题的解答的好坏, 很大程度上取决于你提问的方式与此问题的难度。本指南将教你如何正确地提问以获得你满意的答案。&lt;/p&gt;
&lt;p&gt;现在开源（Open Source）软件已经相当盛行，您通常可以从其他更有经验的用户那里获得与黑客一样好的答案，这是件&lt;strong&gt;好事&lt;/strong&gt;；和黑客相比，用户们往往对那些新手常遇到的问题更宽容一些。尽管如此，以我们在此推荐的方式对待这些有经验的用户通常也是从他们那里获得有用答案的最有效方式。&lt;/p&gt;
&lt;p&gt;首先你应该明白，黑客们喜爱有挑战性的问题，或者能激发他们思维的好问题。如果我们并非如此，那我们也不会成为你想询问的对象。如果你给了我们一个值得反复咀嚼玩味的好问题，我们自会对你感激不尽。好问题是激励，是厚礼。好问题可以提高我们的理解力，而且通常会暴露我们以前从没意识到或者思考过的问题。对黑客而言，“好问题！”是诚挚的大力称赞。&lt;/p&gt;
&lt;p&gt;尽管如此，黑客们有着蔑视或傲慢面对简单问题的坏名声，这有时让我们看起来对新手、无知者似乎较有敌意，但其实不是那样的。&lt;/p&gt;
&lt;p&gt;我们不讳言我们对那些不愿思考、或者在发问前不做他们该做的事的人的蔑视。那些人是时间杀手 —— 他们只想索取，从不付出，消耗我们可用在更有趣的问题或更值得回答的人身上的时间。我们称这样的人为 &lt;code&gt;失败者（loser）&lt;/code&gt; （由于历史原因，我们有时把它拼作 &lt;code&gt;lusers&lt;/code&gt;）。&lt;/p&gt;
&lt;p&gt;我们意识到许多人只是想使用我们写的软件，他们对学习技术细节没有兴趣。对大多数人而言，电脑只是种工具，是种达到目的的手段而已。他们有自己的生活并且有更要紧的事要做。我们认可这点，也从不指望每个人都对这些让我们着迷的技术问题感兴趣。尽管如此，我们只为那些真正有兴趣并愿意积极参与问题解决的人调整回答问题的风格。这点不会变，也不该变：否则，我们就是在最擅长的事情上降低效率。&lt;/p&gt;
&lt;p&gt;我们（在很大程度上）是自愿的，从繁忙的生活中抽出时间来解答疑惑，而且时常被提问淹没。所以我们无情地滤掉一些话题，特别是拋弃那些看起来像失败者的家伙，以便更高效地利用时间来回答&lt;code&gt;赢家（winner）&lt;/code&gt;的问题。&lt;/p&gt;
&lt;p&gt;如果你厌恶我们的态度，高高在上，或过于傲慢，不妨也设身处地想想。我们并没有要求你向我们屈服 —— 事实上，我们大多数人非常乐意与你平等地交流，只要你付出小小努力来满足基本要求，我们就会欢迎你加入我们的文化。但让我们帮助那些不愿意帮助自己的人是没有效率的。无知没有关系，但装白痴就是不行。&lt;/p&gt;
&lt;p&gt;所以，你不必在技术上很在行才能吸引我们的注意，但你必须表现出能引导你变得在行的特质 —— 机敏、有想法、善于观察、乐于主动参与解决问题。如果你做不到这些使你与众不同的事情，我们建议你花点钱找家商业公司签个技术支持服务合同，而不是要求黑客个人无偿地帮助你。&lt;/p&gt;
&lt;p&gt;如果你决定向我们求助，当然你也不希望被视为失败者，更不愿成为失败者中的一员。能立刻得到快速并有效答案的最好方法，就是像赢家那样提问 —— 聪明、自信、有解决问题的思路，只是偶尔在特定的问题上需要获得一点帮助。&lt;/p&gt;
&lt;p&gt;（欢迎对本指南提出改进意见。你可以把你的建议发送至 &lt;a href=&quot;esr@thyrsus.com&quot;&gt;esr@thyrsus.com&lt;/a&gt; 或 &lt;a href=&quot;respond-auto@linuxmafia.com&quot;&gt;respond-auto@linuxmafia.com&lt;/a&gt;。然而请注意，本文并非&lt;a href=&quot;http://www.ietf.org/rfc/rfc1855.txt&quot;&gt;网络礼节&lt;/a&gt;的通用指南，而我们通常会拒绝无助于在技术论坛得到有用答案的建议）。&lt;/p&gt;
&lt;h1&gt;在提问之前&lt;/h1&gt;
&lt;p&gt;在你准备要通过电子邮件、新闻群组或者聊天室提出技术问题前，请先做到以下事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;尝试在你准备提问的论坛的旧文章中搜索答案。&lt;/li&gt;
&lt;li&gt;尝试上网搜索以找到答案。&lt;/li&gt;
&lt;li&gt;尝试阅读手册以找到答案。&lt;/li&gt;
&lt;li&gt;尝试阅读常见问题文件（FAQ）以找到答案。&lt;/li&gt;
&lt;li&gt;尝试自己检查或试验以找到答案。&lt;/li&gt;
&lt;li&gt;向你身边的强者朋友打听以找到答案。&lt;/li&gt;
&lt;li&gt;如果你是程序开发者，请尝试阅读源代码以找到答案。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;谨慎使用 LLM 获取答案 (本站编者注)&lt;/em&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;lt;a id=&quot;LLM&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;p&gt;:::warning
&lt;a href=&quot;https://en.wikipedia.org/wiki/Large_Language_Model&quot;&gt;LLM&lt;/a&gt;，大型语言模型（也就是 OpenAI 的 ChatGPT，Anthropic 的 Claude，Google 的 Gemini，深度求索的 DeepSeek 等 “AI”），看似是人类可以向 AI 询问任何问题，AI 就会给出看着非常可信的答案。有人可能会觉得如获至宝，看到有人问问题就把问题丢给它们问，再把回答随便贴上去。&lt;/p&gt;
&lt;p&gt;但是，现阶段的通用大型语言模型，即便是在有联网工具能力的情况下（比如 ChatGPT 的搜索模式），也只能基本确保它们组出的是语法语气没有问题的句子，而不是事实正确的句子。即便是现在推理用的大模型，也并没有对现实的认知能力，自然没有其他社区成员的经验，询问它们是不大可能获得诸如“你电脑在更新的时候大写锁定键忽然闪灯，是因为闭源 NVIDIA 驱动和内核互作导致更新时内核崩溃，根据你的显卡型号，你应该换用 nvidia-open 这个包”之类的详细结果的。&lt;/p&gt;
&lt;p&gt;好吧，LLM 似乎确实不适合询问莫名其妙的疑难杂症——那如果是让它帮我写一个特定用途的小工具呢？不是说它们很擅长写电脑程序吗？&lt;/p&gt;
&lt;p&gt;在你准备问出更多问题之前，再次强调一遍：现阶段的 AI 没有对现实的认知能力，它不能保证自己写的符合你的要求，甚至可能因为阴差阳错写出有害的东西出来（虽然更多时候是前者）。就算是用所谓的推理模型也没有用，因为 AI 的推理过程也&lt;a href=&quot;https://www.anthropic.com/research/reasoning-models-dont-say-think&quot;&gt;照样会说谎&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;因此，总结一下：如果一段文字看着是 AI 生成的，或者你打算向 AI 问问题，请先认为你看到的内容一个字都不能信。也请不要把“它说的对不对啊”的工作推给别人，因为比起对 LLM 缝缝补补，人类自己早就能把问题解决掉了。
:::&lt;/p&gt;
&lt;p&gt;:::note
&lt;em&gt;以上段落摘自&lt;a href=&quot;https://wiki.archlinuxcn.org/wiki/%E5%BB%BA%E8%AE%AE%E9%98%85%E8%AF%BB/%E7%BB%99%E6%96%B0%E7%94%A8%E6%88%B7%E7%9A%84%E5%85%B3%E4%BA%8E%E5%A6%82%E4%BD%95%E4%B8%8D%E5%8E%BB%E5%BC%84%E5%9D%8F_Arch_Linux_%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%BB%BA%E8%AE%AE#%E8%B0%A8%E6%85%8E%E5%AF%B9%E5%BE%85_LLM_%E7%BB%99%E5%87%BA%E7%9A%84%E5%86%85%E5%AE%B9&quot;&gt;给新用户的关于如何不去弄坏 Arch Linux 系统的建议&lt;/a&gt;。&lt;/em&gt;
:::&lt;/p&gt;
&lt;p&gt;当你提出问题的时候，请先表明你已经做了上述的努力；这将有助于树立你并不是一个不劳而获且浪费别人的时间的提问者。如果你能一并表达在做了上述努力的过程中所&lt;strong&gt;学到&lt;/strong&gt;的东西会更好，因为我们更乐于回答那些表现出能从答案中学习的人的问题。&lt;/p&gt;
&lt;p&gt;运用某些策略，比如先用 Google 搜索你所遇到的各种错误信息（搜索 &lt;a href=&quot;http://groups.google.com/&quot;&gt;Google 论坛&lt;/a&gt;和网页），这样很可能直接就找到了能解决问题的文件或邮件列表线索。即使没有结果，在邮件列表或新闻组寻求帮助时加上一句 &lt;code&gt;我在 Google 中搜过下列句子但没有找到什么有用的东西&lt;/code&gt; 也是件好事，即使它只是表明了搜索引擎不能提供哪些帮助。这么做（加上搜索过的字串）也让遇到相似问题的其他人能被搜索引擎引导到你的提问来。&lt;/p&gt;
&lt;p&gt;别着急，不要指望几秒钟的 Google 搜索就能解决一个复杂的问题。在向专家求助之前，再阅读一下常见问题文件（FAQ）、放轻松、坐得舒服一些，再花点时间思考一下这个问题。相信我们，他们能从你的提问看出你做了多少阅读与思考，如果你是有备而来，将更有可能得到解答。不要将所有问题一股脑拋出，只因你的第一次搜索没有找到答案（或者找到太多答案）。&lt;/p&gt;
&lt;p&gt;准备好你的问题，再将问题仔细地思考过一遍，因为草率的发问只能得到草率的回答，或者根本得不到任何答案。越是能表现出在寻求帮助前你为解决问题所付出的努力，你越有可能得到实质性的帮助。&lt;/p&gt;
&lt;p&gt;小心别问错了问题。如果你的问题基于错误的假设，某个普通黑客（J. Random Hacker）多半会一边在心里想着&lt;code&gt;蠢问题…&lt;/code&gt;，一边用无意义的字面解释来答复你，希望着你会从问题的回答（而非你想得到的答案）中汲取教训。&lt;/p&gt;
&lt;p&gt;绝不要自以为&lt;strong&gt;够格&lt;/strong&gt;得到答案，你没有；你并没有。毕竟你没有为这种服务支付任何报酬。你将会是自己去&lt;strong&gt;挣到&lt;/strong&gt;一个答案，靠提出有内涵的、有趣的、有思维激励作用的问题 —— 一个有潜力能贡献社区经验的问题，而不仅仅是被动地从他人处索取知识。&lt;/p&gt;
&lt;p&gt;另一方面，表明你愿意在找答案的过程中做点什么是一个非常好的开端。&lt;code&gt;谁能给点提示？&lt;/code&gt;、&lt;code&gt;我的这个例子里缺了什么？&lt;/code&gt;以及&lt;code&gt;我应该检查什么地方&lt;/code&gt;比&lt;code&gt;请把我需要的确切的过程贴出来&lt;/code&gt;更容易得到答复。因为你表现出只要有人能指个正确方向，你就有完成它的能力和决心。&lt;/p&gt;
&lt;h1&gt;当你提问时&lt;/h1&gt;
&lt;h2&gt;慎选提问的论坛&lt;/h2&gt;
&lt;p&gt;小心选择你要提问的场合。如果你做了下述的事情，你很可能被忽略掉或者被看作失败者：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在与主题不合的论坛上贴出你的问题。&lt;/li&gt;
&lt;li&gt;在探讨进阶技术问题的论坛张贴非常初级的问题；反之亦然。&lt;/li&gt;
&lt;li&gt;在太多的不同新闻群组上重复转贴同样的问题（cross-post）。&lt;/li&gt;
&lt;li&gt;向既非熟人也没有义务解决你问题的人发送私人电邮。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;黑客会剔除掉那些搞错场合的问题，以保护他们沟通的渠道不被无关的东西淹没。你不会想让这种事发生在自己身上的。&lt;/p&gt;
&lt;p&gt;因此，第一步是找到对的论坛。再说一次，Google 和其它搜索引擎还是你的朋友，用它们来找到与你遭遇到困难的软硬件问题最相关的网站。通常那儿都有常见问题（FAQ）、邮件列表及相关说明文件的链接。如果你的努力（包括&lt;strong&gt;阅读&lt;/strong&gt; FAQ）都没有结果，网站上也许还有报告 Bug（Bug-reporting）的流程或链接，如果是这样，链过去看看。&lt;/p&gt;
&lt;p&gt;向陌生的人或论坛发送邮件最可能是风险最大的事情。举例来说，别假设一个提供丰富内容的网页的作者会想充当你的免费顾问。不要对你的问题是否会受到欢迎做太乐观的估计 —— 如果你不确定，那就向别处发送，或者压根别发。&lt;/p&gt;
&lt;p&gt;在选择论坛、新闻群组或邮件列表时，别太相信它的名字，先看看 FAQ 或者许可书以弄清楚你的问题是否切题。发文前先翻翻已有的话题，这样可以让你感受一下那里的文化。事实上，事先在新闻组或邮件列表的历史记录中搜索与你问题相关的关键词是个极好的主意，也许这样就找到答案了。即使没有，也能帮助你归纳出更好的问题。&lt;/p&gt;
&lt;p&gt;别像机关枪似的一次“扫射”所有的帮助渠道，这就像大喊大叫一样会使人不快。要一个一个地来。&lt;/p&gt;
&lt;p&gt;搞清楚你的主题！最典型的错误之一是在某种致力于跨平台可移植的语言、套件或工具的论坛中提关于 Unix 或 Windows 操作系统程序界面的问题。如果你不明白为什么这是大错，最好在搞清楚这之间差异之前什么也别问。&lt;/p&gt;
&lt;p&gt;一般来说，在仔细挑选的公共论坛中提问，会比在私有论坛中提同样的问题更容易得到有用的回答。有几个理由可以支持这点，一是看潜在的回复者有多少，二是看观众有多少。黑客较愿意回答那些能帮助到许多人的问题。&lt;/p&gt;
&lt;p&gt;可以理解的是，老练的黑客和一些热门软件的作者正在接受过多的错发信息。就像那根最后压垮骆驼背的稻草一样，你的加入也有可能使情况走向极端 —— 已经好几次了，一些热门软件的作者由于涌入其私人邮箱的大量不堪忍受的无用邮件而不再提供支持。&lt;/p&gt;
&lt;h2&gt;Stack Overflow&lt;/h2&gt;
&lt;p&gt;搜索，&lt;em&gt;然后&lt;/em&gt;在 Stack Exchange 问。&lt;/p&gt;
&lt;p&gt;近年来，Stack Exchange 社区已经成为回答技术及其他问题的主要渠道，尤其是那些开放源码的项目。&lt;/p&gt;
&lt;p&gt;因为 Google 索引是即时的，在看 Stack Exchange 之前先在 Google 搜索。有很高的几率某人已经问了一个类似的问题，而且 Stack Exchange 网站们往往会是搜索结果中最前面几个。如果你在 Google 上没有找到任何答案，你再到特定相关主题的网站去找。用标签（Tag）搜索能让你更缩小你的搜索结果。&lt;/p&gt;
&lt;p&gt;如果你还是找不到任何对你的问题有用的内容，请把你的问题发在与它最相关的网站上。提问的时候请善用格式化工具，尤其注意为代码添加格式，并且添加相关的标签（特别是编程语言、操作系统或库/包的名称）。当有人要求你提供更多相关信息时，请编辑你的贴子来补充它们[译注：而不是发一个回帖或回答！]。如果你觉得一个答案对你有帮助，点击向上的箭头来为它投票；如果一个答案提供了问题的正确解决方案，点击投票按钮下方的对勾来将它标记为正解。&lt;/p&gt;
&lt;p&gt;Stack Exchange 已经成长到&lt;a href=&quot;https://stackexchange.com/sites&quot;&gt;超过一百个网站&lt;/a&gt;，以下是最常用的几个站：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Super User 是问一些通用的电脑问题，如果你的问题跟代码或是写程序无关，只是一些网络连线之类的，请到这里。&lt;/li&gt;
&lt;li&gt;Stack Overflow 是问写程序有关的问题。&lt;/li&gt;
&lt;li&gt;Server Fault 是问服务器和网管相关的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;网站和 IRC 论坛&lt;/h2&gt;
&lt;p&gt;本地的用户群组（user group），或者你所用的 Linux 发行版本也许正在宣传他们的网页论坛或 IRC 频道，并提供新手帮助（在一些非英语国家，新手论坛很可能还是邮件列表），这些都是开始提问的好地方，特别是当你觉得遇到的也许只是相对简单或者很普通的问题时。有广告赞助的 IRC 频道是公开欢迎提问的地方，通常可以即时得到回应。&lt;/p&gt;
&lt;p&gt;事实上，如果程序出的问题只发生在特定 Linux 发行版提供的版本（这很常见），最好先去该发行版的论坛或邮件列表中提问，再到程序本身的论坛或邮件列表提问。（否则）该项目的黑客可能仅仅回复“使用&lt;strong&gt;我们的&lt;/strong&gt;版本”。&lt;/p&gt;
&lt;p&gt;在任何论坛发文以前，先确认一下有没有搜索功能。如果有，就试着搜索一下问题的几个关键词，也许这会有帮助。如果在此之前你已做过通用的网页搜索（你也该这样做），还是再搜索一下论坛，搜索引擎有可能没来得及索引此论坛的全部内容。&lt;/p&gt;
&lt;p&gt;通过论坛或 IRC 频道来提供用户支持服务有增长的趋势，电子邮件则大多为项目开发者间的交流而保留。所以最好先在论坛或 IRC 中寻求与该项目相关的协助。&lt;/p&gt;
&lt;p&gt;在使用 IRC 的时候，首先最好不要发布很长的问题描述，有些人称之为频道洪水。最好通过一句话的问题描述来开始聊天。&lt;/p&gt;
&lt;h2&gt;第二步，使用项目邮件列表&lt;/h2&gt;
&lt;p&gt;当某个项目提供开发者邮件列表时，要向列表而不是其中的个别成员提问，即使你确信他能最好地回答你的问题。查一查项目的文件和首页，找到项目的邮件列表并使用它。有几个很好的理由支持我们采用这种办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任何好到需要向个别开发者提出的问题，也将对整个项目群组有益。反之，如果你认为自己的问题对整个项目群组来说太愚蠢，那这也不能成为骚扰个别开发者的理由。&lt;/li&gt;
&lt;li&gt;向列表提问可以分散开发者的负担，个别开发者（尤其是项目领导人）也许太忙以至于没法回答你的问题。&lt;/li&gt;
&lt;li&gt;大多数邮件列表都会被存档，那些被存档的内容将被搜索引擎索引。如果你向列表提问并得到解答，将来其他人可以通过网页搜索找到你的问题和答案，也就不用再次发问了。&lt;/li&gt;
&lt;li&gt;如果某些问题经常被问到，开发者可以利用此信息来改进说明文件或软件本身，以使其更清楚。如果只是私下提问，就没有人能看到最常见问题的完整场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果一个项目既有“用户”也有“开发者”（或“黑客”）邮件列表或论坛，而你又不会动到那些源代码，那么就向“用户”列表或论坛提问。不要假设自己会在开发者列表中受到欢迎，那些人多半会将你的提问视为干扰他们开发的噪音。&lt;/p&gt;
&lt;p&gt;然而，如果你&lt;strong&gt;确信&lt;/strong&gt;你的问题很特别，而且在“用户”列表或论坛中几天都没有回复，可以试试前往“开发者”列表或论坛发问。建议你在张贴前最好先暗地里观察几天以了解那里的行事方式（事实上这是参与任何私有或半私有列表的好主意）&lt;/p&gt;
&lt;p&gt;如果你找不到一个项目的邮件列表，而只能查到项目维护者的电子邮件地址，尽管向他发信。即使是在这种情况下，也别假设（项目）邮件列表不存在。在你的电子邮件中，请陈述你已经试过但没有找到合适的邮件列表，也提及你不反对将自己的邮件转发给他人（许多人认为，即使没什么秘密，私人电子邮件也不应该被公开。通过允许将你的电子邮件转发他人，你给了相应人员处置你邮件的选择）。&lt;/p&gt;
&lt;h2&gt;使用有意义且描述明确的标题&lt;/h2&gt;
&lt;p&gt;在邮件列表、新闻群组或论坛中，大约 50 字以内的标题是抓住资深专家注意力的好机会。别用喋喋不休的&lt;code&gt;帮帮忙&lt;/code&gt;、&lt;code&gt;跪求&lt;/code&gt;、&lt;code&gt;急&lt;/code&gt;（更别说&lt;code&gt;救命啊！！！！&lt;/code&gt;这样让人反感的话，用这种标题会被条件反射式地忽略）来浪费这个机会。不要妄想用你的痛苦程度来打动我们，而应该是在这点空间中使用极简单扼要的描述方式来提出问题。&lt;/p&gt;
&lt;p&gt;一个好标题范例是&lt;code&gt;目标 —— 差异&lt;/code&gt;式的描述，许多技术支持组织就是这样做的。在&lt;code&gt;目标&lt;/code&gt;部分指出是哪一个或哪一组东西有问题，在&lt;code&gt;差异&lt;/code&gt;部分则描述与期望的行为不一致的地方。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;蠢问题：救命啊！我的笔记本电脑不能正常显示了！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;聪明问题：X.org 6.8.1 的鼠标指针会变形，某牌显卡 MV1005 芯片组。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;更聪明问题：X.org 6.8.1 的鼠标指针，在某牌显卡 MV1005 芯片组环境下 - 会变形。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;编写&lt;code&gt;目标 —— 差异&lt;/code&gt; 式描述的过程有助于你组织对问题的细致思考。是什么被影响了？ 仅仅是鼠标指针或者还有其它图形？只在 X.org 的 X 版中出现？或只是出现在 6.8.1 版中？ 是针对某牌显卡芯片组？或者只是其中的 MV1005 型号？ 一个黑客只需瞄一眼就能够立即明白你的环境&lt;strong&gt;和&lt;/strong&gt;你遇到的问题。&lt;/p&gt;
&lt;p&gt;总而言之，请想像一下你正在一个只显示标题的存档讨论串（Thread）索引中查寻。让你的标题更好地反映问题，可使下一个搜索类似问题的人能够关注这个讨论串，而不用再次提问相同的问题。&lt;/p&gt;
&lt;p&gt;如果你想在回复中提出问题，记得要修改内容标题，以表明你是在问一个问题， 一个看起来像 &lt;code&gt;Re: 测试&lt;/code&gt; 或者 &lt;code&gt;Re: 新 bug&lt;/code&gt; 的标题很难引起足够重视。另外，在不影响连贯性之下，适当引用并删减前文的内容，能给新来的读者留下线索。&lt;/p&gt;
&lt;p&gt;对于讨论串，不要直接点击回复来开始一个全新的讨论串，这将限制你的观众。因为有些邮件阅读程序，比如 mutt ，允许用户按讨论串排序并通过折叠讨论串来隐藏消息，这样做的人永远看不到你发的消息。&lt;/p&gt;
&lt;p&gt;仅仅改变标题还不够。mutt 和其它一些邮件阅读程序还会检查邮件标题以外的其它信息，以便为其指定讨论串。所以宁可发一个全新的邮件。&lt;/p&gt;
&lt;p&gt;在网页论坛上，好的提问方式稍有不同，因为讨论串与特定的信息紧密结合，并且通常在讨论串外就看不到里面的内容，故通过回复提问，而非改变标题是可接受的。不是所有论坛都允许在回复中出现分离的标题，而且这样做了基本上没有人会去看。不过，通过回复提问，这本身就是暧昧的做法，因为它们只会被正在查看该标题的人读到。所以，除非你&lt;strong&gt;只想&lt;/strong&gt;在该讨论串当前活跃的人群中提问，不然还是另起炉灶比较好。&lt;/p&gt;
&lt;h2&gt;使问题容易回复&lt;/h2&gt;
&lt;p&gt;以&lt;code&gt;请将你的回复发送到……&lt;/code&gt;来结束你的问题多半会使你得不到回答。如果你觉得花几秒钟在邮件客户端设置一下回复地址都麻烦，我们也觉得花几秒钟思考你的问题更麻烦。如果你的邮件程序不支持这样做，&lt;a href=&quot;http://linuxmafia.com/faq/Mail/muas.html&quot;&gt;换个好点的&lt;/a&gt;；如果是操作系统不支持这种邮件程序，也换个好点的。&lt;/p&gt;
&lt;p&gt;在论坛，要求通过电子邮件回复是非常无礼的，除非你认为回复的信息可能比较敏感（有人会为了某些未知的原因，只让你而不是整个论坛知道答案）。如果你只是想在有人回复讨论串时得到电子邮件提醒，可以要求网页论坛发送给你。几乎所有论坛都支持诸如&lt;code&gt;追踪此讨论串&lt;/code&gt;、&lt;code&gt;有回复时发送邮件提醒&lt;/code&gt;等功能。&lt;/p&gt;
&lt;h2&gt;使用清晰、正确、精准且合乎语法的语句&lt;/h2&gt;
&lt;p&gt;我们从经验中发现，粗心的提问者通常也会粗心地写程序与思考（我敢打包票）。回答粗心大意者的问题很不值得，我们宁愿把时间耗在别处。&lt;/p&gt;
&lt;p&gt;正确的拼写、标点符号和大小写是很重要的。一般来说，如果你觉得这样做很麻烦，不想在乎这些，那我们也觉得麻烦，不想在乎你的提问。花点额外的精力斟酌一下字句，用不着太僵硬与正式 —— 事实上，黑客文化很看重能准确地使用非正式、俚语和幽默的语句。但它&lt;strong&gt;必须很&lt;/strong&gt;准确，而且有迹象表明你是在思考和关注问题。&lt;/p&gt;
&lt;p&gt;正确地拼写、使用标点和大小写，不要将&lt;code&gt;its&lt;/code&gt;混淆为&lt;code&gt;it&apos;s&lt;/code&gt;，&lt;code&gt;loose&lt;/code&gt;搞成&lt;code&gt;lose&lt;/code&gt;或者将&lt;code&gt;discrete&lt;/code&gt;弄成&lt;code&gt;discreet&lt;/code&gt;。不要&lt;strong&gt;全部用大写&lt;/strong&gt;，这会被视为无礼的大声嚷嚷（全部小写也好不到哪去，因为不易阅读。&lt;a href=&quot;http://en.wikipedia.org/wiki/Alan_Cox&quot;&gt;Alan Cox&lt;/a&gt; 也许可以这样做，但你不行）。&lt;/p&gt;
&lt;p&gt;更白话的说，如果你写得像是个半文盲[译注：&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E5%B0%8F%E7%99%BD&quot;&gt;小白&lt;/a&gt;]，那多半得不到理睬。也不要使用即时通信中的简写或&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E7%81%AB%E6%98%9F%E6%96%87&quot;&gt;火星文&lt;/a&gt;，如将&lt;code&gt;的&lt;/code&gt;简化为&lt;code&gt;d&lt;/code&gt;会使你看起来像一个为了少打几个键而省字的小白。更糟的是，如果像个小孩似地鬼画符那绝对是在找死，可以肯定没人会理你（或者最多是给你一大堆指责与挖苦）。&lt;/p&gt;
&lt;p&gt;如果在使用非母语的论坛提问，你可以犯点拼写和语法上的小错，但决不能在思考上马虎（没错，我们通常能弄清两者的分别）。同时，除非你知道回复者使用的语言，否则请使用英语书写。繁忙的黑客一般会直接删除用他们看不懂的语言写的消息。在网络上英语是通用语言，用英语书写可以将你的问题在尚未被阅读就被直接删除的可能性降到最低。&lt;/p&gt;
&lt;p&gt;如果英文是你的外语（Second language），提示潜在回复者你有潜在的语言困难是很好的：
[译注：以下附上原文以供使用]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;English is not my native language; please excuse typing errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;英文不是我的母语，请原谅我的错字或语法。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;If you speak $LANGUAGE, please email/PM me;
I may need assistance translating my question.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;如果你说&lt;strong&gt;某语言&lt;/strong&gt;，请向我发电邮/私信；&lt;/li&gt;
&lt;li&gt;我需要有人协助我翻译我的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;I am familiar with the technical terms,
but some slang expressions and idioms are difficult for me.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;我对技术名词很熟悉，但对于俗语或是特别用法不甚了解。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;ve posted my question in $LANGUAGE and English.
I&apos;ll be glad to translate responses, if you only use one or the other.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;我把我的问题用&lt;strong&gt;某语言&lt;/strong&gt;和英文写出来。&lt;/li&gt;
&lt;li&gt;如果你只用其中的一种语言回答，我会乐意将回复翻译成为你使用的语言。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;使用易于读取且标准的文件格式发送问题&lt;/h2&gt;
&lt;p&gt;如果你人为地将问题搞得难以阅读，它多半会被忽略，人们更愿读易懂的问题，所以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用纯文字而不是 HTML （&lt;a href=&quot;http://archive.birdhouse.org/etc/evilmail.html&quot;&gt;关闭 HTML&lt;/a&gt; 并不难）。&lt;/li&gt;
&lt;li&gt;使用 MIME 附件通常是可以的，前提是真正有内容（譬如附带的源代码或 patch），而不仅仅是邮件程序生成的模板（譬如只是信件内容的拷贝）。&lt;/li&gt;
&lt;li&gt;不要发送一段文字只是一行句子但自动换行后会变成多行的邮件（这使得回复部分内容非常困难）。设想你的读者是在 80 个字符宽的终端机上阅读邮件，最好设置你的换行分割点小于 80 字。&lt;/li&gt;
&lt;li&gt;但是，对一些特殊的文件&lt;strong&gt;不要&lt;/strong&gt;设置固定宽度（譬如日志文件拷贝或会话记录）。数据应该原样包含，让回复者有信心他们看到的是和你看到的一样的东西。&lt;/li&gt;
&lt;li&gt;在英语论坛中，不要使用&lt;code&gt;Quoted-Printable&lt;/code&gt; MIME 编码发送消息。这种编码对于张贴非 ASCII 语言可能是必须的，但很多邮件程序并不支持这种编码。当它们处理换行时，那些文本中四处散布的&lt;code&gt;=20&lt;/code&gt;符号既难看也分散注意力，甚至有可能破坏内容的语意。&lt;/li&gt;
&lt;li&gt;绝对，&lt;strong&gt;永远&lt;/strong&gt;不要指望黑客们阅读使用封闭格式编写的文档，像微软公司的 Word 或 Excel 文件等。大多数黑客对此的反应就像有人将还在冒热气的猪粪倒在你家门口时你的反应一样。即便他们能够处理，他们也很厌恶这么做。&lt;/li&gt;
&lt;li&gt;如果你从使用 Windows 的电脑发送电子邮件，关闭微软愚蠢的&lt;code&gt;智能引号&lt;/code&gt;功能 （从[选项] &amp;gt; [校订] &amp;gt; [自动校正选项]，勾选掉&lt;code&gt;智能引号&lt;/code&gt;单选框），以免在你的邮件中到处散布垃圾字符。&lt;/li&gt;
&lt;li&gt;在论坛，勿滥用&lt;code&gt;表情符号&lt;/code&gt;和&lt;code&gt;HTML&lt;/code&gt;功能（当它们提供时）。一两个表情符号通常没有问题，但花哨的彩色文本倾向于使人认为你是个无能之辈。过滥地使用表情符号、色彩和字体会使你看来像个傻笑的小姑娘。这通常不是个好主意，除非你只是对性而不是对答案感兴趣。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你使用图形用户界面的邮件程序（如微软公司的 Outlook 或者其它类似的），注意它们的默认设置不一定满足这些要求。大多数这类程序有基于选单的&lt;code&gt;查看源代码&lt;/code&gt;命令，用它来检查发送文件夹中的邮件，以确保发送的是纯文本文件同时没有一些奇怪的字符。&lt;/p&gt;
&lt;h2&gt;精确地描述问题并言之有物&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;仔细、清楚地描述你的问题或 Bug 的症状。&lt;/li&gt;
&lt;li&gt;描述问题发生的环境（机器配置、操作系统、应用程序、以及相关的信息），提供经销商的发行版和版本号（如：&lt;code&gt;Fedora Core 4&lt;/code&gt;、&lt;code&gt;Slackware 9.1&lt;/code&gt;等）。&lt;/li&gt;
&lt;li&gt;描述在提问前你是怎样去研究和理解这个问题的。&lt;/li&gt;
&lt;li&gt;描述在提问前为确定问题而采取的诊断步骤。&lt;/li&gt;
&lt;li&gt;描述最近做过什么可能相关的硬件或软件变更。&lt;/li&gt;
&lt;li&gt;尽可能地提供一个可以&lt;code&gt;重现这个问题的可控环境&lt;/code&gt;的方法。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尽量去揣测一个黑客会怎样反问你，在你提问之前预先将黑客们可能提出的问题回答一遍。&lt;/p&gt;
&lt;p&gt;以上几点中，当你报告的是你认为可能在代码中的问题时，给黑客一个可以重现你的问题的环境尤其重要。当你这么做时，你得到有效的回答的机会和速度都会大大的提升。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.chiark.greenend.org.uk/~sgtatham/&quot;&gt;Simon Tatham&lt;/a&gt; 写过一篇名为《&lt;a href=&quot;http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html&quot;&gt;如何有效地报告Bug&lt;/a&gt;》的出色文章。强力推荐你也读一读。&lt;/p&gt;
&lt;h2&gt;话不在多而在精&lt;/h2&gt;
&lt;p&gt;你需要提供精确有内容的信息。这并不是要求你简单的把成堆的出错代码或者资料完全转录到你的提问中。如果你有庞大而复杂的测试样例能重现程序挂掉的情境，尽量将它剪裁得越小越好。&lt;/p&gt;
&lt;p&gt;这样做的用处至少有三点。
第一，表现出你为简化问题付出了努力，这可以使你得到回答的机会增加；
第二，简化问题使你更有可能得到&lt;strong&gt;有用&lt;/strong&gt;的答案；
第三，在精炼你的 bug 报告的过程中，你很可能就自己找到了解决方法或权宜之计。&lt;/p&gt;
&lt;h2&gt;别动辄声称找到 Bug&lt;/h2&gt;
&lt;p&gt;当你在使用软件中遇到问题，除非你非常、&lt;strong&gt;非常&lt;/strong&gt;的有根据，不要动辄声称找到了 Bug。提示：除非你能提供解决问题的源代码补丁，或者提供回归测试来表明前一版本中行为不正确，否则你都多半不够完全确信。这同样适用在网页和文件，如果你（声称）发现了文件的&lt;code&gt;Bug&lt;/code&gt;，你应该能提供相应位置的修正或替代文件。&lt;/p&gt;
&lt;p&gt;请记得，还有其他许多用户没遇到你发现的问题，否则你在阅读文件或搜索网页时就应该发现了（你在抱怨前&lt;a href=&quot;#%E5%9C%A8%E6%8F%90%E9%97%AE%E4%B9%8B%E5%89%8D&quot;&gt;已经做了这些，是吧&lt;/a&gt;？）。这也意味着很有可能是你弄错了而不是软件本身有问题。&lt;/p&gt;
&lt;p&gt;编写软件的人总是非常辛苦地使它尽可能完美。如果你声称找到了 Bug，也就是在质疑他们的能力，即使你是对的，也有可能会冒犯到其中某部分人。当你在标题中嚷嚷着有&lt;code&gt;Bug&lt;/code&gt;时，这尤其严重。&lt;/p&gt;
&lt;p&gt;提问时，即使你私下非常确信已经发现一个真正的 Bug，最好写得像是&lt;strong&gt;你&lt;/strong&gt;做错了什么。如果真的有 Bug，你会在回复中看到这点。这样做的话，如果真有 Bug，维护者就会向你道歉，这总比你惹恼别人然后欠别人一个道歉要好一点。&lt;/p&gt;
&lt;h2&gt;低声下气不能代替你的功课&lt;/h2&gt;
&lt;p&gt;有些人明白他们不该粗鲁或傲慢的提问并要求得到答复，但他们选择另一个极端 —— 低声下气：&lt;code&gt;我知道我只是个可悲的新手，一个失败者，但...&lt;/code&gt;。这既使人困扰，也没有用，尤其是伴随着与实际问题含糊不清的描述时更令人反感。&lt;/p&gt;
&lt;p&gt;别用原始灵长类动物的把戏来浪费你我的时间。取而代之的是，尽可能清楚地描述背景条件和你的问题情况。这比低声下气更好地定位了你的位置。&lt;/p&gt;
&lt;p&gt;有时网页论坛会设有专为新手提问的版面，如果你真的认为遇到了初学者的问题，到那去就是了，但一样别那么低声下气。&lt;/p&gt;
&lt;h2&gt;描述问题症状而非你的猜测&lt;/h2&gt;
&lt;p&gt;告诉黑客们你认为问题是怎样造成的并没什么帮助。（如果你的推断如此有效，还用向别人求助吗？），因此要确信你原原本本告诉了他们问题的症状，而不是你的解释和理论；让黑客们来推测和诊断。如果你认为陈述自己的猜测很重要，清楚地说明这只是你的猜测，并描述为什么它们不起作用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蠢问题&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我在编译内核时接连遇到 SIG11 错误，
我怀疑某条飞线搭在主板的走线上了，这种情况应该怎样检查最好？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;聪明问题&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我的组装电脑是 FIC-PA2007 主机板搭载 AMD K6/233 CPU（威盛 Apollo VP2 芯片组），
256MB Corsair PC133 SDRAM 内存，在编译内核时，从开机 20 分钟以后就频频产生 SIG11 错误，
但是在头 20 分钟内从没发生过相同的问题。重新启动也没有用，但是关机一晚上就又能工作 20 分钟。
所有内存都换过了，没有效果。相关部分的标准编译记录如下…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于以上这点似乎让许多人觉得难以配合，这里有句话可以提醒你：&lt;code&gt;所有的诊断专家都来自密苏里州。&lt;/code&gt; 美国国务院的官方座右铭则是：&lt;code&gt;让我看看&lt;/code&gt;（出自国会议员 Willard D. Vandiver 在 1899 年时的讲话：&lt;code&gt;我来自一个出产玉米，棉花，牛蒡和民主党人的国家，滔滔雄辩既不能说服我，也不会让我满意。我来自密苏里州，你必须让我看看。&lt;/code&gt;） 针对诊断者而言，这并不是一种怀疑，而只是一种真实而有用的需求，以便让他们看到的是与你看到的原始证据尽可能一致的东西，而不是你的猜测与归纳的结论。所以，大方地展示给我们看吧！&lt;/p&gt;
&lt;h2&gt;按发生时间先后列出问题症状&lt;/h2&gt;
&lt;p&gt;问题发生前的一系列操作，往往就是对找出问题最有帮助的线索。因此，你的说明里应该包含你的操作步骤，以及机器和软件的反应，直到问题发生。在命令行处理的情况下，提供一段操作记录（例如运行脚本工具所生成的），并引用相关的若干行（如 20 行）记录会非常有帮助。&lt;/p&gt;
&lt;p&gt;如果挂掉的程序有诊断选项（如 -v 的详述开关），试着选择这些能在记录中增加调试信息的选项。记住，&lt;code&gt;多&lt;/code&gt;不等于&lt;code&gt;好&lt;/code&gt;。试着选取适当的调试级别以便提供有用的信息而不是让读者淹没在垃圾中。&lt;/p&gt;
&lt;p&gt;如果你的说明很长（如超过四个段落），在开头简述问题，接下来再按时间顺序详述会有所帮助。这样黑客们在读你的记录时就知道该注意哪些内容了。&lt;/p&gt;
&lt;h2&gt;描述目标而不是过程&lt;/h2&gt;
&lt;p&gt;如果你想弄清楚如何做某事（而不是报告一个 Bug），在开头就描述你的目标，然后才陈述重现你所卡住的特定步骤。&lt;/p&gt;
&lt;p&gt;经常寻求技术帮助的人在心中有个更高层次的目标，而他们在自以为能达到目标的特定道路上被卡住了，然后跑来问该怎么走，但没有意识到这条路本身就有问题。结果要费很大的劲才能搞定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蠢问题&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我怎样才能从某绘图程序的颜色选择器中取得十六进制的 RGB 值？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;聪明问题&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我正试着用替换一幅图片的色码（color table）成自己选定的色码，我现在知道的唯一方法是编辑每个色码区块（table slot），
但却无法从某绘图程序的颜色选择器取得十六进制的 RGB 值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;第二种提问法比较聪明，你可能得到像是&lt;code&gt;建议采用另一个更合适的工具&lt;/code&gt;的回复。&lt;/p&gt;
&lt;h2&gt;别要求使用私人电邮回复&lt;/h2&gt;
&lt;p&gt;黑客们认为问题的解决过程应该公开、透明，此过程中如果更有经验的人注意到不完整或者不当之处，最初的回复才能够、也应该被纠正。同时，作为提供帮助者可以得到一些奖励，奖励就是他的能力和学识被其他同行看到。&lt;/p&gt;
&lt;p&gt;当你要求私下回复时，这个过程和奖励都被中止。别这样做，让&lt;strong&gt;回复者&lt;/strong&gt;来决定是否私下回答 —— 如果他真这么做了，通常是因为他认为问题编写太差或者太肤浅，以至于不可能使其他人产生兴趣。&lt;/p&gt;
&lt;p&gt;这条规则存在一条有限的例外，如果你确信提问可能会引来大量雷同的回复时，那么这个神奇的提问句会是&lt;code&gt;向我发电邮，我将为论坛归纳这些回复&lt;/code&gt;。试着将邮件列表或新闻群组从洪水般的雷同回复中解救出来是非常有礼貌的 —— 但你必须信守诺言。&lt;/p&gt;
&lt;h2&gt;清楚明确地表达你的问题以及需求&lt;/h2&gt;
&lt;p&gt;漫无边际的提问是近乎无休无止的时间黑洞。最有可能给你有用答案的人通常也正是最忙的人（他们忙是因为要亲自完成大部分工作）。这样的人对无节制的时间黑洞相当厌恶，所以他们也倾向于厌恶那些漫无边际的提问。&lt;/p&gt;
&lt;p&gt;如果你明确表述需要回答者做什么（如提供指点、发送一段代码、检查你的补丁、或是其他等等），就最有可能得到有用的答案。因为这会定出一个时间和精力的上限，便于回答者能集中精力来帮你。这么做很棒。&lt;/p&gt;
&lt;p&gt;要理解专家们所处的世界，请把专业技能想像为充裕的资源，而回复的时间则是稀缺的资源。你要求他们奉献的时间越少，你越有可能从真正专业而且很忙的专家那里得到解答。&lt;/p&gt;
&lt;p&gt;所以，界定一下你的问题，使专家花在辨识你的问题和回答所需要付出的时间减到最少，这技巧对你获得有用的答案相当有帮助 —— 但这技巧通常和简化问题有所区别。因此，问&lt;code&gt;我想更好地理解 X，可否指点一下哪有好一点说明？&lt;/code&gt;通常比问&lt;code&gt;你能解释一下 X 吗？&lt;/code&gt;更好。如果你的代码不能运作，通常请别人看看哪里有问题，比要求别人替你改正要明智得多。&lt;/p&gt;
&lt;h2&gt;询问有关代码的问题时&lt;/h2&gt;
&lt;p&gt;如果没有提示别人应该从何入手，别要求他人帮你调试有问题的代码。张贴几百行的代码，然后说一声：&lt;code&gt;它不能工作&lt;/code&gt;会让你完全被忽略。只贴几十行代码，然后说一句：&lt;code&gt;在第七行以后，我期待它显示 &amp;lt;x&amp;gt;，但实际出现的是 &amp;lt;y&amp;gt;&lt;/code&gt;比较有可能让你得到回应。&lt;/p&gt;
&lt;p&gt;最有效描述程序问题的方法是提供最精简的 Bug 展示测试用例（bug-demonstrating test case）。什么是最精简的测试用例？那是问题的缩影；一小个程序片段能&lt;strong&gt;刚好&lt;/strong&gt;展示出程序的异常行为，而不包含其他令人分散注意力的内容。怎么制作最精简的测试用例？如果你知道哪一行或哪一段代码会造成异常的行为，复制下来并加入足够重现这个状况的代码（例如，足以让这段代码能被编译/直译/被应用程序处理）。如果你无法将问题缩减到一个特定区块，就复制一份代码并移除不影响产生问题行为的部分。总之，测试用例越小越好（查看&lt;a href=&quot;#%E8%AF%9D%E4%B8%8D%E5%9C%A8%E5%A4%9A%E8%80%8C%E5%9C%A8%E7%B2%BE&quot;&gt;话不在多而在精&lt;/a&gt;一节）。&lt;/p&gt;
&lt;p&gt;一般而言，要得到一段相当精简的测试用例并不太容易，但永远先尝试这样做是一个好习惯。这种方式可以帮助你了解如何自行解决这个问题 —— 而且即使你的尝试不成功，黑客们也会看到你在尝试取得答案的过程中付出了努力，这可以让他们更愿意与你合作。&lt;/p&gt;
&lt;p&gt;如果你只是想让别人帮忙审查（Review）一下代码，在信的开头就要说出来，并且一定要提到你认为哪一部分特别需要关注以及为什么。&lt;/p&gt;
&lt;h2&gt;别把自己家庭作业的问题贴上来&lt;/h2&gt;
&lt;p&gt;黑客们很擅长分辨哪些问题是家庭作业式的问题；因为我们中的大多数都曾自己解决这类问题。同样，这些问题得由&lt;strong&gt;你&lt;/strong&gt;来搞定，你会从中学到东西。你可以要求给点提示，但别要求得到完整的解决方案。&lt;/p&gt;
&lt;p&gt;如果你怀疑自己碰到了一个家庭作业式的问题，但仍然无法解决，试试在用户群组，论坛或（最后一招）在项目的&lt;strong&gt;用户&lt;/strong&gt;邮件列表或论坛中提问。尽管黑客们&lt;strong&gt;会&lt;/strong&gt;看出来，但一些有经验的用户也许仍会给你一些提示。&lt;/p&gt;
&lt;h2&gt;去掉无意义的提问句&lt;/h2&gt;
&lt;p&gt;避免用无意义的话结束提问，例如&lt;code&gt;有人能帮我吗？&lt;/code&gt;或者&lt;code&gt;这有答案吗？&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;首先：如果你对问题的描述不是很好，这样问更是画蛇添足。&lt;/p&gt;
&lt;p&gt;其次：由于这样问是画蛇添足，黑客们会很厌烦你 —— 而且通常会用逻辑上正确，但毫无意义的回答来表示他们的蔑视， 例如：&lt;code&gt;没错，有人能帮你&lt;/code&gt;或者&lt;code&gt;不，没答案&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;一般来说，避免用 &lt;code&gt;是或否&lt;/code&gt;、&lt;code&gt;对或错&lt;/code&gt;、&lt;code&gt;有或没有&lt;/code&gt;类型的问句，除非你想得到&lt;a href=&quot;https://strcat.de/questions-with-yes-or-no-answers.html&quot;&gt;是或否类型的回答&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;即使你很急也不要在标题写&lt;code&gt;紧急&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;这是你的问题，不是我们的。宣称&lt;code&gt;紧急&lt;/code&gt;极有可能事与愿违：大多数黑客会直接删除无礼和自私地企图即时引起关注的问题。更严重的是，&lt;code&gt;紧急&lt;/code&gt;这个字（或是其他企图引起关注的标题）通常会被垃圾信过滤器过滤掉 —— 你希望能看到你问题的人可能永远也看不到。&lt;/p&gt;
&lt;p&gt;有半个例外的情况是，如果你是在一些很高调，会使黑客们兴奋的地方，也许值得这样去做。在这种情况下，如果你有时间压力，也很有礼貌地提到这点，人们也许会有兴趣回答快一点。&lt;/p&gt;
&lt;p&gt;当然，这风险很大，因为黑客们兴奋的点多半与你的不同。譬如从 NASA 国际空间站（International Space Station）发这样的标题没有问题，但用自我感觉良好的慈善行为或政治原因发肯定不行。事实上，张贴诸如&lt;code&gt;紧急：帮我救救这个毛茸茸的小海豹！&lt;/code&gt;肯定让你被黑客忽略或惹恼他们，即使他们认为毛茸茸的小海豹很重要。&lt;/p&gt;
&lt;p&gt;如果你觉得这点很不可思议，最好再把这份指南剩下的内容多读几遍，直到你弄懂了再发文。&lt;/p&gt;
&lt;h2&gt;礼多人不怪，而且有时还很有帮助&lt;/h2&gt;
&lt;p&gt;彬彬有礼，多用&lt;code&gt;请&lt;/code&gt;和&lt;code&gt;谢谢您的关注&lt;/code&gt;，或&lt;code&gt;谢谢你的关照&lt;/code&gt;。让大家都知道你对他们花时间免费提供帮助心存感激。&lt;/p&gt;
&lt;p&gt;坦白说，这一点并没有比使用清晰、正确、精准且合乎语法和避免使用专用格式重要（也不能取而代之）。黑客们一般宁可读有点唐突但技术上鲜明的 Bug 报告，而不是那种有礼但含糊的报告。（如果这点让你不解，记住我们是按问题能教给我们什么来评价问题的价值的）&lt;/p&gt;
&lt;p&gt;然而，如果你有一串的问题待解决，客气一点肯定会增加你得到有用回应的机会。&lt;/p&gt;
&lt;p&gt;（我们注意到，自从本指南发布后，从资深黑客那里得到的唯一严重缺陷反馈，就是对预先道谢这一条。一些黑客觉得&lt;code&gt;先谢了&lt;/code&gt;意味着事后就不用再感谢任何人的暗示。我们的建议是要么先说&lt;code&gt;先谢了&lt;/code&gt;，&lt;strong&gt;然后&lt;/strong&gt;事后再对回复者表示感谢，或者换种方式表达感激，譬如用&lt;code&gt;谢谢你的关注&lt;/code&gt;或&lt;code&gt;谢谢你的关照&lt;/code&gt;。）&lt;/p&gt;
&lt;h2&gt;问题解决后，加个简短的补充说明&lt;/h2&gt;
&lt;p&gt;问题解决后，向所有帮助过你的人发个说明，让他们知道问题是怎样解决的，并再一次向他们表示感谢。如果问题在新闻组或者邮件列表中引起了广泛关注，应该在那里贴一个说明比较恰当。&lt;/p&gt;
&lt;p&gt;最理想的方式是向最初提问的话题回复此消息，并在标题中包含&lt;code&gt;已修正&lt;/code&gt;，&lt;code&gt;已解决&lt;/code&gt;或其它同等含义的明显标记。在人来人往的邮件列表里，一个看见讨论串&lt;code&gt;问题 X&lt;/code&gt;和&lt;code&gt;问题 X - 已解决&lt;/code&gt;的潜在回复者就明白不用再浪费时间了（除非他个人觉得&lt;code&gt;问题 X&lt;/code&gt;有趣），因此可以利用此时间去解决其它问题。&lt;/p&gt;
&lt;p&gt;补充说明不必很长或是很深入；简单的一句&lt;code&gt;你好，原来是网线出了问题！谢谢大家 – Bill&lt;/code&gt;比什么也不说要来的好。事实上，除非结论真的很有技术含量，否则简短可爱的小结比长篇大论更好。说明问题是怎样解决的，但大可不必将解决问题的过程复述一遍。&lt;/p&gt;
&lt;p&gt;对于有深度的问题，张贴调试记录的摘要是有帮助的。描述问题的最终状态，说明是什么解决了问题，在此&lt;strong&gt;之后&lt;/strong&gt;才指明可以避免的盲点。避免盲点的部分应放在正确的解决方案和其它总结材料之后，而不要将此信息搞成侦探推理小说。列出那些帮助过你的名字，会让你交到更多朋友。&lt;/p&gt;
&lt;p&gt;除了有礼貌和有内涵以外，这种类型的补充也有助于他人在邮件列表/新闻群组/论坛中搜索到真正解决你问题的方案，让他们也从中受益。&lt;/p&gt;
&lt;p&gt;至少，这种补充有助于让每位参与协助的人因问题的解决而从中得到满足感。如果你自己不是技术专家或者黑客，那就相信我们，这种感觉对于那些你向他们求助的大师或者专家而言，是非常重要的。问题悬而未决会让人灰心；黑客们渴望看到问题被解决。好人有好报，满足他们的渴望，你会在下次提问时尝到甜头。&lt;/p&gt;
&lt;p&gt;思考一下怎样才能避免他人将来也遇到类似的问题，自问写一份文件或加个常见问题（FAQ）会不会有帮助。如果是的话就将它们发给维护者。&lt;/p&gt;
&lt;p&gt;在黑客中，这种良好的后继行动实际上比传统的礼节更为重要，也是你如何透过善待他人而赢得声誉的方式，这是非常有价值的资产。&lt;/p&gt;
&lt;h1&gt;如何解读答案&lt;/h1&gt;
&lt;p&gt;&amp;lt;a id=&quot;RTFM&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;h3&gt;RTFM 和 STFW：如何知道你已完全搞砸了&lt;/h3&gt;
&lt;p&gt;有一个古老而神圣的传统：如果你收到&lt;code&gt;RTFM（Read The Fucking Manual）&lt;/code&gt;的回应，回答者认为你&lt;strong&gt;应该去读他妈的手册&lt;/strong&gt;。当然，基本上他是对的，你应该去读一读。&lt;/p&gt;
&lt;p&gt;RTFM 有一个年轻的亲戚。如果你收到&lt;code&gt;STFW（Search The Fucking Web）&lt;/code&gt;的回应，回答者认为你&lt;strong&gt;应该到他妈的网上搜索&lt;/strong&gt;。那人多半也是对的，去搜索一下吧。（更温和一点的说法是 &lt;strong&gt;&lt;a href=&quot;http://lmgtfy.com/&quot;&gt;Google 是你的朋友&lt;/a&gt;&lt;/strong&gt;！）&lt;/p&gt;
&lt;p&gt;在论坛，你也可能被要求去爬爬论坛的旧文。事实上，有人甚至可能热心地为你提供以前解决此问题的讨论串。但不要依赖这种关照，提问前应该先搜索一下旧文。&lt;/p&gt;
&lt;p&gt;通常，用这两句之一回答你的人会给你一份包含你需要内容的手册或者一个网址，而且他们打这些字的时候也正在读着。这些答复意味着回答者认为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;你需要的信息非常容易获得&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;你自己去搜索这些信息比灌给你，能让你学到更多&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;你不应该因此不爽；&lt;strong&gt;依照黑客的标准，他已经表示了对你一定程度的关注，而没有对你的要求视而不见&lt;/strong&gt;。你应该对他祖母般的慈祥表示感谢。&lt;/p&gt;
&lt;h2&gt;如果还是搞不懂&lt;/h2&gt;
&lt;p&gt;如果你看不懂回应，别立刻要求对方解释。像你以前试着自己解决问题时那样（利用手册，FAQ，网络，身边的高手），先试着去搞懂他的回应。如果你真的需要对方解释，记得表现出你已经从中学到了点什么。&lt;/p&gt;
&lt;p&gt;比方说，如果我回答你：&lt;code&gt;看来似乎是 zentry 卡住了；你应该先清除它。&lt;/code&gt;，然后，这是一个&lt;strong&gt;很糟的&lt;/strong&gt;后续问题回应：&lt;code&gt;zentry 是什么？&lt;/code&gt; &lt;strong&gt;好&lt;/strong&gt;的问法应该是这样：&lt;code&gt;哦~~~我看过说明了但是只有 -z 和 -p 两个参数中提到了 zentries，而且还都没有清楚的解释如何清除它。你是指这两个中的哪一个吗？还是我看漏了什么？&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;处理无礼的回应&lt;/h2&gt;
&lt;p&gt;很多黑客圈子中看似无礼的行为并不是存心冒犯。相反，它是直截了当，一针见血式的交流风格，这种风格更注重解决问题，而不是使人感觉舒服而却模模糊糊。&lt;/p&gt;
&lt;p&gt;如果你觉得被冒犯了，试着平静地反应。如果有人真的做了出格的事，邮件列表、新闻群组或论坛中的前辈多半会招呼他。如果这&lt;strong&gt;没有&lt;/strong&gt;发生而你却发火了，那么你发火对象的言语可能在黑客社区中看起来是正常的，而&lt;strong&gt;你&lt;/strong&gt;将被视为有错的一方，这将伤害到你获取信息或帮助的机会。&lt;/p&gt;
&lt;p&gt;另一方面，你偶尔真的会碰到无礼和无聊的言行。与上述相反，对真正的冒犯者狠狠地打击，用犀利的语言将其驳得体无完肤都是可以接受的。然而，在行事之前一定要非常非常的有根据。纠正无礼的言论与开始一场毫无意义的口水战仅一线之隔，黑客们自己莽撞地越线的情况并不鲜见。如果你是新手或外人，避开这种莽撞的机会并不高。如果你想得到的是信息而不是消磨时光，这时最好不要把手放在键盘上以免冒险。&lt;/p&gt;
&lt;p&gt;（有些人断言很多黑客都有轻度的自闭症或亚斯伯格综合症，缺少用于润滑人类社会&lt;strong&gt;正常&lt;/strong&gt;交往所需的神经。这既可能是真也可能是假的。如果你自己不是黑客，兴许你认为我们脑袋有问题还能帮助你应付我们的古怪行为。只管这么干好了，我们不在乎。我们&lt;strong&gt;喜欢&lt;/strong&gt;我们现在这个样子，并且通常对病患标记都有站得住脚的怀疑。）&lt;/p&gt;
&lt;p&gt;Jeff Bigler 的观察总结和这个相关也值得一读 (&lt;strong&gt;&lt;a href=&quot;http://www.mit.edu/~jcb/tact.html&quot;&gt;tact filters&lt;/a&gt;&lt;/strong&gt;)。&lt;/p&gt;
&lt;p&gt;在下一节，我们会谈到另一个问题，当&lt;strong&gt;你&lt;/strong&gt;行为不当时所会受到的&lt;code&gt;冒犯&lt;/code&gt;。&lt;/p&gt;
&lt;h1&gt;如何避免扮演失败者&lt;/h1&gt;
&lt;p&gt;在黑客社区的论坛中，你以本指南所描述的或类似的方式，可能会有那么几次搞砸了。而你会在公开场合中被告知你是如何搞砸的，也许攻击的言语中还会带点夹七夹八的颜色。&lt;/p&gt;
&lt;p&gt;这种事发生以后，你能做的最糟糕的事莫过于哀嚎你的遭遇、宣称被言语攻击、要求道歉、高声尖叫、憋闷气、威胁诉诸法律、向其雇主报怨、不去关马桶盖等等。相反地，你该这么做：&lt;/p&gt;
&lt;p&gt;熬过去，这很正常。事实上，它是有益健康且合理的。&lt;/p&gt;
&lt;p&gt;社区的标准不会自行维持，它们是通过参与者积极而&lt;strong&gt;公开地&lt;/strong&gt;执行来维持的。不要哭嚎所有的批评都应该通过私下的邮件传送，它不是这样运作的。当有人评论你的一个说法有误或者提出不同看法时，坚持声称受到个人攻击也毫无益处，这些都是失败者的态度。&lt;/p&gt;
&lt;p&gt;也有其它的黑客论坛，受过高礼节要求的误导，禁止参与者张贴任何对别人帖子挑毛病的消息，并声称&lt;code&gt;如果你不想帮助用户就闭嘴。&lt;/code&gt; 结果造成有想法的参与者纷纷离开，这么做只会使它们沦为毫无意义的唠叨与无用的技术论坛。&lt;/p&gt;
&lt;p&gt;夸张的讲法是：你要的是“友善”（以上述方式）还是有用？两个里面挑一个。&lt;/p&gt;
&lt;p&gt;记着：当黑客说你搞砸了，并且（无论多么刺耳）告诉你别再这样做时，他正在为关心&lt;strong&gt;你&lt;/strong&gt;和&lt;strong&gt;他的社区&lt;/strong&gt;而行动。对他而言，不理你并将你从他的生活中滤掉更简单。如果你无法做到感谢，至少要表现得有点尊严，别大声哀嚎，也别因为自己是个有戏剧性超级敏感的灵魂和自以为有资格的新来者，就指望别人像对待脆弱的洋娃娃那样对你。&lt;/p&gt;
&lt;p&gt;有时候，即使你没有搞砸（或者只是在他的想像中你搞砸了），有些人也会无缘无故地攻击你本人。在这种情况下，抱怨倒是&lt;strong&gt;真的&lt;/strong&gt;会把问题搞砸。&lt;/p&gt;
&lt;p&gt;这些来找麻烦的人要么是毫无办法但自以为是专家的不中用家伙，要么就是测试你是否真会搞砸的心理专家。其它读者要么不理睬，要么用自己的方式对付他们。这些来找麻烦的人在给他们自己找麻烦，这点你不用操心。&lt;/p&gt;
&lt;p&gt;也别让自己卷入口水战，最好不要理睬大多数的口水战 —— 当然，这是在你检验它们只是口水战，并且未指出你有搞砸的地方，同时也没有巧妙地将问题真正的答案藏于其后（这也是有可能的）。&lt;/p&gt;
&lt;h1&gt;不该问的问题&lt;/h1&gt;
&lt;p&gt;以下是几个经典蠢问题，以及黑客没回答时心中所想的：&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q1&quot;&gt;我能在哪找到 X 程序或 X 资源？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q2&quot;&gt;我怎样用 X 做 Y？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q3&quot;&gt;如何设定我的 shell 提示？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q4&quot;&gt;我可以用 Bass-o-matic 文件转换工具将 AcmeCorp 文件转换为 TeX 格式吗？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q5&quot;&gt;我的程序/设定/SQL 语句没有用&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q6&quot;&gt;我的 Windows 电脑有问题，你能帮我吗？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q7&quot;&gt;我的程序不会动了，我认为系统工具 X 有问题&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q8&quot;&gt;我在安装 Linux（或者 X ）时有问题，你能帮我吗？&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;问题：&lt;a href=&quot;#q9&quot;&gt;我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢？&lt;/a&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&amp;lt;a id=&quot;q1&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我能在哪找到 X 程序或 X 资源？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：就在我找到它的地方啊，白痴 —— 搜索引擎的那一头。天哪！难道还有人不会用 &lt;a href=&quot;https://www.google.com&quot;&gt;Google&lt;/a&gt; 吗？&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q2&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我怎样用 X 做 Y？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：如果你想解决的是 Y ，提问时别给出可能并不恰当的方法。这种问题说明提问者不但对 X 完全无知，也对 Y 要解决的问题糊涂，还被特定形势禁锢了思维。最好忽略这种人，等他们把问题搞清楚了再说。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q3&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：如何设定我的 shell 提示？？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：如果你有足够的智慧提这个问题，你也该有足够的智慧去 &lt;a href=&quot;#RTFM&quot;&gt;RTFM&lt;/a&gt;，然后自己去找出来。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q4&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我可以用 Bass-o-matic 文件转换工具将 AcmeCorp 文件转换为 TeX 格式吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：试试看就知道了。如果你试过，你就知道了答案，就不用浪费我的时间了。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q5&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我的{程序/设定/SQL 语句}没有用&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：这不算是问题吧，我对要我问你二十个问题才找得出你真正问题的问题没兴趣 —— 我有更有意思的事要做呢。在看到这类问题的时候，我的反应通常不外如下三种&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你还有什么要补充的吗？&lt;/li&gt;
&lt;li&gt;真糟糕，希望你能搞定。&lt;/li&gt;
&lt;li&gt;这关我屁事？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;lt;a id=&quot;q6&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我的 Windows 电脑有问题，你能帮我吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：能啊，扔掉微软的垃圾，换个像 Linux 或 BSD 的开源操作系统吧。&lt;/p&gt;
&lt;p&gt;注意：如果程序有官方版 Windows 或者与 Windows 有互动（如 Samba），你&lt;strong&gt;可以&lt;/strong&gt;问与 Windows 相关的问题，只是别对问题是由 Windows 操作系统而不是程序本身造成的回复感到惊讶， 因为 Windows 一般来说实在太烂，这种说法通常都是对的。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q7&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我的程序不会动了，我认为系统工具 X 有问题&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：你完全有可能是第一个注意到被成千上万用户反复使用的系统调用与函数库文件有明显缺陷的人，更有可能的是你完全没有根据。不同凡响的说法需要不同凡响的证据，当你这样声称时，你必须有清楚而详尽的缺陷说明文件作后盾。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q8&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我在安装 Linux（或者 X ）时有问题，你能帮我吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：不能，我只有亲自在你的电脑上动手才能找到毛病。还是去找你当地的 Linux 使用群组者寻求实际的指导吧（你能在&lt;a href=&quot;http://www.linux.org/groups/index.html&quot;&gt;这儿&lt;/a&gt;找到用户群组的清单）。&lt;/p&gt;
&lt;p&gt;注意：如果安装问题与某 Linux 的发行版有关，在它的邮件列表、论坛或本地用户群组中提问也许是恰当的。此时，应描述问题的准确细节。在此之前，先用 &lt;code&gt;Linux&lt;/code&gt; 和&lt;strong&gt;所有&lt;/strong&gt;被怀疑的硬件作关键词仔细搜索。&lt;/p&gt;
&lt;p&gt;&amp;lt;a id=&quot;q9&quot; tabindex=&quot;-1&quot; style=&quot;width:0; height:0; overflow:hidden; display:block;&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;问题：我怎么才能破解 root 帐号/窃取 OP 特权/读别人的邮件呢？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;回答：想要这样做，说明了你是个卑鄙小人；想找个黑客帮你，说明你是个白痴！&lt;/p&gt;
&lt;h1&gt;好问题与蠢问题&lt;/h1&gt;
&lt;p&gt;最后，我将透过举一些例子，来说明怎样聪明的提问；同一个问题的两种问法被放在一起，一种是愚蠢的，另一种才是明智的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蠢问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我可以在哪儿找到关于 Foonly Flurbamatic 的资料？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这种问法无非想得到 &lt;a href=&quot;#RTFM&quot;&gt;STFW&lt;/a&gt; 这样的回答。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;聪明问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我用 Google 搜索过 &quot;Foonly Flurbamatic 2600&quot;，但是没找到有用的结果。谁知道上哪儿去找对这种设备编程的资料？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个问题已经 STFW 过了，看起来他真的遇到了麻烦。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蠢问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我从 foo 项目找来的源码没法编译。它怎么这么烂？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;他觉得都是别人的错，这个傲慢自大的提问者。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;聪明问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;foo 项目代码在 Nulix 6.2 版下无法编译通过。我读过了 FAQ，但里面没有提到跟 Nulix 有关的问题。这是我编译过程的记录，我有什么做的不对的地方吗？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;提问者已经指明了环境，也读过了 FAQ，还列出了错误，并且他没有把问题的责任推到别人头上，他的问题值得被关注。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蠢问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我的主机板有问题了，谁来帮我？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;某黑客对这类问题的回答通常是：&lt;code&gt;好的，还要帮你拍拍背和换尿布吗？&lt;/code&gt;，然后按下删除键。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;聪明问题&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我在 S2464 主机板上试过了 X 、 Y 和 Z ，但没什么作用，我又试了 A 、 B 和 C 。请注意当我尝试 C 时的奇怪现象。显然 florbish 正在 grommicking，但结果出人意料。通常在 Athlon MP 主机板上引起 grommicking 的原因是什么？有谁知道接下来我该做些什么测试才能找出问题？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这个家伙，从另一个角度来看，值得去回答他。他表现出了解决问题的能力，而不是坐等天上掉答案。&lt;/p&gt;
&lt;p&gt;在最后一个问题中，注意&lt;code&gt;告诉我答案&lt;/code&gt;和&lt;code&gt;给我启示，指出我还应该做什么诊断工作&lt;/code&gt;之间微妙而又重要的区别。&lt;/p&gt;
&lt;p&gt;事实上，后一个问题源自于 2001 年 8 月在 Linux 内核邮件列表（lkml）上的一个真实的提问。我（Eric）就是那个提出问题的人。我在 Tyan S2464 主板上观察到了这种无法解释的锁定现象，列表成员们提供了解决这一问题的重要信息。&lt;/p&gt;
&lt;p&gt;通过我的提问方法，我给了别人可以咀嚼玩味的东西；我设法让人们很容易参与并且被吸引进来。我显示了自己具备和他们同等的能力，并邀请他们与我共同探讨。通过告诉他们我所走过的弯路，以避免他们再浪费时间，我也表明了对他们宝贵时间的尊重。&lt;/p&gt;
&lt;p&gt;事后，当我向每个人表示感谢，并且赞赏这次良好的讨论经历的时候，一个 Linux 内核邮件列表的成员表示，他觉得我的问题得到解决并非由于我是这个列表中的&lt;strong&gt;名&lt;/strong&gt;人，而是因为我用了正确的方式来提问。&lt;/p&gt;
&lt;p&gt;黑客从某种角度来说是拥有丰富知识但缺乏人情味的家伙；我相信他是对的，如果我&lt;strong&gt;像&lt;/strong&gt;个乞讨者那样提问，不论我是谁，一定会惹恼某些人或者被他们忽视。他建议我记下这件事，这直接导致了本指南的出现。&lt;/p&gt;
&lt;h1&gt;如果得不到回答&lt;/h1&gt;
&lt;p&gt;如果仍得不到回答，请不要以为我们觉得无法帮助你。有时只是看到你问题的人不知道答案罢了。没有回应不代表你被忽视，虽然不可否认这种差别很难区分。&lt;/p&gt;
&lt;p&gt;总的来说，简单地重复张贴问题是个很糟的点子。这将被视为无意义的喧闹。有点耐心，知道你问题答案的人可能生活在不同的时区，可能正在睡觉，也有可能你的问题一开始就没有组织好。&lt;/p&gt;
&lt;p&gt;你可以通过其他渠道获得帮助，这些渠道通常更适合初学者的需要。&lt;/p&gt;
&lt;p&gt;有许多网上的以及本地的用户群组，由热情的软件爱好者（即使他们可能从没亲自写过任何软件）组成。通常人们组建这样的团体来互相帮助并帮助新手。&lt;/p&gt;
&lt;p&gt;另外，你可以向很多商业公司寻求帮助，不论公司大还是小。别为要付费才能获得帮助而感到沮丧！毕竟，假使你的汽车发动机汽缸密封圈爆掉了 —— 完全可能如此 —— 你还得把它送到修车铺，并且为维修付费。就算软件没花费你一分钱，你也不能强求技术支持总是免费的。&lt;/p&gt;
&lt;p&gt;对像是 Linux 这种大众化的软件，每个开发者至少会对应到上万名用户。根本不可能由一个人来处理来自上万名用户的求助电话。要知道，即使你要为这些协助付费，和你所购买的同类软件相比，你所付出的也是微不足道的（通常封闭源代码软件的技术支持费用比开源软件的要高得多，且内容也没那么丰富）。&lt;/p&gt;
&lt;h1&gt;如何更好地回答问题&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;态度和善一点。&lt;/strong&gt; 问题带来的压力常使人显得无礼或愚蠢，其实并不是这样。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;对初犯者私下回复。&lt;/strong&gt; 对那些坦诚犯错之人没有必要当众羞辱，一个真正的新手也许连怎么搜索或在哪找常见问题都不知道。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果你不确定，一定要说出来！&lt;/strong&gt; 一个听起来权威的错误回复比没有还要糟，别因为听起来像个专家很好玩，就给别人乱指路。要谦虚和诚实，给提问者与同行都树个好榜样。&lt;/p&gt;
&lt;p&gt;:::warning
&lt;a href=&quot;#LLM&quot;&gt;不要使用 LLM 不懂装懂！&lt;/a&gt;
:::&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果帮不了忙，也别妨碍他。&lt;/strong&gt; 不要在实际步骤上开玩笑，那样也许会毁了提问者的设置 —— 有些可怜的呆瓜会把它当成真的指令。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;试探性的反问以引出更多的细节。&lt;/strong&gt; 如果你做得好，提问者可以学到点东西 —— 你也可以。试试将蠢问题转变成好问题，别忘了我们都曾是新手。&lt;/p&gt;
&lt;p&gt;尽管对那些懒虫抱怨一声 RTFM 是正当的，但能给出文档的链接（即使只是建议个 Google 搜索关键词）会更好。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果你决定回答，就请给出好的答案。&lt;/strong&gt; 当别人正在用错误的工具或方法时别建议笨拙的权宜之计（workaround），应推荐更好的工具，重新界定问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正面地回答问题！&lt;/strong&gt; 如果这个提问者已经很深入的研究而且也表明已经试过 X 、 Y 、 Z 、 A 、 B 、 C 但没得到结果，回答 &lt;code&gt;试试看 A 或是 B&lt;/code&gt; 或者 &lt;code&gt;试试 X 、 Y 、 Z 、 A 、 B 、 C&lt;/code&gt; 并附上一个链接一点用都没有。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;帮助你的社区从问题中学习。&lt;/strong&gt; 当回复一个好问题时，问问自己&lt;code&gt;如何修改相关文件或常见问题文件以免再次解答同样的问题？&lt;/code&gt;，接着再向文件维护者发一份补丁。&lt;/p&gt;
&lt;p&gt;如果你在研究一番后才作出了回答，&lt;strong&gt;展现你的技巧而不是直接端出结果&lt;/strong&gt;。毕竟&lt;code&gt;授人以鱼不如授人以渔&lt;/code&gt;。&lt;/p&gt;
&lt;h1&gt;相关资源&lt;/h1&gt;
&lt;p&gt;如果你需要个人电脑、Unix 系统和网络如何运作的基础知识，参阅 &lt;a href=&quot;http://en.tldp.org/HOWTO/Unix-and-Internet-Fundamentals-HOWTO/&quot;&gt;Unix 系统和网络基本原理&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当你发布软件或补丁时，试着按&lt;a href=&quot;http://en.tldp.org/HOWTO/Software-Release-Practice-HOWTO/index.html&quot;&gt;软件发布实践&lt;/a&gt;操作。&lt;/p&gt;
&lt;h1&gt;鸣谢&lt;/h1&gt;
&lt;p&gt;Evelyn Mitchel 贡献了一些愚蠢问题例子并启发了编写&lt;code&gt;如何更好地回答问题&lt;/code&gt;这一节， Mikhail Ramendik 贡献了一些特别有价值的建议和改进。&lt;/p&gt;
</content:encoded></item><item><title>写 C 时遇到的一个小问题</title><link>https://sakimidare.top/posts/a-problem-during-c-programming/</link><guid isPermaLink="true">https://sakimidare.top/posts/a-problem-during-c-programming/</guid><description>数组越界不报错？有点意思</description><pubDate>Sat, 23 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;起因&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int main(void)
{
    int sum = 0, i = 0;
    char input[5];

    while (1) {
        sum = 0;
        scanf(&quot;%s&quot;, input);
        for (i = 0; input[i] != &apos;\0&apos;; i++)
            sum = sum*10 + input[i] - &apos;0&apos;;
        printf(&quot;input=%d\n&quot;, sum);
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在浏览&lt;a href=&quot;https://akaedu.github.io/book/ch10s03.html&quot;&gt;Linux C编程一站式学习 第十章 gdb 3. 观察点&lt;/a&gt; 时遇到了上述代码。这段代码目的很简单：把从输入设备输入的整数字符串转换为整数并输出。原文采用了以下调试步骤发现了问题：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ./main
123
input=123
67
input=67
12345
input=123407
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原文的解释是：在内存中，局部变量&lt;code&gt;i&lt;/code&gt;紧跟在&lt;code&gt;input[4]&lt;/code&gt;后，所以&lt;code&gt;input[5]&lt;/code&gt;指的就是局部变量&lt;code&gt;i&lt;/code&gt;。而从键盘输入了&lt;code&gt;12345&lt;/code&gt;，分别给&lt;code&gt;input&lt;/code&gt;的各个元素赋值，便成了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;input[0] = &apos;1&apos;;
input[1] = &apos;2&apos;;
input[2] = &apos;3&apos;;
input[3] = &apos;4&apos;;
input[4] = &apos;5&apos;;
i = &apos;\0&apos;;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的 &lt;code&gt;i&lt;/code&gt; 被赋值为 &lt;code&gt;&apos;\0&apos;&lt;/code&gt;，因为键盘读取了一行字符串，而字符串以&lt;code&gt;&apos;\0&apos;&lt;/code&gt;结尾。C 语言的&lt;code&gt;scanf()&lt;/code&gt;函数不会读取空白字符，所以末尾不包含&lt;code&gt;\n&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;注意到：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for (i = 0; input[i] != &apos;\0&apos;; i++)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;for&lt;/code&gt;循环的控制条件是&lt;code&gt;input[i] != &apos;\0&apos;&lt;/code&gt;，而这个数组并不包含&lt;code&gt;&apos;\0&apos;&lt;/code&gt;，因此出现了访问越界的情况。&lt;/p&gt;
&lt;p&gt;原文使用了 GDB 调试，部分调试信息如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;(gdb) n
11			for (i = 0; input[i] != &apos;\0&apos;; i++)
(gdb) p sum
$3 = 12345
(gdb) n
12				sum = sum*10 + input[i] - &apos;0&apos;;
(gdb) x/7b input
0xbfb8f0a7:	0x31	0x32	0x33	0x34	0x35	0x05	0x00
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;i&lt;/code&gt;后面一个地址位置的值是&lt;code&gt;0x00&lt;/code&gt;，因此最后一次循环执行了 &lt;code&gt;12345*10 + 0x05 - &apos;\0&apos;&lt;/code&gt;，得到了 &lt;code&gt;123407&lt;/code&gt; 。&lt;/p&gt;
&lt;p&gt;然而，事情真的有这么简单吗？&lt;/p&gt;
&lt;h1&gt;发现问题&lt;/h1&gt;
&lt;p&gt;我在使用 CLion 调试上述代码，正常得很！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;12345
input=12345
114514
input=114514
1919810
input=1919810
^C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;怎么回事呢？&lt;/p&gt;
&lt;p&gt;看了一眼原文的上一页，发现原作者是这么编译运行的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc main.c -g -o main
$ ./main 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;行吧，我也这么办。&lt;/p&gt;
&lt;p&gt;？&lt;/p&gt;
&lt;p&gt;怪事，一切正常啊。难道这个 bug 这么没有鲁棒性？&lt;/p&gt;
&lt;p&gt;这时我有点摸不着头脑，看一眼我的 GCC 和 Linux 版本：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ uname -a
Linux sakimidare-arch 6.16.2-arch1-1 #1 SMP PREEMPT_DYNAMIC Wed, 20 Aug 2025 21:43:45 +0000 x86_64 GNU/Linux

$ gcc --version
gcc (GCC) 15.2.1 20250813
Copyright © 2025 Free Software Foundation, Inc.
本程序是自由软件；请参看源代码的版权声明。本软件没有任何担保；
包括没有适销性和某一专用目的下的适用性担保。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好嘛，再试试其他编译器呢？总不会这个 Bug 到现代机器上不复存在了吧……&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ clang main.c -o main
$ ./main
12345
input=123407
666666
input=666617
123456789
input=123407
114514
input=114467
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;问题出现了！有时出错的代码比正确而不可靠的代码更有意义。&lt;/p&gt;
&lt;p&gt;经常听到有人调侃道：代码跑起来就不要去管它了。这似乎是生产环境下的无奈之举。毕竟人是要吃饭的，谁也不可能抱着一段正常运行的代码研究一辈子。如果把时间全用来研究一段代码，程序带来的效率收益与投入的时间成本相比可能并不划算。&lt;/p&gt;
&lt;p&gt;但与生产不一样的是，我们是在学习。在学习一门语言，理解一门语言时如果不深入了解每一行代码的意义，用“程序跑起来就不用管它”来麻痹自己，那么程序里必然有我们发现不了的隐患，生产中有所谓“我这边能跑啊，你那边环境没配对吧”的借口，学习中有知其然而不知其所以然的糟糕态度。&lt;/p&gt;
&lt;p&gt;这些看似微不足道的怠惰悄悄构成了思维上的不完备，让我们不习惯于全面地研究问题。长年累月下去，只会追悔莫及。&lt;/p&gt;
&lt;h1&gt;为什么会这样？&lt;/h1&gt;
&lt;p&gt;好了好了扯远啦，我们来看看为什么这两种编译器编译出来的程序有不同的行为。&lt;/p&gt;
&lt;p&gt;我们知道，从一个 &lt;code&gt;.c&lt;/code&gt; 源代码文件到可执行程序共分为四步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;预处理 (Preprocessing)&lt;/li&gt;
&lt;li&gt;编译 (Compilation)&lt;/li&gt;
&lt;li&gt;汇编 (Assembling)&lt;/li&gt;
&lt;li&gt;链接 (Linking)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;0. 预处理&lt;/h2&gt;
&lt;p&gt;预处理是指&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;处理 &lt;code&gt;#include&lt;/code&gt; 展开头文件；&lt;/li&gt;
&lt;li&gt;处理 &lt;code&gt;#define&lt;/code&gt; 替换宏；&lt;/li&gt;
&lt;li&gt;处理条件编译指令 &lt;code&gt;#if&lt;/code&gt; &lt;code&gt;#ifdef&lt;/code&gt; &lt;code&gt;#ifndef&lt;/code&gt;；&lt;/li&gt;
&lt;li&gt;删除注释。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;用 &lt;code&gt;gcc&lt;/code&gt; 和 &lt;code&gt;clang&lt;/code&gt; 分别预处理这个 &lt;code&gt;main.c&lt;/code&gt;，看看生成的预处理文件有什么不一样吧！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -E main.c -o gcc.i
$ clang -E main.c -o clang.i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;发现&lt;code&gt;main()&lt;/code&gt;函数部分代码一样，都是：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int main(void)
{
    int sum = 0, i = 0;
    char input[5];

    while (1) {
        sum = 0;
        scanf(&quot;%s&quot;, input);
        for (i = 0; input[i] != &apos;\0&apos;; i++)
            sum = sum*10 + input[i] - &apos;0&apos;;
        printf(&quot;input=%d\n&quot;, sum);
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这也符合我们的认知，因为预处理只是进行了替换操作，不涉及修改函数的逻辑。&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;main()&lt;/code&gt;上方有八百多行代码，两个编译器处理后的文件不一样。不过我们先不去管它，因为这个问题出现的主要原因是 &lt;code&gt;input&lt;/code&gt; 数组和 &lt;code&gt;i&lt;/code&gt; 的位置相邻。根据我们的直觉，问题不在头文件。&lt;/p&gt;
&lt;p&gt;先把这两个文件放在一边，我们继续。&lt;/p&gt;
&lt;h2&gt;1. 编译&lt;/h2&gt;
&lt;p&gt;:::note
此处的汇编语言是 x86-64 GNU 汇编语言，Windows 无法直接运行。
:::&lt;/p&gt;
&lt;p&gt;编译是指把预处理后的 C 代码翻译成汇编代码。这一步包括语法检查、语义分析、优化等，于是我们有理由怀疑编译器在这一步做了不一样的操作，导致汇编逻辑不一样。&lt;/p&gt;
&lt;p&gt;出发吧！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -S gcc.i -o gcc.s
$ clang -S clang.i -o clang.s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;把这两个文件都贴出来：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	.file	&quot;main.c&quot;
	.text
	.section	.rodata
.LC0:
	.string	&quot;%s&quot;
.LC1:
	.string	&quot;input=%d\n&quot;
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$32, %rsp
	movq	%fs:40, %rax
	movq	%rax, -8(%rbp)
	xorl	%eax, %eax
	movl	$0, -24(%rbp)
	movl	$0, -20(%rbp)
.L4:
	movl	$0, -24(%rbp)
	leaq	-13(%rbp), %rax
	leaq	.LC0(%rip), %rdx
	movq	%rax, %rsi
	movq	%rdx, %rdi
	movl	$0, %eax
	call	__isoc23_scanf@PLT
	movl	$0, -20(%rbp)
	jmp	.L2
.L3:
	movl	-24(%rbp), %edx
	movl	%edx, %eax
	sall	$2, %eax
	addl	%edx, %eax
	addl	%eax, %eax
	movl	%eax, %edx
	movl	-20(%rbp), %eax
	cltq
	movzbl	-13(%rbp,%rax), %eax
	movsbl	%al, %eax
	addl	%edx, %eax
	subl	$48, %eax
	movl	%eax, -24(%rbp)
	addl	$1, -20(%rbp)
.L2:
	movl	-20(%rbp), %eax
	cltq
	movzbl	-13(%rbp,%rax), %eax
	testb	%al, %al
	jne	.L3
	movl	-24(%rbp), %eax
	leaq	.LC1(%rip), %rdx
	movl	%eax, %esi
	movq	%rdx, %rdi
	movl	$0, %eax
	call	printf@PLT
	jmp	.L4
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	&quot;GCC: (GNU) 15.2.1 20250813&quot;
	.section	.note.GNU-stack,&quot;&quot;,@progbits
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;	.file	&quot;main.c&quot;
	.text
	.globl	main                            # -- Begin function main
	.p2align	4
	.type	main,@function
main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp
	movl	$0, -4(%rbp)
	movl	$0, -8(%rbp)
	movl	$0, -12(%rbp)
.LBB0_1:                                # =&amp;gt;This Loop Header: Depth=1
                                        #     Child Loop BB0_2 Depth 2
	movl	$0, -8(%rbp)
	leaq	-17(%rbp), %rsi
	leaq	.L.str(%rip), %rdi
	movb	$0, %al
	callq	__isoc99_scanf@PLT
	movl	$0, -12(%rbp)
.LBB0_2:                                #   Parent Loop BB0_1 Depth=1
                                        # =&amp;gt;  This Inner Loop Header: Depth=2
	movslq	-12(%rbp), %rax
	movsbl	-17(%rbp,%rax), %eax
	cmpl	$0, %eax
	je	.LBB0_5
# %bb.3:                                #   in Loop: Header=BB0_2 Depth=2
	imull	$10, -8(%rbp), %eax
	movslq	-12(%rbp), %rcx
	movsbl	-17(%rbp,%rcx), %ecx
	addl	%ecx, %eax
	subl	$48, %eax
	movl	%eax, -8(%rbp)
# %bb.4:                                #   in Loop: Header=BB0_2 Depth=2
	movl	-12(%rbp), %eax
	addl	$1, %eax
	movl	%eax, -12(%rbp)
	jmp	.LBB0_2
.LBB0_5:                                #   in Loop: Header=BB0_1 Depth=1
	movl	-8(%rbp), %esi
	leaq	.L.str.1(%rip), %rdi
	movb	$0, %al
	callq	printf@PLT
	jmp	.LBB0_1
.Lfunc_end0:
	.size	main, .Lfunc_end0-main
	.cfi_endproc
                                        # -- End function
	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,&quot;aMS&quot;,@progbits,1
.L.str:
	.asciz	&quot;%s&quot;
	.size	.L.str, 3

	.type	.L.str.1,@object                # @.str.1
.L.str.1:
	.asciz	&quot;input=%d\n&quot;
	.size	.L.str.1, 10

	.ident	&quot;clang version 20.1.8&quot;
	.section	&quot;.note.GNU-stack&quot;,&quot;&quot;,@progbits
	.addrsig
	.addrsig_sym __isoc99_scanf
	.addrsig_sym printf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来看看&lt;code&gt;gcc.s&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.LFB0:
  .cfi_startproc
  pushq  %rbp
  .cfi_def_cfa_offset 16
  .cfi_offset 6, -16
  movq  %rsp, %rbp
  .cfi_def_cfa_register 6
  subq  $32, %rsp           # 预留 32 字节栈帧给局部变量
  movq  %fs:40, %rax
  movq  %rax, -8(%rbp)
  xorl  %eax, %eax
  movl  $0, -24(%rbp)       # sum = 0;
  movl  $0, -20(%rbp)       # i = 0;
.L4:
  movl	$0, -24(%rbp)       # sum = 0;
  leaq	-13(%rbp), %rax     # input[0] 的位置在-13(%rbp)
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再看看&lt;code&gt;clang.s&lt;/code&gt;是如何处理的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main:                                   # @main
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	subq	$32, %rsp       # 预留 32 字节栈帧给局部变量
	movl	$0, -4(%rbp)    # 返回值临时保留位，本程序未使用
	movl	$0, -8(%rbp)    # sum = 0;
	movl	$0, -12(%rbp)   # i = 0;
.LBB0_1:                                # =&amp;gt;This Loop Header: Depth=1
                                        #     Child Loop BB0_2 Depth 2
	movl	$0, -8(%rbp)    # sum = 0;
	leaq	-17(%rbp), %rsi # input[0] 的位置在-17(%rbp)
    ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好啦，这下就清楚了！&lt;/p&gt;
&lt;p&gt;我们来画一下栈：&lt;/p&gt;
&lt;h3&gt;GCC 栈&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;变量&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-9&lt;/td&gt;
&lt;td&gt;input[4]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-10&lt;/td&gt;
&lt;td&gt;input[3]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-11&lt;/td&gt;
&lt;td&gt;input[2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-12&lt;/td&gt;
&lt;td&gt;input[1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-13&lt;/td&gt;
&lt;td&gt;input[0]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-20&lt;/td&gt;
&lt;td&gt;i&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-24&lt;/td&gt;
&lt;td&gt;sum&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Clang 栈&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;位置&lt;/th&gt;
&lt;th&gt;变量&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;-8&lt;/td&gt;
&lt;td&gt;sum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-12&lt;/td&gt;
&lt;td&gt;i&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-13&lt;/td&gt;
&lt;td&gt;input[4]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-14&lt;/td&gt;
&lt;td&gt;input[3]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-15&lt;/td&gt;
&lt;td&gt;input[2]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-16&lt;/td&gt;
&lt;td&gt;input[1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;-17&lt;/td&gt;
&lt;td&gt;input[0]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此，我们得出了结论：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GCC为&lt;code&gt;i&lt;/code&gt;和&lt;code&gt;input[0]&lt;/code&gt;之间留足了栈帧，并且&lt;code&gt;input[4]&lt;/code&gt;之后也没有变量可以影响循环，因此没出问题。&lt;/strong&gt;
&lt;strong&gt;而Clang让&lt;code&gt;input[4]&lt;/code&gt;和&lt;code&gt;i&lt;/code&gt;紧靠在一起，增加了数组越界的风险。&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;2. 汇编&lt;/h2&gt;
&lt;h2&gt;3. 链接&lt;/h2&gt;
&lt;p&gt;哎呀这两个标题和本文没关系，加上只是为了目录更好看（&lt;/p&gt;
&lt;h1&gt;验证猜想&lt;/h1&gt;
&lt;p&gt;我们用 GCC 看看&lt;code&gt;input[-7]&lt;/code&gt;？按道理就是&lt;code&gt;i&lt;/code&gt;了吧！
修改程序为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

int main(void)
{
    int sum = 0, i = 0;
    char input[5];

    while (1) {
        sum = 0;
        scanf(&quot;%s&quot;, input);
        for (i = 0; input[i] != &apos;\0&apos;; i++)
            sum = sum*10 + input[i] - &apos;0&apos;;
        printf(&quot;input=%d\n&quot;, sum);
        printf(&quot;%d\n&quot;, input[-7]);
    }
    return 0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;运行程序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc test.c -o test
$ ./test
12345
input=12345
5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;大功告成！&lt;strong&gt;果然，&lt;code&gt;input[-7]&lt;/code&gt; 就是 &lt;code&gt;i&lt;/code&gt;！&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;如何规避风险？&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;-O0&lt;/code&gt;了吗？&lt;code&gt;-fsanitize=address&lt;/code&gt;了吗？快加上！&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;一位群友如是说。
好吧好吧，我们加上这两个参数再编译一次试试：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ gcc -O0 -fsanitize=address test.c -o test
$ ./test
1234567
=================================================================
==16748==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7b4c18f00025 at pc 0x7f4c1ba6e51d bp 0x7ffdce2744c0 sp 0x7ffdce273c48
WRITE of size 8 at 0x7b4c18f00025 thread T0
    #0 0x7f4c1ba6e51c in scanf_common /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc:342
    #1 0x7f4c1ba8edee in __isoc23_vscanf /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1554
    #2 0x7f4c1ba8f5f5 in __isoc23_scanf /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1584
    #3 0x564e475b9254 in main (/home/sakimidare/CLionProjects/c_study/test+0x1254) (BuildId: 35fabe8824d13d3c1ca4e2836107a3b16992a4a9)
    #4 0x7f4c1b627674  (/usr/lib/libc.so.6+0x27674) (BuildId: 4fe011c94a88e8aeb6f2201b9eb369f42b4a1e9e)
    #5 0x7f4c1b627728 in __libc_start_main (/usr/lib/libc.so.6+0x27728) (BuildId: 4fe011c94a88e8aeb6f2201b9eb369f42b4a1e9e)
    #6 0x564e475b90d4 in _start (/home/sakimidare/CLionProjects/c_study/test+0x10d4) (BuildId: 35fabe8824d13d3c1ca4e2836107a3b16992a4a9)

Address 0x7b4c18f00025 is located in stack of thread T0 at offset 37 in frame
    #0 0x564e475b91b8 in main (/home/sakimidare/CLionProjects/c_study/test+0x11b8) (BuildId: 35fabe8824d13d3c1ca4e2836107a3b16992a4a9)

  This frame has 1 object(s):
    [32, 37) &apos;input&apos; (line 6) &amp;lt;== Memory access at offset 37 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/sakimidare/CLionProjects/c_study/test+0x1254) (BuildId: 35fabe8824d13d3c1ca4e2836107a3b16992a4a9) in main
Shadow bytes around the buggy address:
  0x7b4c18effd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18effe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18effe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18efff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18efff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=&amp;gt;0x7b4c18f00000: f1 f1 f1 f1[05]f3 f3 f3 00 00 00 00 00 00 00 00
  0x7b4c18f00080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18f00100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18f00180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18f00200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x7b4c18f00280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==16748==ABORTING
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;看得出来，加上参数确实有助于规避数组越界风险。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不过，最有效的方法还是事先考虑好所有情况，防范任何可能出现的 Bug！&lt;/strong&gt;&lt;s&gt;（酒吧点炒饭.txt）&lt;/s&gt;&lt;/p&gt;
&lt;h1&gt;写在最后&lt;/h1&gt;
&lt;p&gt;这是我第一次写这种类型的文章，算是对自己独立解决问题能力的一次检验吧！&lt;/p&gt;
&lt;p&gt;&lt;s&gt;也不知道会不会有人看这篇文章，当作日记得了。&lt;/s&gt; 如果有人看到这里，感谢大家阅读！&lt;/p&gt;
</content:encoded></item><item><title>Hello World! 梦开始的地方</title><link>https://sakimidare.top/posts/hello-world/</link><guid isPermaLink="true">https://sakimidare.top/posts/hello-world/</guid><description>第一篇文章！</description><pubDate>Fri, 22 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;也算是把站给搭起来了，这是这个博客的第一篇文章 &lt;s&gt;（也不能算是文章就是了）&lt;/s&gt; ！&lt;/p&gt;
&lt;p&gt;大家现在看到的是我把五年的黑历史删掉后重建的站。高中三年过去了，人生站在新起点上，博客也得站在新起点不是吗？希望在这里能写下真正有用的东西，无论是对自己还是对他人。&lt;/p&gt;
&lt;p&gt;当个日记本也好，当个什么其他奇怪的小站也好，总之这是一个梦开始的地方，欢迎大家！&lt;/p&gt;
&lt;p&gt;&lt;s&gt;（我怎么语无伦次的）&lt;/s&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>