深入 C 语言和程序运行原理
于航
PayPal 技术专家
21121 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
深入 C 语言和程序运行原理
15
15
1.0x
00:00/00:00
登录|注册

课前热身|学习这门课前,你需要了解哪些知识?

REX
Displacement
SIB
ModR/M
MOV r/m, imm
MOV r, r/m
MOV r/m, r
思考题
指令集中的寄存器
汇编语言
常见数据量单位
分析汇编代码并计算寄存器eax的值
寄存器的读写
寄存器别名
x86-64架构下的通用目的寄存器
系统寄存器
状态寄存器
通用目的寄存器
高速存储器硬件
寄存器文件
机器指令中的信息
机器指令代码的组成结构
汇编指令的参数形式
通过观察汇编代码了解程序运行细节
不具备可移植性
使用助记符表示机器指令
低级编程语言
字节
总结
思考题
指令集中的寄存器
汇编语言
常见数据量单位
系统学习C语言前,先来个课前热身吧!

该思维导图由 AI 生成,仅供参考

你好,我是于航。
在我们正式进入到 C 语言课程的学习之前,为了帮助你更好地理解课程内容,我为你准备了一节基础知识讲解课。这是一节选学课,你可以根据自己的实际情况选择性学习。
在这一讲中,我会用通俗易懂的方式,为你介绍这门课中最常用的一些基础知识,分别是常见数据量单位、汇编语言,以及 CPU 指令集中涉及的不同类型的寄存器。如果你对这些内容还不太熟悉,那么通过这一讲,你可以对它们有一个大致的印象。我们后面的课程还会提到汇编指令或寄存器,我会视情况进行更加具体的讲解,帮你加深理解。

数据量单位:位、字节和字

