标签: inline-assembly

在Visual C++中是否有一个8位原子CAS(cmpxchg)内在的X64?

在32位Visual Studio C++中可以使用以下代码.是否有使用内在函数的64位等效项,因为64位版本的Visual Studio C++不支持内联ASM?

FORCEINLINE bool bAtomicCAS8(volatile UINT8 *dest, UINT8 oldval, UINT8 newval)
{
    bool result=false;
    __asm
    {
        mov     al,oldval
        mov     edx,dest
        mov     cl,newval
        lock cmpxchg    byte ptr [edx],cl
        setz    result
    }
    return(result);
}
Run Code Online (Sandbox Code Playgroud)

以下instrinsics在Visual Studio C++下编译

_InterlockedCompareExchange16
_InterlockedCompareExchange
_InterlockedCompareExchange64
_InterlockedCompareExchange128
Run Code Online (Sandbox Code Playgroud)

我正在寻找的是什么

_InterlockedCompareExchange8
Run Code Online (Sandbox Code Playgroud)

但这似乎并不存在.

64-bit x86-64 inline-assembly visual-c++

6
推荐指数
1
解决办法
1657
查看次数

在GCC风格的扩展内联asm中,是否可以输出"虚拟化"布尔值,例如进位标志?

如果我有以下C++代码来比较两个128位无符号整数,使用内联amd-64 asm:

struct uint128_t {
    uint64_t lo, hi;
};
inline bool operator< (const uint128_t &a, const uint128_t &b)
{
    uint64_t temp;
    bool result;
    __asm__(
        "cmpq %3, %2;"
        "sbbq %4, %1;"
        "setc %0;"
        : // outputs:
        /*0*/"=r,1,2"(result),
        /*1*/"=r,r,r"(temp)
        : // inputs:
        /*2*/"r,r,r"(a.lo),
        /*3*/"emr,emr,emr"(b.lo),
        /*4*/"emr,emr,emr"(b.hi),
        "1"(a.hi));
    return result;
}
Run Code Online (Sandbox Code Playgroud)

然后它将非常有效地内联,但有一个缺陷.返回值通过通用寄存器的"接口"完成,值为0或1.这会增加两个或三个不必要的额外指令,并减少比较操作,否则将完全优化.生成的代码看起来像这样:

    mov    r10, [r14]
    mov    r11, [r14+8]
    cmp    r10, [r15]
    sbb    r11, [r15+8]
    setc   al
    movzx  eax, al
    test   eax, eax
    jnz    is_lessthan
Run Code Online (Sandbox Code Playgroud)

如果我使用带有"bo"返回值的"sbb%0,%0"而不是带有"bool"返回值的"setc%0",那么还有两个额外的指令:

    mov    r10, [r14]
    mov    r11, [r14+8]
    cmp    r10, [r15] …
Run Code Online (Sandbox Code Playgroud)

assembly flags gcc boolean inline-assembly

5
推荐指数
2
解决办法
1585
查看次数

使用Delphi内联汇编程序创建类实例

我想要做的是,使用assembly,创建一个类实例,调用其中一个方法,然后释放实例.

我知道我错过了一些非常重要的东西,可能很简单,但我不知道是什么.

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TSomeClass = class(TObject)
  private
    FCreateDateTime: string;
  public
    constructor Create;
    procedure SayYeah;
  end;

constructor TSomeClass.Create;
begin
  FCreateDateTime := DateTimeToStr(Now);
end;

procedure TSomeClass.SayYeah;
begin
  Writeln('yeah @ ' + FCreateDateTime);
end;

procedure Doit;
asm
  CALL TSomeClass.Create; // <= Access Violation
  CALL TSomeClass.SayYeah;
  CALL TSomeClass.Free;
end;

begin
  try
    Doit;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
Run Code Online (Sandbox Code Playgroud)

仅供参考:我想了解如何在低水平实现这一目标,而不是另一种方式.

更新:

感谢Andreas Rejbrand,我找到了罪魁祸首:

Update2:

感谢Arnaud使用EBX而不是PUSH/POP EAX来发现缺陷

var
  TSomeClass_TypeInfo: Pointer;

procedure Doit; …
Run Code Online (Sandbox Code Playgroud)

delphi inline-assembly basm

