Articles of x86 64

为什么Linux / GNU链接器select地址0x400000?

我正在试验ELF可执行文件和Linux x86_64上的gnu工具链: 我已经链接并剥离了一个“Hello World”testing。 .global _start .text _start: mov $1, %rax … 到一个267字节的ELF64可执行文件… 0000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF………… 0000010: 0200 3e00 0100 0000 d400 4000 0000 0000 ..>…….@….. 0000020: 4000 0000 0000 0000 0000 0000 0000 0000 @…………… 0000030: 0000 0000 4000 3800 0100 4000 0000 0000 ….@.8…@….. 0000040: 0100 […]

在64位Linux&64位处理器上运行32位汇编代码:解释exception

我在一个有趣的问题。我忘了我正在使用64位机器和操作系统,并写了一个32位汇编代码。 我不知道如何写64位代码。 这是Linux上Gnu Assembler(AT&T语法)的x86 32位汇编代码。 //hello.S #include <asm/unistd.h> #include <syscall.h> #define STDOUT 1 .data hellostr: .ascii "hello wolrd\n"; helloend: .text .globl _start _start: movl $(SYS_write) , %eax //ssize_t write(int fd, const void *buf, size_t count); movl $(STDOUT) , %ebx movl $hellostr , %ecx movl $(helloend-hellostr) , %edx int $0x80 movl $(SYS_exit), %eax //void _exit(int status); […]

双重下划线的含义在一开始

在标准库(glibc)中,我们可以看到使用前两个下划线定义的函数,例如sys/mman.h __mmap 。 什么目的? 而且我们怎样才能调用一个函数mmap ,这个函数似乎没有在任何地方声明。 我的意思是我们包含sys/mman.h ,但是sys/mman.h不声明mmap ,它只声明__mmap 。

在assembly中使用printf会导致空的输出

我尝试从我的汇编代码中使用printf ,这是一个最简单的例子,它应该打印hello到stdout: .section .rodata hello: .ascii "hello\n\0" .section .text .globl _start _start: movq $hello, %rdi #first parameter xorl %eax, %eax #0 – number of used vector registers call printf #exit movq $60, %rax movq $0, %rdi syscall 我用它来构build它 gcc -nostdlib try_printf.s -o try_printf -lc 当我运行它,似乎工作:stringhello打印出来,退出状态是0 : XXX$ ./try_printf hello XXX$ echo $? 0 XXX$ 但是,当我尝试捕捉文本时,很明显,有些东西不能正常工作: […]

编译器使用本地variables而不调整RSP

问题编译器:了解从小程序生成的汇编代码 ,编译器使用两个局部variables而不调整堆栈指针。 不调整RSP以使用局部variables似乎不会中断安全 ,因此编译器似乎依靠硬件在中断发生时自动切换到系统堆栈。 否则,出现的第一个中断会将指针指向堆栈并覆盖局部variables。 这个问题的代码是: #include <stdio.h> int main() { for(int i=0;i<10;i++){ int k=0; } } 该编译器生成的汇编代码是: 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 […]

生成LLVM C ++ API代码作为后端

在线LLVM演示页面可以select从源代码生成LLVM C ++ API代码作为后端。 但是,该演示页面现在已禁用。 我想知道如何使用可用的LLVM工具自己做。 我尝试了以下 clang++ -c -emit-llvm input.cpp -o input.ll llc -march=cpp -o input.ll.cpp input.ll 这给出了以下错误 llc: error: invalid target 'cpp'. 我正在使用LLVM / Clang版本3.2。

在gdb中检查C / C ++堆内存统计信息

我试图调查在Linux amd64 gdb内的C / C ++堆的状态,是否有一个很好的方法来做到这一点? 我试过的一种方法是“调用mallinfo()”,但不幸的是我不能提取我想要的值,因为gdb没有正确处理返回值。 我不是很容易编写一个函数来编译到我附加的过程的二进制文件中,所以我可以简单地实现我自己的函数,通过以这种方式在我自己的代码中调用mallinfo()来提取值。 是否有一个聪明的把戏,可以让我在飞行中做到这一点? 另一个select可能是find堆并遍历malloc头文件/空闲列表; 我很感激任何指向我可以开始寻找这些位置和布局的地方。 我一直在试图谷歌和解决这个问题约2个小时,我已经学到了一些迷人的东西,但仍然没有find我所需要的。

与位置无关的代码差异:x86与x86-64

我最近正在构build一个针对x86-64架构的特定共享库(ELF),如下所示: g++ -o binary.so -shared –no-undefined … -lfoo -lbar 这失败了以下错误: 在创build共享对象时,不能使用“对本地符号”进行重定位R_X86_64_32; 用-fPIC重新编译 当然,这意味着我需要重build它作为位置无关的代码,所以适合链接到共享库。 但是,这完全适用于x86,完全相同的构build参数。 所以问题是,如何重新定位x86不同于x86-64,为什么我不需要使用-fPIC编译前者?

x86-64 SysV ABI中的参数和返回值寄存器的高位允许垃圾吗?

x86-64 SysV ABI指定了函数参数如何在寄存器中传递( rdi第一个参数,然后是rsi等),以及如何传回整数返回值(在rax ,然后在rdx中传递非常大的值)。 但是,我不能find的是当传递小于64位的types时,参数或返回值寄存器的高位应该是什么。 例如,对于以下function: void foo(unsigned x, unsigned y); … x将在rsi以rdi和y传递,但它们只有32位。 rdi和rsi的高32位是否需要为零? 直觉上,我会承认是的,但所有的海湾合作委员会,铛和ICC 生成的代码具有特定的mov指令在开始零高位,所以它似乎编译器假设,否则。 同样,编译器似乎认为,如果返回值小于64位,则返回值rax的高位可能具有垃圾位。 例如,以下代码中的循环: unsigned gives32(); unsigned short gives16(); long sum32_64() { long total = 0; for (int i=1000; i–; ) { total += gives32(); } return total; } long sum16_64() { long total = 0; for (int i=1000; i–; […]

使用MAP_NORESERVE的mmap是否保留物理内存?

mmap文档在关于标志MAP_NORESERVE的说明如下。 不要为这个映射保留交换空间。 当交换空间被保留时,可以保证可以修改映射。 当交换空间未被保留时,如果没有可用的物理内存,则可以在写入时获得SIGSEGV。 我实际上想要的只是保留虚拟内存地址,并没有分配实际的物理内存。 这可以通过使用MAP_NORESERVE的mmap来完成吗? 如果我想要使用任何物理内存,我将使用MAP_NORESERVE通过mmap中的地址范围内的MAP_FIXED重新映射它。 总而言之,我希望内核不会为MAP_NORSERVE标志的mmap分配的内存预留任何物理页面。 它是否真的像这样工作,或者如果内核具有足够的物理内存,内核是否分配物理页面?