标签: x86-64

GCC/Clang x86_64 C++ ABI在返回元组时不匹配?

在尝试优化x86_64上的返回值时,我注意到一件奇怪的事情.即,给出代码:

#include <cstdint>
#include <tuple>
#include <utility>

using namespace std;

constexpr uint64_t a = 1u;
constexpr uint64_t b = 2u;

pair<uint64_t, uint64_t> f() { return {a, b}; }
tuple<uint64_t, uint64_t> g() { return tuple<uint64_t, uint64_t>{a, b}; }
Run Code Online (Sandbox Code Playgroud)

Clang 3.8输出此汇编代码f:

movl $1, %eax
movl $2, %edx
retq
Run Code Online (Sandbox Code Playgroud)

这个用于g:

movl $2, %eax
movl $1, %edx
retq
Run Code Online (Sandbox Code Playgroud)

哪个看起来最佳.但是,使用GCC 6.1编译时,生成的程序集f与Clang输出相同,生成的程序集为g:

movq %rdi, %rax
movq $2, (%rdi)
movq $1, 8(%rdi)
ret
Run Code Online (Sandbox Code Playgroud)

看起来返回值的类型被GCC归类为MEMORY,而Clang归类为INTEGER.我可以确认将Clang代码与GCC代码链接这样的代码可能会导致分段错误(Clang调用GCC编译 …

c++ tuples x86-64 abi compiler-bug

12
推荐指数
2
解决办法
501
查看次数

Clang 中的 256 位算术(扩展整数)

我正处于一个项目的设计阶段,该项目需要执行大量简单的 256 位整数运算(仅加、子、多、分),并且需要针对这四个操作进行合理优化的东西。

我已经熟悉 GMP、NTL 和大多数其他重量级 bignum 实现。然而,这些实现的开销促使我做我自己的低级实现——我真的不想这样做;众所周知,这东西很难做对。

在我的研究中,我注意到 Clang 中新的扩展整数类型 - 我是 gcc 用户 - 我想知道是否有人对现实生活中的扩展整数有任何经验,愤怒的实现?它们是否针对“明显的”位大小(256、512 等)进行了优化?

我在 linux 下的 x-64 上使用 C 语言(目前是 Ubuntu,但如果需要,可以向其他发行版开放)。我主要使用 gcc 进行生产工作。

编辑添加:@phuclv 确定了以前的答案C++ 128/256-bit fixed size integer types。(感谢@phuclv。)这个q/a 侧重于c++ 支持;我希望确定是否有人对新的 Clang 类型有任何特定的经验。

c x86-64 clang bigint extint

12
推荐指数
1
解决办法
662
查看次数

可以说服 clang 优化这个几乎叶函数吗

考虑以下几乎叶函数:

int almost_leaf(int* x) {
    if (__builtin_expect(*x >= 0, true)) {
        return *x;
    }
    return x_was_negative() + 1;
}
Run Code Online (Sandbox Code Playgroud)

几乎是叶子,因为它不是严格意义上的叶子函数(它可能调用x_was_negativeis x 为负数,但__builtin_expect提示编译器return *x通常采用分支,这不涉及任何调用。

clang-16 像这样编译它:

almost_leaf(int*):                      # @almost_leaf(int*)
        push    rax
        mov     eax, dword ptr [rdi]
        test    eax, eax
        js      .LBB0_1
        pop     rcx
        ret
.LBB0_1:
        call    x_was_negative()
        inc     eax
        pop     rcx
        ret
Run Code Online (Sandbox Code Playgroud)

快速(预期)路径上的and (直到第一个的部分)在这里push是完全不必要的:堆栈未使用,并且不会进行需要“由于 ABI”而对齐的堆栈的调用。popret

最好将堆栈对齐到x_was_negative()调用的慢速路径上,就像 gcc 那样:

almost_leaf(int*):
        mov     eax, DWORD PTR [rdi] …
Run Code Online (Sandbox Code Playgroud)

c++ optimization performance x86-64 clang

12
推荐指数
1
解决办法
179
查看次数

如何用汇编语言编写"Hello World"应用程序?

可能重复:
如何在windows下的汇编程序中编写hello world?

我经常听说使用神灵语言汇编语言编写的应用程序.我从来没有尝试过,我甚至都不知道该怎么做.

如果我想涉猎,我该怎么做呢?我完全不知道需要什么,虽然可能是某种编译器和记事本.

纯粹出于好奇,我需要写一个"Hello World!" 应用?

编辑添加,我正在运行Windows 7 64位

编辑添加,我想知道是否有Visual Studio的汇编语言插件?

x86 assembly x86-64

11
推荐指数
2
解决办法
2万
查看次数

REX.B覆盖是否适用于MOVSS指令?

我正在为64位x86生成以下指令:

41 F3 0F 10 46 10       movss   XMM0,014h[R14]
Run Code Online (Sandbox Code Playgroud)

不幸的是,它在该行上出现故障.gdb将其反汇编为:

0x0000000000402054 <+320>:   rex.B
0x0000000000402055 <+321>:   movss  0x14(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)

请注意,无法识别rex.B覆盖,索引是RSI而不是R14.

指令无效吗?在AMD 64位指令参考中,我找不到任何迹象表明此编码无效.

objdump也无法将其识别为有效指令:

41                      rex.B
f3 0f 10 46 10          movss  0x10(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

assembly x86-64

11
推荐指数
1
解决办法
629
查看次数

如何在x86_64汇编中读取STDIN的输入?

我正在尝试学习x86_64程序集,我今天正在尝试标准输入输出并偶然发现这个帖子学习程序集 - echo程序名称如何从STDIN读取输入(使用SYSCALL指令)?特别是如果我知道输入将始终是一个整数,我想将其读入寄存器?

编辑: @Daniel Kozar在下面的回答帮助我理解了STDIN和STDOUT如何与Linux上的SYSCALL指令一起工作.我试图编写一个小程序,它从控制台输入中读取一个数字并打印与该数字对应的ascii字符.假如你输入65作为输入,你应该得到A作为输出.还有一个新的线条角色.如果有的话,它可以帮助任何其他人:-)

section .text
    global _start

_start:
    mov rdi, 0x0      ; file descriptor = stdin = 0
    lea rsi, [rsp+8]  ; buffer = address to store the bytes read
    mov rdx, 0x2      ; number of bytes to read
    mov rax, 0x0      ; SYSCALL number for reading from STDIN
    syscall           ; make the syscall

    xor rax, rax      ; clear off rax
    mov rbx, [rsp+8]  ; read the first byte read into rsp+8 by STDIN call …
Run Code Online (Sandbox Code Playgroud)

assembly stdin x86-64

11
推荐指数
1
解决办法
2万
查看次数

为什么x86-64 GCC函数序言分配的堆栈少于局部变量?

考虑以下简单程序:

int main(int argc, char **argv)
{
        char buffer[256];

        buffer[0] = 0x41;
        buffer[128] = 0x41;
        buffer[255] = 0x41;

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

在x86-64机器上使用GCC 4.7.0编译.用GDB反汇编main()给出:

0x00000000004004cc <+0>:     push   rbp
0x00000000004004cd <+1>:     mov    rbp,rsp
0x00000000004004d0 <+4>:     sub    rsp,0x98
0x00000000004004d7 <+11>:    mov    DWORD PTR [rbp-0x104],edi
0x00000000004004dd <+17>:    mov    QWORD PTR [rbp-0x110],rsi
0x00000000004004e4 <+24>:    mov    BYTE PTR [rbp-0x100],0x41
0x00000000004004eb <+31>:    mov    BYTE PTR [rbp-0x80],0x41
0x00000000004004ef <+35>:    mov    BYTE PTR [rbp-0x1],0x41
0x00000000004004f3 <+39>:    mov    eax,0x0
0x00000000004004f8 <+44>:    leave  
0x00000000004004f9 <+45>:    ret    
Run Code Online (Sandbox Code Playgroud)

当缓冲区为256字节时,为什么sub rsp只有0x98 = 152d?当我将数据移入缓冲区[0]时,它似乎只是使用分配的堆栈帧之外的数据并使用rbp来引用,那么甚至sub rsp的点是什么,0x98? …

assembly stack gcc x86-64

11
推荐指数
1
解决办法
2516
查看次数

JRE 32位对比64位

我一直在使用Java一段时间,而我设置新开发机器的典型仪式需要从Oracle网站下载和安装最新JDK的规范.

这引发了一个不寻常的问题, does it matter if I use the 32bit or 64bit JRE bundle?

回过头来看,我之前已经安装了两个版本,而且我的普通工具链很快就插入了(Eclipse).在我的日常编程中,我不记得曾经因为我使用的是64位JRE(或针对这方面的目标是64位JRE)而不得不以不同的方式改变某些东西或思考某些东西.

根据我对64位与32位的理解 - 它实际上归结为数字如何存储在封面下...我知道这int是32位并且long是64位...与float32位相同并且double是64位 - 所以只是Java已经抽象出了这个微妙之处,并且可能一直都是"64位兼容"吗?

我确定我在这里遗漏了一些东西,除了无法在32位系统上安装64位JRE.

java x86 x86-64 jvm-hotspot

11
推荐指数
2
解决办法
2万
查看次数

为什么这个movq指令适用于linux而不是osx?

以下汇编代码as在OSX 10.9.4上运行时出错,但在Linux(Debian 7.6)上成功运行.特别是,movq指令似乎不喜欢label参数.

$ cat test.S
.globl _main
_main:
    movq $_main, %rax
    ret
Run Code Online (Sandbox Code Playgroud)

这是错误:

$ as -o test.o test.S 
test.S:3:32-bit absolute addressing is not supported for x86-64
test.S:3:cannot do signed 4 byte relocation
Run Code Online (Sandbox Code Playgroud)

$_main第3行更改为文字$10就好了.

代码必须以非常小的方式进行修改才能在Linux上运行 - 只需从标签中删除下划线即可.

$ cat test.S
.globl main
main:
    movq $main, %rax
    ret
Run Code Online (Sandbox Code Playgroud)

很容易独立验证代码在Linux上是否可行:

$ as -o test.o test.S
$ gcc -o test.out test.o
$ ./test.out
Run Code Online (Sandbox Code Playgroud)

请忽略代码并没有真正做很多事情,我故意尽可能地将其修剪下来以证明错误.

我已经看了很多使用LEA(加载有效地址),但在我做出改变之前,我想了解其中的区别 - 为什么它适用于Linux而不是OSX?

linux macos x86-64

11
推荐指数
1
解决办法
1688
查看次数

Nasm - 符号`printf'导致R_X86_64_PC32重定位溢出

我试图在nasm中创建一个应该显示该字母的简单程序a.然而,它给了我一个Segfault并说:

./a.out: Symbol `printf' causes overflow in R_X86_64_PC32 relocation
Segmentation fault (core dumped)
Run Code Online (Sandbox Code Playgroud)

基本上,我试图将值0x61(字母a的十六进制)移动到内存地址1234,然后将其作为参数传递给printf.这是我的确切代码:

extern printf
section .text
global main
main:
push rbp
mov rax,0
mov qword [1234], 0x61 ; move 0x61 into address 1234
mov rdi, qword [1234] ; mov address 1234 into rdi
call printf ; should print the letter a
pop rbp
mov rax,0
ret
Run Code Online (Sandbox Code Playgroud)

我正在运行Linux x86_64

linux gcc x86-64 nasm segmentation-fault

11
推荐指数
2
解决办法
5462
查看次数