5
推荐指数
2
解决办法
851
查看次数

从内联汇编访问结构成员?

我正在尝试使用内联汇编将一堆结构成员(Particle是指向此类结构的指针)加载到某些寄存器中。这是我最初的解决方案:

asm("mov    %1(%0), %%edx\n"
    "fld    %2(%0)\n"
    "fld    %3(%0)\n"
    "fld    %4(%0)\n"
    "fld    %5(%0)\n"
    "movups %6(%0), %%xmm1\n"
    "movups %7(%0), %%xmm2\n"
    "movups %8(%0), %%xmm3\n"
    "movups %9(%0), %%xmm4\n"
    :
    : "r" (Particle),
        "n" (offsetof(ptcParticle, Active)),
        "n" (offsetof(ptcParticle, Size)),
        "n" (offsetof(ptcParticle, Rotation)),
        "n" (offsetof(ptcParticle, Time)),
        "n" (offsetof(ptcParticle, TimeScale)),
        "n" (offsetof(ptcParticle, Colour)),
        "n" (offsetof(ptcParticle, Location)),
        "n" (offsetof(ptcParticle, Velocity)),
        "n" (offsetof(ptcParticle, Accel))
    : "%edx", "%st", "%st(1)", "%st(2)", "%st(3)", "%xmm1", "%xmm2",
        "%xmm3", "%xmm4"
);
Run Code Online (Sandbox Code Playgroud)

但它不起作用,因为 GCC 将这些偏移量输出为立即数字文字,如下所示:

mov     $0(%eax), %edx
fld     $44(%eax)
fld     $40(%eax)
fld     $8(%eax) …
Run Code Online (Sandbox Code Playgroud)

gcc gnu-assembler inline-assembly

5
推荐指数
1
解决办法
2597
查看次数

内联ASM的非传统呼叫

我正在使用一个专有的MCU,它有一个内置的金属库(掩模ROM).我正在使用的编译器是clang,它使用类似GCC的内联ASM.我遇到的问题是调用库,因为库没有一致的调用约定.虽然我找到了一个解决方案,但我发现在某些情况下,编译器会在调用之前立即对clobber进行优化,我认为我的工作方式有问题.这是我正在使用的代码:

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))(); //MASKROM_EchoByte is a 16-bit integer with the memory location of the function
}
Run Code Online (Sandbox Code Playgroud)

现在这有一个明显的问题,即当变量"asmHex"被声明为寄存器R1时,实际调用不使用它,因此编译器"不知道"在调用时保留R1.我使用以下代码来消除这种情况:

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))();
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
}
Run Code Online (Sandbox Code Playgroud)

这对我来说真的很难看,而且应该有更好的方法.另外我担心编译器可能会在两者之间做一些废话,因为调用本身并没有表明它需要asmHex变量.不幸的是,((volatile void(*)(int))(MASKROM_EchoByte))(asmHex)不起作用,因为它将遵循C-convention,它将参数放入R2 +(R1保留用于刮擦)

请注意,遗憾的是,更改Mask ROM库是不可能的,并且有太多常用的例程在C/C++中重新创建它们.

干杯,谢谢.

编辑:我应该注意,虽然我可以调用ASM块中的函数,但编译器对无调用函数进行了优化,并且通过调用汇编看起来没有调用.如果有某种方式指示内联ASM包含函数调用,我可以使用此路由,但否则返回地址可能会被破坏.在任何情况下我都无法找到办法.

c c++ embedded clang inline-assembly

5
推荐指数
1
解决办法
715
查看次数

x86_64 上的原子 16 字节操作

以下 16 字节原子操作是否正确实现?还有更好的选择吗?

typedef struct {
    uintptr_t low;
    uintptr_t high;
} uint128_atomic;


uint128_atomic load_relaxed(uint128_atomic const *atomic)
{
    uint128_atomic ret;
    asm volatile("xor %%eax, %%eax\n"
                 "xor %%ebx, %%ebx\n"
                 "xor %%ecx, %%ecx\n"
                 "xor %%edx, %%edx\n"
                 "lock; cmpxchg16b %1"
                 : "=A"(ret)
                 : "m"(*atomic)
                 : "cc", "rbx", "rcx");
    return ret;
}

