相关疑难解决方法(0)

在x86和x64上读取同一页面内的缓冲区末尾是否安全?

如果允许在输入缓冲区末尾读取少量数据,则可以(并且)简化在高性能算法中找到的许多方法.这里,"少量"通常意味着W - 1超过结束的字节,其中W是算法的字节大小(例如,对于处理64位块中的输入的算法,最多7个字节).

很明显,写入输入缓冲区的末尾通常是不安全的,因为您可能会破坏缓冲区1之外的数据.同样清楚的是,在缓冲区的末尾读取到另一页面可能会触发分段错误/访问冲突,因为下一页可能不可读.

但是,在读取对齐值的特殊情况下,页面错误似乎是不可能的,至少在x86上是这样.在该平台上,页面(以及因此内存保护标志)具有4K粒度(较大的页面,例如2MiB或1GiB,可能,但这些是4K的倍数),因此对齐的读取将仅访问与有效页面相同的页面中的字节缓冲区的一部分.

这是一个循环的规范示例,它对齐其输入并在缓冲区末尾读取最多7个字节:

int processBytes(uint8_t *input, size_t size) {

    uint64_t *input64 = (uint64_t *)input, end64 = (uint64_t *)(input + size);
    int res;

    if (size < 8) {
        // special case for short inputs that we aren't concerned with here
        return shortMethod();
    }

    // check the first 8 bytes
    if ((res = match(*input)) >= 0) {
        return input + res;
    }

    // align pointer to the next 8-byte …
Run Code Online (Sandbox Code Playgroud)

c optimization performance x86 assembly

33
推荐指数
2
解决办法
2027
查看次数

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

当使用内联汇编循环数组时,我应该使用寄存器修饰符"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
查看次数

使用simd查找角色的第一个实例

我试图找到一个字符的第一个实例,在这种情况下'''使用simd(AVX2或更早版本).我想使用_mm256_cmpeq_epi8,但是我需要一个快速的方法来查找是否有任何结果字节__m256i已设置为0xFF.然后计划使用_mm256_movemask_epi8将结果从字节转换为位,并使用ffs获取匹配的索引.使用_mm_movemask_epi8一次移出一部分是否更好?其他建议?

x86 sse simd avx avx2

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

GCC内联汇编:"g"约束和参数大小

背景

我知道使用内联汇编解决以下问题是个坏主意.我目前正在学习内联汇编作为linux内核类的一部分,这是该类的一个赋值的一部分.

安装程序

下面的开头是一段几乎正确的代码片段,而不是段错误.它是一个函数,它将src从索引处开始并在索引处s_idx结束(排他地)的子字符串复制e_idxdest仅使用内联汇编的预分配.

static inline char *asm_sub_str(char *dest, char *src, int s_idx, int e_idx) {
  asm("addq %q2, %%rsi;"  /* Add start index to src (ptrs are 64-bit) */
      "subl %k2, %%ecx;"  /* Get length of substr as e - s (int is 32-bit) */
      "cld;"              /* Clear direction bit (force increment) */
      "rep movsb;"        /* Move %ecx bytes of str at %esi into str at %edi */
      : /* No Ouputs …
Run Code Online (Sandbox Code Playgroud)

c assembly gcc inline-assembly

5
推荐指数
0
解决办法
419
查看次数

来自GCC内联汇编的系统调用

是否可以使用内联汇编块中的系统调用来编写单个字符?如果是这样,怎么样?它应该看起来像这样的"东西":

__asm__ __volatile__
                    (
                     " movl $1,  %%edx \n\t"
                     " movl $80, %%ecx \n\t"
                     " movl $0,  %%ebx \n\t"
                     " movl $4,  %%eax \n\t"
                     " int $0x80       \n\t"
                     ::: "%eax", "%ebx", "%ecx", "%edx"
                    );
Run Code Online (Sandbox Code Playgroud)

80美元是ascii中的'P',但是没有返回任何内容.

任何建议非常感谢!

c linux gcc system-calls inline-assembly

4
推荐指数
2
解决办法
3671
查看次数

"+&r"与"+ r"有什么不同?

GCC的内联汇编程序识别声明符=r=&r.这些对我来说很有意义:=r让汇编器重用输入寄存器来输出.

但是,GCC的内联汇编程序也承认声明者+r+&r.这些对我来说不太合理.毕竟,是不是区别+r+&r区别没有区别?是否+r仅仅告诉编译器保留一个仅用于单个变量的寄存器是不够的?

例如,以下GCC代码有什么问题?

#include <stdio.h>
int main()
{
    int a = 0;
    printf("Initially, a == %d.\n", a);
    /* The architecture is amd64/x86-64. */
    asm(
        "inc %[a]\n"
        : [a] "+r" (a)
        : : "cc"
    );
    printf("However, after incrementation, a == %d.\n", a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

顺便提一下,我的内联汇编缺少输入声明,因为在我的(可能是错误的)头脑中,+r封面输入,破坏,输出,一切.我有什么误会,拜托?

背景

我已经在汇编中编写了8位和16位微控制器,但在托管环境中编码汇编方面几乎没有经验.

c x86 gcc inline-assembly

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

GCC 内联程序集错误:“'int' 的操作数大小不匹配”

首先,如果有人知道标准 C 库的一个函数,该函数无需查找二进制零即可打印字符串,但需要绘制字符数,请告诉我!

否则,我有这个问题:

void printStringWithLength(char *str_ptr, int n_chars){

asm("mov 4, %rax");//Function number (write)
asm("mov 1, %rbx");//File descriptor (stdout)
asm("mov $str_ptr, %rcx");
asm("mov $n_chars, %rdx");
asm("int 0x80");
return;

}
Run Code Online (Sandbox Code Playgroud)

GCC 将以下错误告知“int”指令:

"Error: operand size mismatch for 'int'"
Run Code Online (Sandbox Code Playgroud)

有人可以告诉我这个问题吗?

c assembly gcc x86-64 inline-assembly

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

at&t asm inline c ++问题

我的守则

const int howmany = 5046;
char buffer[howmany];
    asm("lea     buffer,%esi"); //Get the address of buffer
    asm("mov     howmany,%ebx");         //Set the loop number
    asm("buf_loop:");                      //Lable for beginning of loop
    asm("movb     (%esi),%al");             //Copy buffer[x] to al
    asm("inc     %esi");                   //Increment buffer address
    asm("dec     %ebx");                   //Decrement loop count
    asm("jnz     buf_loop");              //jump to buf_loop if(ebx>0)
Run Code Online (Sandbox Code Playgroud)

我的问题

我正在使用gcc编译器.出于某种原因,我的缓冲区/ howmany变量在我的asm眼中是不确定的.我不知道为什么.我只想将缓冲区数组的起始地址移动到esi寄存器中,在将每个元素复制到al寄存器时循环"howmany"次.

c x86 assembly gcc inline-assembly

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

标签 统计

c ×7

gcc ×6

inline-assembly ×6

assembly ×5

x86 ×4

avx ×1

avx2 ×1

linux ×1

optimization ×1

performance ×1

simd ×1

sse ×1

system-calls ×1

x86-64 ×1