macOS 汇编

十进制与二进制的相互转换 十进制转为二进制,分为整数部分和小数部分 整数部分采用除 2 倒取余法: 用2去除十进制整数,可以得到一个商和余数;在用2去除商,又会得到一个商和余数,如此进行,知道商为0时为止,然后把先的到的余数作为二进制的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来。 小数部分采用乘2取整法,具体做法:用2乘十进制小数,可以得到积,将积中的整数部分取出,在用2乘余下的小数部分,又得到一个积,在将积中的整数部分取出,如此进行,直到积中的小数部分为0,此时0或1为二进制的最后一位,或者达到所要求的精度为止,然后把取出的整数部分按顺序排列起来,先取得整数作为二进制小数的最高位有效位,后取的整数作为低位有效位。 二进制转为十进制 按权相加法,即将二进制每位上的数乘以权,然后相加之和即是十进制数 预备知识 由于计算机的硬件决定,任何存储于计算机中的数据,其本质都是以二进制码存储。 根据冯·诺依曼提出的经典计算机体系结构框架,一台计算机由运算器、控制器、存储器、输入和输出设备组成。其中运算器只有加法运算器,没有减法运算器(据说一开始是有的,后来由于减法运算器硬件开销太大,被废了)。 所以计算机中没办法直接做减法的,它的减法是通过加法实现的。现实世界中所有的减法也可以当成加法的,减去一个数可以看作加上这个数的相反数,但前提是要先有负数的概念,这就是为什么不得不引入一个符号位。符号位在内存中存放的最左边一位,如果该位为0,则说明该数为正;若为1,则说明该数为负。 而且从硬件的角度上看,只有正数加负数才算减法,正数与正数相加,负数与负数相加,其实都可以通过加法器直接相加。 原码、反码、补码的产生过程就是为了解决计算机做减法和引入符号位的问题。 原码 原码:是最简单的机器数表示法,用最高位表示符号位,其他位存放该数的二进制的绝对值。 以带符号位的四位二进制数为例:1010,最高位为1表示这是一个负数,其它三位010,即02^2+12^1+0*2^0=2,所以1010表示十进制数-2。 正数 负数 0 0000 -0 1000 1 0001 -1 1001 2 0010 -2 1010 3 0011 -3 1011 4 0100 -4 1100 5 0101 -5 1101 6 0110 -6 1110 7 0111 -7 1111 原码的表示法很简单,虽然出现了+0和-0,但是直观易懂。于是开始运算 — 0001 + 0010 = 0011, 1+2=3; 0000 + 1000= 1000, +0+(-0)=-0; 0001 + 1001=1010, 1+(-1)=-2 ...

April 9, 2026 · 4 min · Theme PaperMod

汇编入门