bool cmpexch_weak_relaxed(
    uint128_atomic *atomic,
    uint128_atomic *expected,
    uint128_atomic desired)
{
    bool matched;
    uint128_atomic e = *expected;
    asm volatile("lock; cmpxchg16b %1\n"
                 "setz %0"
                 : "=q"(matched), "+m"(atomic->ui)
                 : "a"(e.low), "d"(e.high), "b"(desired.low), "c"(desired.high)
                 : "cc");
    return matched;
} …
Run Code Online (Sandbox Code Playgroud)

c x86-64 inline-assembly

5
推荐指数
1
解决办法
1874
查看次数

glibc的atomic_forced_read函数的目的是什么?

我试图理解atomic_forced_read定义的目的,它经常出现在malloc.c的GNU libc实现中。

我不太擅长内联汇编,但看起来这会返回完全相同的值,并且类型与输入值相同。我在这里缺少什么?

原子强制读取定义在atomic.h中

523 #ifndef atomic_forced_read
524 # define atomic_forced_read(x) \
525   ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
526 #endif
Run Code Online (Sandbox Code Playgroud)

链接到atomic.h

https://code.woboq.org/userspace/glibc/include/atomic.h.html

c glibc atomic libc inline-assembly

5
推荐指数
1
解决办法
507
查看次数

为什么局部变量不能在 GNU C 基本内联 asm 语句中使用?

main为什么我不能在基本 asm 内联中使用局部变量?它只允许在扩展汇编中使用,但为什么会这样呢?

(我知道局部变量在返回地址之后位于堆栈上(因此一旦函数返回就不能使用),但这不应成为不使用它们的原因)

以及基本汇编的示例:

int a = 10; //global a
int b = 20; //global b
int result;

int main() {
    asm ( "pusha\n\t"
          "movl a, %eax\n\t"
          "movl b, %ebx\n\t"
          "imull %ebx, %eax\n\t"
          "movl %eax, result\n\t"
          "popa");

    printf("the answer is %d\n", result);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

扩展的例子:

int main (void) {
    int data1 = 10;  //local var - could be used in extended
    int data2 = 20;
    int result;

    asm ( "imull %%edx, %%ecx\n\t"
          "movl %%ecx, %%eax" 
          : "=a"(result) …
Run Code Online (Sandbox Code Playgroud)

c gcc language-design inline-assembly

5
推荐指数
2
解决办法
2737
查看次数

如何在cython中调用C内联汇编asm?

如何asm()在cython中调用C语言的内联汇编函数?我尝试了一个简单的asm("mov $eax, 0x1") or __asm__(). 它 cythonizes 很好,直到asm-call,然后给我以下错误:

NameError:名称“asm”未定义

我将我的代码编译为python setup.py build_ext --inplace && python runids.py

c inline-assembly cython

5
推荐指数
1
解决办法
647
查看次数

Google 的“DoNotOptimize()”函数如何强制语句排序

我试图准确理解谷歌的DoNotOptimize()运作方式。

为了完整起见,以下是它的定义(对于 clang 和非常量数据):

template <class Tp>
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
  asm volatile("" : "+r,m"(value) : : "memory");
}
Run Code Online (Sandbox Code Playgroud)

据我了解,我们可以在如下代码中使用它:

start_time = time();
bench_output = run_bench(bench_inputs);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)

为了确保基准保持在关键部分:

start_time = time();
DoNotOptimize(bench_inputs);
bench_output = run_bench(bench_inputs);
DoNotOptimise(bench_output);
result = time() - start_time;
Run Code Online (Sandbox Code Playgroud)

具体来说,我不明白的是为什么这保证(是吗?)run_bench()不会移到上面start_time = time()

(有人在这个评论中问过这个问题,但我不明白答案)。

据我了解,上面DoNotOptimze()做了几件事:

  • 它强制value进入堆栈,因为它是通过 C++ 引用传递的。您不能有指向寄存器的指针,因此它必须位于内存中。
  • 因为value现在位于堆栈上,因此随后破坏内存(如在 asm 约束中完成的那样)将迫使编译器假设value通过调用DoNotOptimize(value).
  • (我不清楚+r,m …

benchmarking inline-assembly compiler-optimization google-benchmark instruction-reordering

5
推荐指数
1
解决办法
1312
查看次数