位(bit)是计算机中最小的存储单位,每一个位可以存储一个二进制码值的 0 或 1。而字节(byte)则通常是由八个位组成的一个存储单元。在计算机中,字节是最小的可寻址单位,这意味着 CPU 在使用数据时,可以以字节为单位,为每一字节内存分配一个相应的独立地址。
位和字节是在我们的日常工作中最为常见的两个数据量概念,你应该很熟悉。不过,字(word)的概念就没有这么清晰了。字的大小并不固定,一个字的大小可能是 2 的幂次个位,比如 16 位、32 位,也有可能是 12 位、27 位等一些并不常见的大小。而这主要是因为字的概念与具体的处理器或硬件体系架构直接相关,它跟位、字节这种较为通用和统一的数据量概念并不相同。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入介绍了在学习C语言之前的重要基础知识,包括计算机基础知识、汇编语言和CPU指令集中的寄存器类型。作者首先解释了位、字节和字的概念,以及它们在计算机中的作用和区别。接着详细讲解了汇编语言的特点和使用方法,强调了汇编语言的低级特性和与具体平台的紧密关联。此外,还介绍了汇编语言中使用的助记符和不同参数形式的汇编指令。文章还指出了在x86-64平台上书写和解读汇编代码的方式,并解释了汇编指令与机器指令之间的对应关系。另外,文章还介绍了CPU指令集中的寄存器,包括通用目的寄存器、状态寄存器和系统寄存器等,并详细介绍了在汇编代码中如何使用这些寄存器。最后,文章提供了一个思考题,帮助读者巩固所学内容。整体而言,本文为读者提供了C语言学习前的重要基础知识,帮助他们更好地理解后续的课程内容。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入 C 语言和程序运行原理》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(28)

  • 最新
  • 精选
  • ZR2021
    置顶
    于老师,为啥main函数里的asm("movl $0x1, %eax");是将1给eax的,src 跟dst反过来了好像

    作者回复: 这又是一个好问题!其实这里我们在代码中使用的是 AT&T 的写法,是一种默认被编译器广泛支持的内联汇编写法。当然,我们也可以做适当的调整来使用 Intel 写法,比如这样: #include <stdio.h> int main(void) { register long num asm("rax") = 0x100000000; asm( ".intel_syntax noprefix \n\t" "mov eax, 1\n\t" // "mov ax, 1\n\t" ".att_syntax" ); printf("%ld\n", num); return 0; } 但这种方式的问题在于,对于某些汇编器可能没有很好的兼容性。

    2021-12-07
    2
    23
  • 继业(Adrian)
    quizz: ``` mov eax, 0x1 # 0b1 inc eax # 0b10 sub eax, 10 # 0b10 - 0b1010 = 0xfffffff8 xor eax, eax # 0xfffffff8 xor 0xfffffff8 = 0x00000000 add eax, 1 # 0x00000001 mul eax # 0x00000001 mul 0x00000001 = 0x00000001 ``` answer: 0x00000001 = 1

    作者回复: 完全正确!

    2021-12-12
    20
  • 糊糊
    请教老师, 文中 mov ebx, 1 ,它所对应的机器指令代码为二进制值 bb 01 00 00 00 ,问题有两个: 1、汇编助记符 mov 是如何被翻译为二进制的 ? 是通过在哪里查的表吗 ,如果是查的表,那表又存在哪里呢 2、 那根据机器码二进制能否推导出汇编代码呢?bb 01 00 00 00 ==》mov ebx, 1

    作者回复: 很好的问题! 第一个问题:每一个汇编指令都有其对应的组成结构,汇编器会根据助记符的名称进行相应的转换。具体的转换细节可以参考官方手册。比如对于 x86-64:https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html 第二个问题:二进制状态下的机器指令识别可以通过每个指令对应的 OpCode 字节进行切分,然后再根据相应的结构解析出整体指令的结构。

    2021-12-07
    3
    6
  • 验证重写64位寄存器低32位/低16位/低8位的代码中如果不是按照文中那样给寄存器赋值,而是任意赋值,建议大家将printf("%ld\n", num);改为printf("%lx\n", num);,输出16进制数,这样才能观察到正确的结果,否则输出10进制数,一开始没注意的话会发现结果很奇怪 思考题: xor eax, eax是异或,eax自己与自己异或应该为0 add eax, 1,相当于0x0+0x1=0x1 mul eax之后eax的结果应该还是0x1,不知道理论分析是否正确,汇编还不是很熟

    作者回复: 答案是正确的哈!

    2021-12-06
    5
  • dog_brother
    按老师的程序去执行,第一种(asm("movl $0x1, %eax");)结果是1,第二种(asm("movw $0x1, %ax");)结果是4294967297。 ============================== ```c #include <stdio.h> int main(void) { register long num asm("rax") = 0x100000000; asm("movl $0x1, %eax"); // 第一种 // asm("movw $0x1, %ax"); // 第二种 printf("%d\n", num); printf("%ld\n", num); printf("%X\n", num); return 0; } ``` 按我这段的代码去执行,第一种(movl)和第二种(movw)的执行结果都是 ```shell 1 2 2 ```

    作者回复: 关于这个问题我可以先给点提示,然后你再思考下看看。第一个提示就是把第一行 printf 中的 “%d” 改成 “%ld” 就可以输出正确的结果;第二个提示是 printf 的调用会影响寄存器 rax 的值。

    2021-12-07
    4
  • jack123
    xor eax,eax 相当于把eax置零了,最后+1,然后mul相乘 默认与eax相乘,最后还是为1

    作者回复: 没错!

    2021-12-07
    4
  • cc
    在 x86-64 架构下,CPU 指令集架构(ISA)中一共定义了 16 个通用目的寄存器,这些寄存器最大可以存放 4 个字,即 64 位长的数据。在汇编代码中 ---- x86-64 下一个字长不就 64bit 了吗,为什么这里说 「4 个字,即 64 位长的数据」

    作者回复: 这是一个很好的发现!我们修改了文章,稍后会更新。 简单来讲就是:字这个概念会在多个地方的多种不同场景下使用。而文中我们介绍的字实际上是指可以体现 CPU 硬件特征的那个字,我一般会称它为硬件字。而在 CPU 指令集中,字也被用来作为衡量数据大小的单位。x86 架构由于历史原因,会将指令集中出现的 WORD 定义为固定 16 位的大小。所以实际文中提到的 4 个字你可以理解为指令字,它的单位是 WORD,4 个字即对应 64 位大小。

    2021-12-08
    3
  • 琥珀·
    因为我的环境有 warning: overflow in conversion from 'long long int' to 'long int' 的告警,所以把 register long num 改成了 register long long num #include <stdio.h> int main(void) { register long long num asm("rax") = 0x100000000; asm("movl $0x1, %eax"); // asm("movw $0x1, %ax"); printf("%llx\n", num); return 0; } 不知道这样理解对不对: 当某个指令需要重写寄存器的低 16 位或低 8 位数据时,寄存器中其他位上的数据不会被修改。所以asm("movw $0x1, %ax") 不会修改rax的值,这时num输出的值为0x100000001 而当指令需要重写寄存器低 32 位的数据时,高 32 位的数据会被同时复位,即置零。所以 asm("movl $0x1, %eax") 会将 rax 的结果置零后再写入1,这时num输出的值为0x1。

    作者回复: 理解正确哈!

    2021-12-13
    2
  • eax = 1 eax = eax + 1 eax = eax - 10 异或操作令 eax = 0 eax = eax + 1 eax = eax * eax 最后eax = 1

    作者回复: 正解!

    2021-12-12
    2
  • 傻猫周大福
    在clang下,rax寄存器虽然被置位,但在此之前会将rax寄存器的值拷贝到栈中,在输出时不会把被置位后的rax输出,而是从栈中重新取出num的值

    作者回复: 这是一个很好的发现!

    2021-12-11
    3
    2
收起评论
显示
设置
留言
28
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部