Articles of x86 64

Linux / x86-64系统调用中的结构体对于汇编程序员的布局?

许多linux / x86-64系统调用接受指向结构的指针作为参数。 例如stat(2)的第二个参数是struct stat* … struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; […]

在64位Linux上从32位模式切换到64位(长模式)

我的程序是在x86_64 CPU(64位操作系统,Ubuntu 8.04)上运行的32位模式。 是否可以暂时在用户模式下切换到64位模式(长时间模式)? 如果是这样,怎么样? 背景故事:我正在写一个链接到32位模式程序的库,所以它在启动时必须是32位模式。 但是,我想使用更快的x86_64入侵以获得更好的性能。 所以我想切换到64位模式做一些纯粹的计算(没有操作系统的交互;不需要64位寻址),返回到32位,然后返回给调用者。 我发现有一些相关但不同的问题。 例如, 在64位程序中运行32位代码 在32位操作系统中运行64位代码 我的问题是“在32位程序,64位操作系统中运行64位代码”

Linux在x86-64中如何支持超过512GB的虚拟地址范围?

用于Linux的x86-64的用户虚拟地址空间是47位长。 这基本上意味着Linux可以映射具有大约128 TB的虚拟地址范围的进程。 然而,我认为x86-64体系结构支持ISA为每个进程定义了4级分层页表(排列为基数树)。 页表的根目录最多只能映射512 GB的连续虚拟地址空间。 那么Linux如何能够支持超过512GB的虚拟地址范围呢? 它是否为每个进程使用多个页表? 如果是的话,那么对于一个进程来说,CR3(x86-64的寄存器包含页表的基地址)应该包含什么给定的进程? 我错过了什么吗?

为什么gcc强制PIC为x64共享库?

试图用gcc将非PIC代码编译到x64上的共享库中会导致错误,如下所示: /usr/bin/ld: /tmp/ccQ2ttcT.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC 这个问题是关于为什么这样。 我知道x64具有RIP相对寻址function,旨在提高PIC代码的效率。 但是,这并不意味着加载时重定位不能(理论上)适用于这样的代码。 一些在线资源(包括在这个问题上被广泛引用)声称, 由于 RIP相对寻址,共享库中的非PIC代码有一些固有的限制。 我不明白为什么这是真的。 考虑“旧x86” – 一个call指令也有一个IP相对操作数。 然而, call它的x86代码在没有PIC的情况下编译成共享库,但使用加载时重定位 R_386_PC32 。 对于x64中的数据RIP相对寻址,不能这样做吗? 请注意,我完全理解PIC代码的好处,并且性能降低了RIP相对寻址有助于缓解。 不过,我很好奇不允许使用非PIC代码的原因。 是否有一个真正的技术背后的原因,还是只是鼓励编写PIC代码?

页面错误陷阱的成本

我有一个应用程序定期(每1或2秒后)通过分叉自己的检查点。 所以检查点是原始进程的一个分支,它只是保持空闲,直到在原始进程中出现错误时要求启动。 现在我的问题是fork的copy-on-write机制是多么昂贵。 写入时复制机制将确保原始进程写入内存页面(在获得检查点之后的第一次)时,将发生的页面错误陷阱的成本是多less与检查点不同的物理页面。 在我看来,页面错误陷阱开销可能会相当高,因为中断发生时,我们从用户空间降落到内核空间,然后从内核回到用户空间。 我可以从这样的页面错误陷阱中损失多lessCPU周期。 假设RAM足够大,我们不需要交换到硬盘。 那么我知道,很难想象一个检查点计划比这更有效率,因此你可以说为什么我担心页面陷阱错误的开销,但我只是想知道这个计划将有多less成本。

什么是“mov rax,QWORD PTR fs:0x28”汇编指令呢?

在执行该指令之前,fs包含0x0。 另外我想知道我怎么能从GDB的这个内存区读取,这个命令是什么?

SMP如何处理中断?

在SMP(Symmetrix多处理器/多核)机器上如何处理中断? 是否只有一个内存pipe理单元? 假设有两个线程,运行在不同内核上的A和B触及页表中不存在的内存页面(同时),在这种情况下会出现页面错误,并从内存中引入新页面。 什么是将发生的事件序列? 如果有一个内存pipe理单元,哪个核心是页面错误转发的? 内核如何处理它? 是否有多个内核实例,每个实例都运行在不同的内核上? 如果是这样,他们如何同步页面error handling等事件?

上证所:跨越页面边界的未alignment的加载和存储

我在某处读取了在执行未alignment的加载或存储在页面边界旁边(例如使用_mm_loadu_si128 / _mm_storeu_si128内在函数)之前,代码应该首先检查整个向量(本例中为16字节)是否属于同一页面,并切换到非向量指令如果不。 我明白,如果下一页不属于进程,则需要防止coredump。 但是,如果这两个页面属于进程(例如,它们是一个缓冲区的一部分,并且我知道该缓冲区的大小)呢? 我写了一个小的testing程序,执行跨越页面边界的未alignment的加载和存储,并没有崩溃。 在这种情况下,我是否必须经常检查页面边界,还是足以确保我不会溢出缓冲区? Env:Linux,x86_64,gcc

Linux:大型int数组:mmap vs查找文件?

假设我有一个数据集,它是一个存储在4TB HDD ext4文件系统文件中的1e12 32位整数(4 TB)数组。 考虑到数据很可能是随机的(或者至less似乎是随机的)。 // pseudo-code for (long long i = 0; i < (1LL << 40); i++) SetFileIntAt(i) = GetRandInt(); 此外,考虑我希望以不可预知的顺序读取单个int元素,并且algorithm运行不确定(正在进行)。 // pseudo-code while (true) UseInt(GetFileInt(GetRand(1<<40))); 我们在Linux x86_64上,gcc。 您可以假设系统具有4GB的RAM(即比数据集小1000倍) 以下是架构访问的两种方法: (A)将文件映射到4TB的内存块,并以int数组的forms访问它 (B)打开(2)文件并使用seek(2)和read(2)来读取整数。 A和B哪个会有更好的performance?为什么? 还有另一种devise能比A或B提供更好的性能吗?

编译器:了解从小程序生成的汇编代码

我正在研究编译器是如何工作的。 我正在通过阅读从小型64位Linux程序反汇编生成的代码来学习。 我写了这个C程序: #include <stdio.h> int main() { for(int i=0;i<10;i++){ int k=0; } } 使用objdump后,我得到: 00000000004004d6 <main>: 4004d6: 55 push rbp 4004d7: 48 89 e5 mov rbp,rsp 4004da: c7 45 f8 00 00 00 00 mov DWORD PTR [rbp-0x8],0x0 4004e1: eb 0b jmp 4004ee <main+0x18> 4004e3: c7 45 fc 00 00 00 00 mov DWORD […]