Linux Debugging 4 - Primer on PC Architecture

本文介绍了汇编语言的基础知识,包括通用寄存器、堆栈寄存器等概念,并探讨了不同位数系统下的寄存器扩展。此外,还详细讲解了进程内存空间分布、虚拟内存的工作原理、物理地址扩展(PAE)以及64位系统下的寻址方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 需要了解的汇编基础知识

通用寄存器:AX(参数传递以及函数调用返回值),BX(base),CX(计数器),DX(Data被除数)

堆栈寄存器:SP(栈顶指针),BP(栈基址指针)

字符串操作寄存器:SI(source index),DI(dest index)

指令计数器:IP(Instruction pointer)

标志寄存器:FLAGS(PUSHF/POPF)

段寄存器:CS(last 2 bits hold the current privilege level),DS,SS,ES,FS,GS

调试寄存器:DR0-3, DR6, DR7(仅在ring0可以操作)

控制寄存器:CR0(PG-bit31,PE-bit0), CR1, CR2, CR3(页表寄存器), CR4(PAE)

在64位系统中,所有的E寄存器扩展为64位的R寄存器,以及另外的R8至R15寄存器。

 

注意:

1) 如果程序编译时使用了-fomit-frame-pointer,则不使用BP寄存器

2) od -x a.out

3) IP 指向下一条将要执行的指令的地址,可以通过指令jmp, call, ret, sysenter/syscall, int来改变。

4) 下面的这段程序的目的是对齐ESP指针(16字节)

5) 汇编代码要从后往前读,否则很容易lost

6) 对32位程序来说,函数最好不要超过4个参数,否则多余的参数要通过栈来传递,而不是通过通用寄存器。

理论依据:四色原理与寄存器分配(http://en.wikipedia.org/wiki/Graph_coloring#Register_allocation)

7) 如果在调试时,发现esp的内容类似“xxx000”,说明产生了“page fault”.

同时,BP和SP的内容应该相差不大,如果相差很大,说明BP被破坏了,SP的内容是好的。

8) 下面的函数function,首先保存原BP值,然后用当前SP值更新BP值,使其指向新的栈基地址;然后SP-32个字节越过局部变量区。

 

2. 进程的内存空间分布

refer to http://blog.youkuaiyun.com/BetterManLu/archive/2010/05/09/5571663.aspx

 

3. 技巧

在代码中不使用assert,abort,而是"int #3",这是因为在调试时可以加断点,并且可以continue执行代码。例子如下,

 

 

更好的一种写法,

 

4. 虚拟内存

从虚拟地址到物理内存地址的转换包含3个步骤,

1) CR3指向PDT(Page Directory Table)的基地址, 而虚拟地址的前10位指向了该表的一个表项(Page Descriptor offset)

2) 虚拟地址的中间的10位指向了一个具体的页表(PTE, Page Table offset)

3) 最后的12位是在该页表中的偏移量,每个页表最多4K (Page offset)

注意:

1) 每个进程的地址空间为4G。

2) 在每个页表中,每项的最后12位,可以用做该页的标志位,参考http://wiki.osdev.org/Paging

3) 关于VSDO,a shared object exposed by the kernel at a fixed address in every process’ memory

4) OOM

下面是一个例子,程序占用内存太大,被系统kill掉了。(resident memory里面是数据 )

dmesg的结果显示a.out被kill了,如果这是应用服务程序,杯具了。

可以参考http://www.dbanotes.net/database/linux_outofmemory_oom_killer.html

 

同样的例子,修改每次分配的内存空间大小,这次失败的原因变成了malloc失败导致的segV,(resident memory里面是页表 )

检查dmesg,有如下的内容

[41521.451367] b.out[22155]: segfault at 0 rip 7f36e0c94390 rsp 7fffe9146ac8 error 6

5) 共享内存,例如libc

6) resident memory vs virtual memory


resident memory typically refers to physical RAM installed in the machine.

virtual memory is Hard Disk space reserved for the O/S to act as RAM. The O/S "swaps" data in and out of the virtual memory to place it in RAM, or to take it out of RAM. linux "swap" devices are exactly this.

shared memory refers to physical or virtual memory that is attached to more than one process - being shared.

 

7) TLB:Translation Lookaside Buffer

根据功能可以译为快表,直译可以翻译为旁路转换缓冲,也可以把它理解成页表缓冲。里面存放的是一些页表文件(虚拟地址到物理地址的转换表)。当处理器要在主内存寻址时,不是直接在内存的物理地址里查找的,而是通过一组虚拟地址转换到主内存的物理地址,TLB就是负责将虚拟内存地址翻译成实际的物理内存地址,而CPU寻址时会优先在TLB中进行寻址。处理器的性能就和寻址的命中率有很大的关系。
映射机制必须使一个程序能断言某个地址在其自己的进程空间或地址空间内,并且能够高效的将其转换为真实的物理地址以访问内存。一个方法是使用一个含有整个空间内所有页的入口(entry)的表(即页表),每个入口包含这个页的正确物理地址。这很明显是个相当大的数据结构,因而不得不存放于主存之中。
由于CPU首先接到的是由程序传来的虚拟内存地址,所以CPU必须先到物理内存中取页表,然后对应程序传来的虚拟页面号,在表里找到对应的物理页面号,最后才能访问实际的物理内存地址,也就是说整个过程中CPU必须访问两次物理内存(实际上访问的次数更多)。因此,为了减少CPU访问物理内存的次数,引入 TLB。

 

5. 物理地址扩展(PAE)

可以使机器支持4GB 以上物理内存,寻址方式变为2+9+9+12,每个进程的地址空间仍是4G。这时的CR3指向Page Directory Pointer Table。

对于PDT和PT,每个表项由32位变为8个字节,表项数目由1024变为了512(2^9),但是总的空间仍是4K。

 

6. 64位机器

汇编最多使用6个寄存器(r8,r9),第7个参数入栈。

寻址方式为9+9+9+9+12, 仅使用了48位。

下面的例子展示了浮点数参数是如何传递的,

使用gdb a.out显示了浮点数不是通过寄存器传递的,

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值