Tag: x86 64

打印堆栈框架

所以我目前正在学习堆栈帧,我想实验打印一个函数的堆栈帧(手动)。 我有以下图片记住堆栈框架(我可能是错的): | | 0xffff0fdc +——————————–+ | … | 0xffff0fd8 +——————————–+ | parameter 2 | 0xffff0fd4 +——————————–+ | parameter 1 | 0xffff0fd0 +——————————–+ | return address | 0xffff0fcc +——————————–+ | local variable 2 | 0xffff0fc8 +——————————–+ | local variable 1 | 0xffff0fc4 +——————————–+ 因此我首先写了这个函数来实现上面的结果并打印出来: void func(int a,int b) { uint64_t loc = 0; uint64_t *sp […]

C / C ++在引擎盖下按值返回struct

(这个问题特定于我的机器的架构和调用约定,Windows x86_64) 我不记得我在哪里读过这个,或者我是否正确地回忆过它,但是我听说过,当一个函数应该按值返回一些结构或对象时,它会将它填入rax (如果对象可以适合64位的寄存器宽度)或传递指向结果对象所在的指针(我猜在调用函数的堆栈帧中分配)在rcx ,它将执行所有常规初始化,然后是mov rax, rcx为回程。 就是这样的 extern some_struct create_it(); // implemented in assembly 真的会有一个秘密参数 extern some_struct create_it(some_struct* secret_param_pointing_to_where_i_will_be); 我的记忆对我有用,还是我不正确? 如何通过函数的值返回大对象(即宽度超过寄存器宽度)?

gcc参数寄存器溢出x86-64

我正在尝试使用x86-64程序集。 编译了这个虚函数: long myfunc(long a, long b, long c, long d, long e, long f, long g, long h) { long xx = a * b * c * d * e * f * g * h; long yy = a + b + c + d + e + f + g + […]

字对齐加载比x64处理器上的未对齐加载更快吗?

在x86 / 64(Intel / AMD 64位)处理器上,在字边界上对齐的变量是否比未对齐的加载操作更快? 我的一位同事辩称,未对齐的载荷很慢,应该避免。 他引用了项目填充到结构中的单词边界,作为未对齐加载缓慢的证据。 例: struct A { char a; uint64_t b; }; 结构A通常大小为16个字节。 另一方面, Snappy压缩器的文档指出Snappy认为“未对齐的32位和64位负载和存储很便宜”。 根据源代码,英特尔32和64位处理器也是如此。 那么:这里的真相是什么? 如果和未对齐的负载有多少? 在哪种情况下?

为什么编译器可以假设全局变量的地址适合32位?

在查看这个简单函数的汇编程序(参见godbolt.org )时 extern int global; void doit(int *); void call_doit(){ doit(&global); } 32位值用于保存global地址: call_doit: movl $global, %edi jmp doit 据我所知,这里使用32位寄存器(即%edi )优于64位寄存器(即%rdi ),因为可以保存2个字节( movl $global, %edi需要5个字节而movq $global, %rdi需要7个字节+ 4个额外字节,如果不假设$global适合32位)。 (编者注:编译器实际上使用7字节lea global(%rip), %rdi来创建一个来自RIP + 32位相对位移的64位地址,编译器可以假设它在范围内有相关原因。并且movabs $global, %rdi对于64位绝对地址movabs $global, %rdi为10个字节,而不是11个。) 但是为什么编译器允许假设全局变量的地址适合这32位? 编译器有什么保证? 对于局部变量,编译器使用64位寄存器来保存堆栈地址,例如: void doit(int *); void call_doit(){ int local=0; doit(&local); } 结果(见godbolt.org ): call_doit: subq $24, %rsp […]

GCCassembly优化 – 为什么这些相同?

我正在尝试学习assembly如何在初级阶段工作,所以我一直在玩gcc汇编的-S输出。 我写了一个简单的程序,定义了两个字节并返回它们的总和。 整个计划如下: int main(void) { char A = 5; char B = 10; return A + B; } 当我使用以下方法编译时没有优化: gcc -O0 -S -c test.c 我得到test.s,如下所示: .file “test.c” .def ___main; .scl 2; .type 32; .endef .text .globl _main .def _main; .scl 2; .type 32; .endef _main: LFB0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 […]

如何在程序中获取_GLOBAL_OFFSET_TABLE_地址?

我想在我的程序中获取_GLOBAL_OFFSET_TABLE_的地址。 一种方法是在Linux中使用nm命令,可能将输出重定向到文件并解析该文件以获取_GLOBAL_OFFSET_TABLE_的地址。 但是,这种方法似乎效率很低。 有哪些更有效的方法呢?

数学函数在现代处理器上花费了多少周期

我们知道现代处理器直接在处理器上执行诸如cosine和sin指令,因为它们具有操作码。 我的问题是这些指令通常需要多长时间。 他们是否需要恒定时间或依赖输入参数?

用ptrace解析调用和Ret。

我尝试使用ptrace解析可执行文件中的所有Calls和Rets。 符合x64opcode ,我找到了调用的操作码:0xe8和Rets:0xc3,0xc2,0xca,0xcb 。 自从我解析它们后,我发现了更多的Rets而不是Calls。 有我跟踪的程序: void func() { write(1, “i”, 1); } int main(int ac) { func(); return(0); } 有我的示踪剂: int tracer(t_info *info) { int status; long ptr; int ret = 0; int call = 0; waitpid(info->pid, &status, 0); while (WIFSTOPPED(status)) { ptrace(PTRACE_GETREGS, info->pid, NULL, info->regs); ptr = ptrace(PTRACE_PEEKDATA, info->pid, info->regs->rip); if (((ptr & […]

最少组装或编译至少三个值

我正在查看GCC-4.8为x86_64生成的代码,并想知道是否有更好(更快)的方法来计算三个值的最小值。 这是Python的集合模块的摘录,它计算m , rightindex+1和leftindex的最小值: ssize_t m = n; if (m > rightindex + 1) m = rightindex + 1; if (m > leftindex) m = leftindex; GCC使用CMOV生成连续相关的代码: leaq 1(%rbp), %rdx cmpq %rsi, %rdx cmovg %rsi, %rdx cmpq %rbx, %rdx cmovg %rbx, %rdx 是否有更快的代码可以通过删除数据依赖性来利用处理器无序并行执行? 我想知道是否存在用于计算多个值的最小值而不使用条件或谓词指令的已知技巧。 我也想知道是否有一些饱和的算术内在函数可以帮助解决这种情况。 EDITS: 如图所示,代码使用带符号的算术,但无符号算术答案也会有所帮助。 我询问了最少三个,但也对n最小的n感兴趣。 Linus对CMOV的警告: http : //ondioline.org/mail/cmov-a-bad-idea-on-out-of-order-cpus