相关疑难解决方法(0)

if语句汇编输出c代码

我在c中有这么简单的代码:

#include <stdio.h>

void test() {}

int main()
{
    if (2 < 3) {

        int zz = 10;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我看到这段代码的汇编输出时:

test():
  pushq %rbp
  movq %rsp, %rbp
  nop
  popq %rbp
  ret
main:
  pushq %rbp
  movq %rsp, %rbp
  movl $10, -4(%rbp) // space is created for zz on stack
  movl $0, %eax
  popq %rbp
  ret
Run Code Online (Sandbox Code Playgroud)

我从这里 得到了程序集(默认选项) 我看不出条件检查的指令在哪里?

c assembly

0
推荐指数
1
解决办法
152
查看次数

为什么x86-64 System V调用约定在寄存器而不是堆栈中传递args?

为什么32位C将所有函数参数直接推送到堆栈上,而64位C将前6个参数放入寄存器而其余的放在堆栈中?

所以32位堆栈看起来像:

...
arg2
arg1
return address
old %rbp
Run Code Online (Sandbox Code Playgroud)

虽然64位堆栈看起来像:

...
arg8
arg7
return address
old %rbp
arg6
arg5
arg4
arg3
arg2
arg1
Run Code Online (Sandbox Code Playgroud)

那么为什么64位C会这样做呢?将所有内容都推送到堆栈而不是将前6个参数放在寄存器中以便将它们移动到函数序言中的堆栈中是不是更容易?

assembly gcc x86-64 calling-convention

0
推荐指数
1
解决办法
313
查看次数

了解“ volatile”关键字和比较的工作方式

如果未使用关键字指定变量volatile,则编译器可能会进行缓存。必须始终从内存访问该变量,否则直到其事务单元结束。我想知道的重点在于装配零件。

int main() {
    /* volatile */ int lock = 999;
    while (lock);
}
Run Code Online (Sandbox Code Playgroud)

x86-64-clang-3.0.0编译器上,其汇编代码如下。

main:                                   # @main
        mov     DWORD PTR [RSP - 4], 0
        mov     DWORD PTR [RSP - 8], 999


.LBB0_1:                                # =>This Inner Loop Header: Depth=1
        cmp     DWORD PTR [RSP - 8], 0
        je      .LBB0_3
        jmp     .LBB0_1


.LBB0_3:
        mov     EAX, DWORD PTR [RSP - 4]
        ret
Run Code Online (Sandbox Code Playgroud)

volatile关键字被注释时,结果如下。

main:                                   # @main
        mov     DWORD PTR [RSP - 4], 0
        mov     DWORD …
Run Code Online (Sandbox Code Playgroud)

c assembly x86-64 volatile

0
推荐指数
1
解决办法
104
查看次数

为什么 %rax 寄存器在这个程序的程序集中使用 8 个参数?

我有以下 C 函数:

void proc(long  a1, long  *a1p,
          int   a2, int   *a2p,
          short a3, short *a3p,
          char  a4, char  *a4p)
{
    *a1p += a1;
    *a2p += a2;
    *a3p += a3;
    *a4p += a4;
}
Run Code Online (Sandbox Code Playgroud)

使用Godbolt,我已将其转换为 x86_64 程序集(为简单起见,我使用该-Og标志来最小化优化)。它产生以下组件:

proc:
        movq    16(%rsp), %rax
        addq    %rdi, (%rsi)
        addl    %edx, (%rcx)
        addw    %r8w, (%r9)
        movl    8(%rsp), %edx
        addb    %dl, (%rax)
        ret
Run Code Online (Sandbox Code Playgroud)

我对汇编的第一行感到困惑:movq 16(%rsp), %rax. 我知道%rax寄存器用于存储返回值。但是该proc过程没有返回值。所以我很好奇为什么在此处使用该寄存器,而不是 %r9其他一些不用于返回值的寄存器。

相对于其他指令,我也对这条指令的位置感到困惑。它首先出现,远在%rax任何需要其目标寄存器之前(实际上,直到最后一步才需要该寄存器)。它也出现在 之前addq %rdi, (%rsi) …

assembly x86-64 cpu-registers compiler-optimization

0
推荐指数
1
解决办法
384
查看次数

从没有返回的函数中返回一个值

我想我发现 gcc 编译器处理函数的方式有问题。

我不知道这是一个错误还是我多年来忽略的东西从来没有分心。实际上,通过声明一个函数并定义后者具有返回值,编译器将在函数范围内分配的第一个变量的值存储在 EAX 寄存器中,然后依次将其存储在一个变量中。例子:

#include<stdio.h>

int add(int a, int b)
{
    int c = a + b;

    ;there isn't return
}

int main(void)
{
    int res = add(3, 2);

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

这是输出:

5
Run Code Online (Sandbox Code Playgroud)

这是具有 intel 语法的 x86-64 程序集:

功能添加:

push   rbp
mov    rbp, rsp
mov    DWORD PTR[rbp-0x14], edi  ;store first
mov    DWORD PTR[rbp-0x18], esi  ;store second
mov    edx, DWORD PTR[rbp-0x14]
mov    eax, DWORD PTR[rbp-0x18]
add    eax, esx
mov    DWORD PTR[rbp-0x4], eax
nop
pop    rbp
ret
Run Code Online (Sandbox Code Playgroud)

主要功能:

push …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc undefined-behavior

0
推荐指数
1
解决办法
94
查看次数

如何强制 g++ 内联 STL 函数

测试代码:

#include <array>

int test(const std::array<int, 10> &arr) {
    return arr[9];
}
Run Code Online (Sandbox Code Playgroud)

我要实现arr[0]像C风格数组一样高效,这意味着内联STL数组[]运算符函数。

我检查了生成汇编代码:

$ g++ --std=c++17  -c test.cpp && objdump -d -C test.o

test.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <test(std::array<int, 10ul> const&)>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 ec 10             sub    $0x10,%rsp
   8:   48 89 7d f8             mov    %rdi,0xfffffffffffffff8(%rbp)
   c:   48 8b 45 f8             mov    0xfffffffffffffff8(%rbp),%rax
  10:   be 09 00 00 00          mov    $0x9,%esi
  15:   48 89 …
Run Code Online (Sandbox Code Playgroud)

c++ gcc stl compiler-optimization

0
推荐指数
1
解决办法
224
查看次数

x86_64 Linux 系统的 GCC 调用约定

我编写了一个最小函数来测试是否可以调用/链接 C 和 x86_64 汇编代码。

这是我的main.c

#include <stdio.h>

extern int test(int);

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

    int a = 10;
    
    int b = test(a);

    printf("b=%d\n", b);

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

这是我的test.asm

section .text
    global test

test:
    mov ebx,2
    add eax,ebx
    ret
Run Code Online (Sandbox Code Playgroud)

我使用这个脚本构建了一个可执行文件

#!/usr/bin/env bash

nasm -f elf64 test.asm -o test.o

gcc -c main.c -o main.o

gcc main.o test.o -o a.out
Run Code Online (Sandbox Code Playgroud)

我写的时候test.asm并没有任何真正的线索我在做什么。然后我离开并做了一些阅读,现在我不明白我的代码是如何工作的,因为我说服自己它不应该这样。

以下是我认为这不起作用的原因列表:

  • 我不保存或恢复基指针(设置堆栈帧)。我实际上不明白为什么需要这样做,但我看过的每个例子都是这样做的。
  • Linux 系统上 gcc 编译器的调用约定应该是通过堆栈传递参数。这里我假设参数是使用eaxand传递的ebx。我认为这是不对的。
  • ret可能希望从某个地方获取返回地址。我相当确定我没有提供这个。
  • 甚至可能还有其他我不知道的原因。

我所编写的内容产生正确的输出完全是侥幸吗?

我对此完全陌生。虽然我顺便听说过一些 …

c linux gcc x86-64 calling-convention

0
推荐指数
1
解决办法
1196
查看次数

为什么没有内联这个C ++包装器类?

编辑 -我的构建系统有问题。我仍在弄清楚到底是什么,但是gcc产生了奇怪的结果(即使它是一个.cpp文件),但是一旦使用,g++它就会按预期工作。


对于我一直遇到的问题,这是一个非常减少的测试用例,其中使用数字包装器类(我认为应该内联)使我的程序慢10倍。

这与优化级别无关(使用-O0和尝试-O3)。

我在包装器类中缺少一些细节吗?


C ++

我有以下程序,其中定义了一个包装a double并提供+操作符的类:

#include <cstdio>
#include <cstdlib>

#define INLINE __attribute__((always_inline)) inline

struct alignas(8) WrappedDouble {
    double value;

    INLINE friend const WrappedDouble operator+(const WrappedDouble& left, const WrappedDouble& right) {
        return {left.value + right.value};
    };
};

#define doubleType WrappedDouble // either "double" or "WrappedDouble"

int main() {
    int N = 100000000;
    doubleType* arr = (doubleType*)malloc(sizeof(doubleType)*N);
    for (int i = 1; i < N; …
Run Code Online (Sandbox Code Playgroud)

c++ performance assembly compilation c++11

-1
推荐指数
1
解决办法
133
查看次数

如果速度更快,为什么编译器不将“n / 2.0”强制转换为“n * 0.5”?

我一直认为num * 0.5fnum / 2.0f是等价的,因为我认为编译器足够聪明,可以优化除法。所以今天我决定测试一下这个理论,但我发现的结果却难住了我。

给出以下示例代码:

float mul(float num) {
    return num * 0.5f;
}

float div(float num) {
    return num / 2.0f;
}
Run Code Online (Sandbox Code Playgroud)

x86-64 clang 和 gcc 都会生成以下汇编输出:

mul(float):
        push    rbp
        mov     rbp, rsp
        movss   DWORD PTR [rbp-4], xmm0
        movss   xmm1, DWORD PTR [rbp-4]
        movss   xmm0, DWORD PTR .LC0[rip]
        mulss   xmm0, xmm1
        pop     rbp
        ret
div(float):
        push    rbp
        mov     rbp, rsp
        movss   DWORD PTR [rbp-4], xmm0
        movss   xmm0, DWORD PTR [rbp-4]
        movss   xmm1, DWORD PTR …
Run Code Online (Sandbox Code Playgroud)

c c++ intrinsics compiler-optimization

-10
推荐指数
1
解决办法
224
查看次数