# exit.s .section __TEXT, __text .globl _main _main: mov1 $0, %rax retq 注释 程序的第一行是注释。在macOS的as汇编器语法下,注释由#开头,在进行汇编的时候会自动将其处理为空白字符。 我们习惯上将注释写在语句的上方(如例程)或后方,如: movq $0, %rax # mov 0 to register rax 缩进 在最古老的机器上,汇编代码的文本包含四列:标签、助记符、操作数与注释。汇编器通过识别一个文本在哪个列来判断该文本有什么作用。现代的汇编器已经抛弃了这种方法,采用先进的词法分析技术来判断。但是,我们最好仍然按照这种格式来缩进。 汇编器指令(Directive) “Directive"是汇编语言中一个重要的组成部分,然而它的中文译名似乎还不固定,这里暂且叫它汇编器指令。在汇编语言中,以.开头的都是汇编器指令,如例程中的.section, .globl等。由汇编器指令开头的语句,一般不会被直接翻译成机器码。汇编器指令并不是告诉汇编器做什么, 而是告诉汇编器如何做。就比如说例程中,movq $0, %rax 会被汇编器直接翻译为机器码,最终会由CPU直接执行,而.section __TEXT,__text, 则不会被翻译成机器码,在最终的可执行文件中也不会找到这句话的踪影。它的作用是告诉汇编器如何汇编。下面,就介绍一下.section的作用 .section 我们之前在操作系统基础中提到,mach-o可执行文件的Data部分拥有许多段(Segment), 每个段又有许多节(section). 同一个段的作用往往是类似的,同时在执行的时候一个段会被分配到一个页之中。而.section最常用的格式,就是 .section segname, sectname 其中segment是段名,sectname是节名。我们目前编写的第一个汇编语言程序,只包含纯代码。在macho中,纯代码被放在了__TEXT段的__text节中,因此,我们在文件的第二行写了 .section __TEXT, __text 代表之后的语句都是__TEXT段的__text节中。 此外,由于这个节过于常用,因此,汇编器给予了我们一个简单的记号:.text. 我们可以直接用.text代替.section __TEXT, __text. 在以后的程序中,我也都会用这种记号。 除了__TEXT段__text节后,还有许多段和节。常用的段和节的名称和作用可参见Assembler Directives. 我们之后更复杂的程序中也会用到更多的段和节。 .globl 我们在由汇编语言翻译机器码的时候,得到的文件并不仅仅包含操作的指令,还需要包含一些名字和记号。比如说,C语言中,程序执行的起点是main函数。那么,这个函数的名字main就要包含在文件中,使得程序执行的时候知道执行哪个函数。 _main macOS中,汇编语言程序执行的起点是_main函数。关于函数与下一行的_main:标签,我会在之后的文章中提到。是谁决定它叫这个名字的呢,是链接器。如果我们写的程序想把它主函数叫做_start, 那么只需要在链接的时候写上即可。 ld -e _start exit.o -L/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib -lSystem -o exit movq movq是我们遇到的第一个真正的指令。在汇编语言中,这种能直接翻译成机器码的指令被称作助记符(mnemonic). 之前我们也提到过,在GAS语法下,一条指令是助记符+源+目的,也就是说,它后面紧跟的是源操作数,然后是目的操作数。在x86-64架构下所有的可以被识别的助记符可以参考64-ia-32-architectures-software-developer-instruction-set-reference-manual, 但值得注意的是,这份官方的参考文档是用的Intel语法,我们只需要把源和目的颠倒过来看就行。 ...

April 9, 2026 · 2 min · Theme PaperMod

汇编语言

汇编语言 第一章: 基础知识 1.3 汇编语言的组成 汇编指令:机器码的助记符,有对应的机器码。 伪指令:没有对应的机器码,由编译器执行,计算机并不执行。 其它符号:如 + - * /等,由编译器识别,没有对应的机器码。 汇编语言的核心是汇编指令,它决定了汇编语言的特性。 小结(1.1~1.10) 1). 汇编指令是机器指令的助记符,同机器指令一一对应。 2). 每一种 CPU 都有自己的汇编指令集。 3). CPU 可以直接使用的信息在存储器中存放。 4). 在存储器中指令和数据没有任何区别,都是二进制信息。 5). 存储单元从零开始顺序编号。 6). 一个存储单元可以存储 8 个 bit,即 8 位二进制数。 7). 1Byte=8bit 1KB=1024B 1MB=1024KB 1GB=1024MB 8). 每一个 CPU 芯片都有许多管脚,这些管脚和总线相连。也可以说,这些管脚引出总线。一个 CPU 可以引出 3 种总线的宽度标志了这个 CPU 的不同方面的性能 地址总线的宽度决定了 CPU 的寻址能力 数据总线的宽度决定了 CPU 与其它器件进行数据传送时的一次数据传送量 控制总线的宽度决定了 CPU 对系统中其它器件的控制能力 检测点 1.1 (1) 1个CPU的寻址能力为8KB,那么他的地址总线的宽度为【 13 】。 (2) 1KB的存储器有 【 1024 】个存储单元。存储单元编号从【 0000 】到【 1023 】。 (3) 1KB的存储器可以存储【 1024 x 8 】个bit,【 1024 】个Byte。 (4) 1GB、1MB、1KB分别是【1024x1024x1024、1024x1024、1024 】Byte。 (5) 8080、8088、8026、80386的地址总线宽度分别为16根、20根、24根、32根,则他们的寻址能力分别为:【 64 】(KB)、【 1 】(MB)、【 16 】(MB)、【 4 】(GB)。 (6) 8080、8088、8086、8026、80386的数据总线宽度分别为8根、8根、16根、16根、32根。则它们一次可以传送的数据为:【 1 】(B)、【 1 】(B)、【 2 】(B)、【 2 】(B)、【 4 】(B)。 ...

April 9, 2026 · 6 min · Theme PaperMod