相关疑难解决方法(0)

用于测试Collat​​z猜想的C++代码比手写程序集更快 - 为什么?

我为Project Euler Q14编写了这两个解决方案,在汇编和C++中.它们是用于测试Collat​​z猜想的相同蛮力方法.装配解决方案与组装

nasm -felf64 p14.asm && gcc p14.o -o p14
Run Code Online (Sandbox Code Playgroud)

C++是用.编译的

g++ p14.cpp -o p14
Run Code Online (Sandbox Code Playgroud)

部件, p14.asm

section .data
    fmt db "%d", 10, 0

global main
extern printf

section .text

main:
    mov rcx, 1000000
    xor rdi, rdi        ; max i
    xor rsi, rsi        ; i

l1:
    dec rcx
    xor r10, r10        ; count
    mov rax, rcx

l2:
    test rax, 1
    jpe even

    mov rbx, 3
    mul rbx
    inc rax
    jmp c1

even:
    mov rbx, 2 …
Run Code Online (Sandbox Code Playgroud)

c++ optimization performance x86 assembly

803
推荐指数
8
解决办法
14万
查看次数

编译器优化可能会导致整数溢出。可以吗?

我有一个int x。为简单起见,假设ints 占据范围 -2^31 到 2^31-1。我想计算2*x-1. 我允许x为任何值 0 <= x<= 2^30。如果我计算 2*(2^30),我会得到 2^31,这是整数溢出。

一种解决方案是计算2*(x-1)+1. 比我想要的多了一项减法,但这不应该溢出。但是,编译器会将其优化为2*x-1. 这是源代码的问题吗?这是可执行文件的问题吗?

是 Godbolt 的输出2*x-1

func(int):                               # @func(int)
        lea     eax, [rdi + rdi]
        dec     eax
        ret
Run Code Online (Sandbox Code Playgroud)

是 Godbolt 的输出2*(x-1)+1

func(int):                               # @func(int)
        lea     eax, [rdi + rdi]
        dec     eax
        ret
Run Code Online (Sandbox Code Playgroud)

c++ integer-overflow compiler-optimization undefined-behavior integer-arithmetic

64
推荐指数
4
解决办法
7744
查看次数

使用自修改代码观察在x86上获取过时的指令

我被告知并且从英特尔的手册中读到可以将指令写入内存,但是指令预取队列已经获取了陈旧的指令并将执行那些旧的指令.我没有成功观察到这种行为.我的方法如下.

英特尔软件开发手册从第11.6节开始说明

对当前在处理器中高速缓存的代码段中的存储器位置的写入导致相关联的高速缓存行(或多个行)无效.此检查基于指令的物理地址.此外,P6系列和奔腾处理器检查对代码段的写入是否可以修改已经预取执行的指令.如果写入影响预取指令,则预取队列无效.后一种检查基于指令的线性地址.

所以,看起来如果我希望执行陈旧的指令,我需要有两个不同的线性地址引用相同的物理页面.所以,我将内存映射到两个不同的地址.

int fd = open("code_area", O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO);
assert(fd>=0);
write(fd, zeros, 0x1000);
uint8_t *a1 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
uint8_t *a2 = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
        MAP_FILE | MAP_SHARED, fd, 0);
assert(a1 != a2);
Run Code Online (Sandbox Code Playgroud)

我有一个汇编函数,它接受一个参数,一个指向我想要更改的指令的指针.

fun:
    push %rbp
    mov %rsp, %rbp

    xorq %rax, %rax # Return value 0

# A far jump simulated with a far return
# Push the …
Run Code Online (Sandbox Code Playgroud)

c x86 caching self-modifying

23
推荐指数
3
解决办法
2563
查看次数

用于比较std :: optional原始类型的迷人程序集

Valgrind选择了一个条件跳转或移动取决于我的一个单元测试中未初始化的值.

检查程序集,我意识到以下代码:

bool operator==(MyType const& left, MyType const& right) {
    // ... some code ...
    if (left.getA() != right.getA()) { return false; }
    // ... some code ...
    return true;
}
Run Code Online (Sandbox Code Playgroud)

在哪里MyType::getA() const -> std::optional<std::uint8_t>,生成以下程序集:

   0x00000000004d9588 <+108>:   xor    eax,eax
   0x00000000004d958a <+110>:   cmp    BYTE PTR [r14+0x1d],0x0
   0x00000000004d958f <+115>:   je     0x4d9597 <... function... +123>
x  0x00000000004d9591 <+117>:   mov    r15b,BYTE PTR [r14+0x1c]
x  0x00000000004d9595 <+121>:   mov    al,0x1

   0x00000000004d9597 <+123>:   xor    edx,edx
   0x00000000004d9599 <+125>:   cmp    BYTE PTR [r13+0x1d],0x0 …
Run Code Online (Sandbox Code Playgroud)

c++ assembly gcc x86-64 c++17

23
推荐指数
2
解决办法
833
查看次数

未定义的行为是否适用于asm代码?

假设您知道您的软件只能运行在两个补码机器上,其中已经很好地定义了带符号的溢出行为.签名溢出仍然是C和C++中未定义的行为,编译器可以用"ret"替换你的整个程序,开始核战争,格式化你的驱动器,或让恶魔飞出你的鼻子.

假设您已在内联asm中签名溢出,您的程序是否仍然调用UB?

如果是,那么单独编译和链接汇编程序呢?

c c++ assembly undefined-behavior language-lawyer

14
推荐指数
1
解决办法
531
查看次数

X64指令在不同的CPU上表现不同

在一次采访中,有人问我是否知道x64指令的行为有所不同,具体取决于使用的CPU,我在任何地方找不到任何文档,有谁知道这些指令是什么以及为什么会这样?

x86 assembly x86-64

3
推荐指数
1
解决办法
341
查看次数