相关疑难解决方法(0)

使用内联汇编在数组上循环

当使用内联汇编循环数组时,我应该使用寄存器修饰符"r"还是内存修饰符"m"?

让我们考虑其将两个浮标阵为例x,与y和结果写入z.通常我会使用内在函数这样做

for(int i=0; i<n/4; i++) {
    __m128 x4 = _mm_load_ps(&x[4*i]);
    __m128 y4 = _mm_load_ps(&y[4*i]);
    __m128 s = _mm_add_ps(x4,y4);
    _mm_store_ps(&z[4*i], s);
}
Run Code Online (Sandbox Code Playgroud)

这是我使用寄存器修饰符"r"提出的内联汇编解决方案

void add_asm1(float *x, float *y, float *z, unsigned n) {
    for(int i=0; i<n; i+=4) {
        __asm__ __volatile__ (
            "movaps   (%1,%%rax,4), %%xmm0\n"
            "addps    (%2,%%rax,4), %%xmm0\n"
            "movaps   %%xmm0, (%0,%%rax,4)\n"
            :
            : "r" (z), "r" (y), "r" (x), "a" (i)
            :
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

这会产生与GCC类似的组装.主要区别在于GCC将16添加到索引寄存器并使用1的标度,而内联汇编解决方案将4添加到索引寄存器并使用4的标度.

我无法使用通用寄存器作为迭代器.在这种情况下,我必须指定一个rax.是否有一个原因?

这是我想出的使用内存修饰符"m"的解决方案

void add_asm2(float *x, float *y, …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc inline-assembly

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

为什么局部变量不能在 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
查看次数

正确调用内联汇编的方法

我正在探索在C++源代码中包含汇编.现在看来,这始于一个电话asm(),但我也看到了_asm()__asm().下划线之间有什么区别?如果相关,我最感兴趣的是GNU编译器.

编辑:来自这个论坛

_asm - simply invokes the inline assembler
__asm - is treated like an intrinsic function call
Run Code Online (Sandbox Code Playgroud)

不确定这是真的还是胡扯?

c++ assembly

4
推荐指数
1
解决办法
585
查看次数

在不使用C库的情况下在0xb8000处显示文本视频内存

我一直在用C编写内核.我一直在使用GCC交叉编译器,在Windows系统上编写并以16位实模式为目标.我没有可用于编写内核的C库.我已经开始使用一些代码来假设将字符直接打印到屏幕上.这是一个函数来自kernel.c:

int main()
{
  char *src = (char *)0xB8000000L;
  *src = 'M';
  src += 2;
  *src = 'D';
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我使用GCC编译了我的代码,并使用参数-m16生成将在实模式下运行的代码.我使用这些命令来生成我的kernel.bin:

gcc -ffreestanding -c -m16 kernel.c -o kernel.o
ld -Ttext 0x10000 -o kernel.pe kernel.o
objcopy -O binary kernel.pe kernel.bin
Run Code Online (Sandbox Code Playgroud)

Stack Overflow用户Michael Petch解决了我的链接器问题,但评论代码本身是不正确的.他发表了这样的评论:

除链接器问题外,您是否尝试将旧的TurboC/MSVC 16位代码转换为GCC?我发现(char*)0xB8000000L可疑.如果它是一个真正的16位C编译器,它可能是好的,如果它是(char far*)0xB8000000L.GCC不是一个真正的16位C编译器,并没有旧式远指针的概念.所以,即使你得到这个代码进行编译,这可能不会做你认为它做的,我假设从-m16选项与GCC你正在尝试创建一个实模式16位内核(而不是保护模式一个) )?

我一直在尝试printf在C中为我自己的操作系统实现自己的类似功能.我上面提供的代码只是我理解的一小部分.我在程序集中创建了一个bootloader(8086).

迈克尔是对的吗?如果是这样,我该如何解决这个问题并直接写入视频内存0xb8000

assembly kernel real-mode osdev x86-16

4
推荐指数
1
解决办法
1349
查看次数

::"r" 与 :"=r" 汇编说明

我试图理解汇编语言的语法,首先正确地编写代码,然后高效地编写代码。在此示例中,它显示了使用的示例"=r"

asm volatile ("MRS %0, PMUSERENR_EL0\n": "=r"(value));
Run Code Online (Sandbox Code Playgroud)

这会读取寄存器的值并将其存储在值变量中。另一个例子使用::"r"

asm volatile ("MSR PMUSERENR_EL0, %0\n":: "r"(value));
Run Code Online (Sandbox Code Playgroud)

这会将值变量写入 PMUSERENR_ELO 寄存器。这是另一个例子:如何测量 ARM Cortex-A8 处理器中的程序执行时间?

当我尝试使用上述两个命令编译一个简单的测试代码时,我收到错误::9:2: error: output operand constraint lacks '='如果我添加“=”并删除一个“:”,它将编译,但当我测试它时,它只是说Illegal instruction

如果有人可以解释其中的差异,这将很有帮助,许多组装教程显示相同的格式但没有解释。如果这提供了任何见解的话,它是在 64 位 ARM 平台上进行的。谢谢。

c assembly gcc inline-assembly arm64

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

如何将输入传递给扩展的asm?

从我之前的问题中考虑这段代码.

int main(){
    asm("movq $100000000, %rcx;"
            "startofloop: ; "
            "sub $0x1, %rcx; "
            "jne startofloop; ");
}
Run Code Online (Sandbox Code Playgroud)

我想将循环的迭代次数变为C变量,所以在阅读本文后我尝试了以下内容.

int main(){                                      
    int count = 100000000;                       
    asm("movq %0, %rcx;"                         
            "startofloop: ; "                    
            "sub $0x1, %rcx; "                   
            "jne startofloop; ":: "r"(count));   
}                                                
Run Code Online (Sandbox Code Playgroud)

不幸的是,这无法编译,并打破以下错误.

asm_fail.c: In function ‘main’:
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter
     asm("movq %0, %rcx;"
     ^
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter
Run Code Online (Sandbox Code Playgroud)

将C变量的值传递给程序集的正确方法是什么?

c gcc x86-64 inline-assembly att

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

汇编 - 为什么这个 CALL 函数不起作用?

我不明白为什么这段代码中的 CALL 函数不起作用:

#include<stdio.h>

void main() {

    __asm {

        jmp L1

        L2:
        mov eax, 8
        ret

        L1:
        call L2
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我一步一步调试代码,'call L1'行没有被处理,程序直接跳到最后。怎么了?我正在使用 Intel 32 位寄存器开发 VisualStudio2015。

debugging assembly call

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

有关strlen不同实现的性能的问题

我已经实现了strlen()以不同的方式,包括功能SSE2 assemblySSE4.2 assembly并且SSE2 intrinsic,我也产生了一些实验,请用strlen() in <string.h>strlen() in glibc。但是,以毫秒(时间)为单位的性能是出乎意料的。

我的实验环境: CentOS 7.0 + gcc 4.8.5 + Intel Xeon

以下是我的实现:

  1. strlen 使用SSE2程序集

    long strlen_sse2_asm(const char* src){
    long result = 0;
    asm(
        "movl %1, %%edi\n\t"
        "movl $-0x10, %%eax\n\t"
        "pxor %%xmm0, %%xmm0\n\t"
        "lloop:\n\t"
            "addl $0x10, %%eax\n\t"
            "movdqu (%%edi,%%eax), %%xmm1\n\t"
            "pcmpeqb %%xmm0, %%xmm1\n\t"
            "pmovmskb %%xmm1, %%ecx\n\t"
            "test %%ecx, %%ecx\n\t"
            "jz lloop\n\t"
    
        "bsf %%ecx, %%ecx\n\t"
        "addl %%ecx, %%eax\n\t"
        "movl %%eax, %0"
        :"=r"(result)
        :"r"(src)
        :"%eax" …
    Run Code Online (Sandbox Code Playgroud)

performance gcc sse inline-assembly intrinsics

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

clang汇编程序的奇怪行为

我试图编译Zend引擎的这个溢出检测宏:

#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval) do {   \
    long __tmpvar;                                                  \
    __asm__( \
        "mul %0, %2, %3\n"                                      \
        "smulh %1, %2, %3\n"                                        \
        "sub %1, %1, %0, asr #63\n"                                 \
            : "=X"(__tmpvar), "=X"(usedval)                         \
            : "X"(a), "X"(b));                                      \
    if (usedval) (dval) = (double) (a) * (double) (b);              \
    else (lval) = __tmpvar;                                         \
} while (0)
Run Code Online (Sandbox Code Playgroud)

并在装配中得到了这个结果:

; InlineAsm Start
mul     x8, x8, x9
smulh   x9, x8, x9
sub x9, x9, x8, asr #63

; InlineAsm End
Run Code Online (Sandbox Code Playgroud)

编译器仅对宏的输入和输出使用2个寄存器,我认为它必须至少为3,并导致错误的计算结果(例如,-1*-1).有什么建议吗?

assembly gcc llvm clang

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

将Pentium II定时代码转换为内联汇编?

我试图在GCC中使用以下代码.它抛出错误(我猜是因为__asm).为什么这种简单易用的格式在GCC中不起作用?这里提供了扩展汇编的语法.当在内联汇编中使用更多变量时,我感到困惑.有人可以将以下程序转换为适当的形式,并在有变量使用的地方给出必要的解释.

    int time, subtime;
    float x = 5.0f;
    __asm {
            cpuid
            rdtsc
            mov     subtime, eax
            cpuid
            rdtsc
            sub     eax, subtime
            mov     subtime, eax    // Only the last value of subtime is kept
            // subtime should now represent the overhead cost of the
            // MOV and CPUID instructions
            fld     x
            fld     x
            cpuid                   // Serialize execution
            rdtsc                   // Read time stamp to EAX
            mov     time, eax
            fdiv                    // Perform division
            cpuid                   // Serialize …
Run Code Online (Sandbox Code Playgroud)

x86 assembly gcc code-conversion visual-c++

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