相关疑难解决方法(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
查看次数

x86上的错误对齐指针

有人提供一个示例是否会因为错位而将指针从一种类型转换为另一种类型失败?

在对这个答案的评论中,两者都表示做了类似的事情

char * foo = ...;
int bar = *(int *)foo;
Run Code Online (Sandbox Code Playgroud)

如果启用了对齐检查,即使在x86上也可能导致错误.

set $ps |= (1<<18)在GDB中设置对齐检查标志后尝试生成错误条件,但没有任何反应.

工作(即非工作;))示例是什么样的?


答案中没有任何代码片段在我的系统上失败 - 我将尝试使用不同的编译器版本,稍后在不同的PC上.

顺便说一句,我自己的测试代码看起来像这样(现在也使用asm来设置AC标志和未对齐的读写):

#include <assert.h>

int main(void)
{
    #ifndef NOASM
    __asm__(
        "pushf\n"
        "orl $(1<<18),(%esp)\n"
        "popf\n"
    );
    #endif

    volatile unsigned char foo[] = { 1, 2, 3, 4, 5, 6 };
    volatile unsigned int bar = 0;

    bar = *(int *)(foo + 1);
    assert(bar == 0x05040302);

    bar = *(int *)(foo + 2);
    assert(bar == 0x06050403);

    *(int …
Run Code Online (Sandbox Code Playgroud)

c pointers casting alignment

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

如何在一个malloc调用中为数组和结构分配内存而不破坏严格的别名?

为可变大小的数组分配内存时,我经常这样做:

struct array {
    long length;
    int *mem;
};

struct array *alloc_array( long length)
{
    struct array *arr = malloc( sizeof(struct array) + sizeof(int)*length);
    arr->length = length;
    arr->mem = (int *)(arr + 1); /* dubious pointer manipulation */
    return arr;
}
Run Code Online (Sandbox Code Playgroud)

然后我使用这样的arrray:

int main()
{
    struct array *arr = alloc_array( 10);
    for( int i = 0; i < 10; i++)
        arr->mem[i] = i;
    /* do something more meaningful */
    free( arr);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这工作和编译没有警告.然而,最近我读到了严格的别名.根据我的理解,上面的代码在严格别名方面是合法的,因为通过它访问int *的内存不是通过它访问的内存struct array …

c memory-management strict-aliasing

18
推荐指数
2
解决办法
716
查看次数

为什么“对齐”在32位和64位系统上相同?

我想知道编译器是否会在32位和64位系统上使用不同的填充,因此我在一个简单的VS2019 C ++控制台项目中编写了以下代码:

struct Z
{
    char s;
    __int64 i;
};

int main()
{
    std::cout << sizeof(Z) <<"\n"; 
}
Run Code Online (Sandbox Code Playgroud)

我对每个“平台”设置的期望:

x86: 12
X64: 16
Run Code Online (Sandbox Code Playgroud)

实际结果:

x86: 16
X64: 16
Run Code Online (Sandbox Code Playgroud)

由于x86上的存储字大小为4个字节,因此这意味着它必须以i两个不同的字存储字节。所以我认为编译器将以这种方式进行填充:

struct Z
{
    char s;
    char _pad[3];
    __int64 i;
};
Run Code Online (Sandbox Code Playgroud)

所以我可以知道背后的原因是什么?

  1. 是否与64位系统具有前向兼容性?
  2. 由于在32位处理器上支持64位数字的限制?

c++ abi memory-alignment 32bit-64bit visual-c++

16
推荐指数
3
解决办法
2819
查看次数

C未定义的行为.严格别名规则或错误对齐?

我无法解释这个程序的执行行为:

#include <string> 
#include <cstdlib> 
#include <stdio.h>

typedef char u8;
typedef unsigned short u16;

size_t f(u8 *keyc, size_t len)
{
    u16 *key2 = (u16 *) (keyc + 1);
    size_t hash = len;
    len = len / 2;

    for (size_t i = 0; i < len; ++i)
        hash += key2[i];
    return hash;
}

int main()
{
    srand(time(NULL));
    size_t len;
    scanf("%lu", &len);
    u8 x[len];
    for (size_t i = 0; i < len; i++)
        x[i] = rand();

    printf("out %lu\n", f(x, len));
}
Run Code Online (Sandbox Code Playgroud)

因此,当使用带有gcc的-O3编译并使用参数25运行时,它会引发段错误.没有优化它工作正常.我已经对它进行了反汇编:它正在进行矢量化,并且编译器假定 …

c gcc strict-aliasing memory-alignment

13
推荐指数
3
解决办法
2368
查看次数

未对齐的内存访问是否总是导致总线错误?

根据维基百科页面分段错误,未对齐的内存访问可能导致总线错误.本文提供了有关如何触发总线错误的示例.在该示例中,我们必须启用对齐检查以查看总线错误.如果我们禁用这种对齐检查怎么办?

该程序似乎正常工作.我有一个程序经常访问未对齐的内存,并且它被很多人使用,但没有人向我报告总线错误或其他奇怪的结果.如果我们禁用对齐检查,未对齐内存的副作用是什么?

平台:我正在开发x86/x86-64.我也通过在Mac上用"gcc -arch ppc"编译它来尝试我的程序,它运行正常.

c memory-alignment

9
推荐指数
2
解决办法
6915
查看次数

是否由于未定义的行为导致错位负载?

是否由于void*未定义的行为导致错位负载?


以下是我对Clang及其消毒剂的看法:

bufhelp.h:146:29: runtime error: load of misaligned address 0x7fff04fdd0e1 for type 'const uintptr_t' (aka 'const unsigned long'), which requires 8 byte alignment
0x7fff04fdd0e1: note: pointer points here
 00 00 00  66 66 6f 6f 62 61 72 34  32 46 4f 4f 42 41 52 31  37 66 6f 6f 62 61 72 34  33 46 4f 4f 42
              ^ 
Run Code Online (Sandbox Code Playgroud)

这是演员阵容发挥作用的地方:

buf_xor(void *_dst, const void *_src1, const void *_src2, size_t len)
{
  ...
  ldst = (uintptr_t *)(void …
Run Code Online (Sandbox Code Playgroud)

c casting memory-alignment undefined-behavior

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

字对齐加载比x64处理器上的未对齐加载更快吗?

在x86/64(Intel/AMD 64位)处理器上,在字边界上对齐的变量是否比未对齐的加载操作更快?

我的一位同事辩称,未对齐的载荷很慢,应该避免.他引用了项目填充到结构中的单词边界,作为未对齐加载缓慢的证明.例:

struct A {
  char a;
  uint64_t b;
};
Run Code Online (Sandbox Code Playgroud)

结构A通常大小为16个字节.

另一方面,Snappy压缩器文档指出Snappy假设"未对齐的32位和64位加载和存储很便宜".根据源代码,英特尔32和64位处理器也是如此.

那么:这里的真相是什么?如果和未对齐的载荷减少多少?在哪种情况下?

c x86-64 alignment

6
推荐指数
3
解决办法
4822
查看次数

提取__m128i中每个布尔字节的低位?布尔数组到打包位图

(编者注:这个问题最初是: 一个人应该如何访问__m128i对象的m128i_i8成员或一般成员?,试图对GCC的定义使用MSVC特定的方法__m128i。但这是一个XY问题,并且已被接受。答案是关于XY问题。另一个答案确实回答了这个问题。)

我意识到Microsoft建议不要直接访问这些对象的成员,但是我需要对其进行设置,因此非常缺乏文档

我继续收到错误“我在'(我的var名)'中请求成员'm128i_i8',它是非类类型'wirelabel {aka __vector(2)long long int}'”的错误,因为我已包含所有正确的标头,并且可以识别__m128i变量。

注意1:wirelabel是__m128i的typedef,即在标头中存在

typedef __m128i wirelabel 
Run Code Online (Sandbox Code Playgroud)

注意2:使用注释 1的原因在下面的其他问题中进行了解释: tbb :: cache_aligned_allocator:通过__m128i获取“对成员的请求...非类类型的请求”。用户错误或错误?

注意3:我正在使用编译器g ++

注意4:以下问题不能回答我的问题,但会讨论相关信息为什么不直接访问__m128i字段?

我也知道有一个_mm_set_epi8函数,但是它要求您一次设置所有8位部分,而这对我来说目前不是一个选择。


接受答案的问题回答:

编辑:有人问我为什么我需要访问__m128i对象的16个8位部分中的每个细节,这是为什么:我有一个bool大小为'n * 128' 的数组(n为size_t ),我需要将它们存储在大小为'n'的'wirelabel'数组中。

现在,由于wirelabel只是__m128i的别名/ typedef(如果有区别,请纠正我),因此可以将128个布尔的“ n”个索引中的每个存储在“ wirelabel”数组中。

但是,为了做到这一点,我相信需要将每个8位转换为它的带符号等效项,并将其存储在数组中每个“ wirelabel”指针中的正确8位索引中。

c++ gcc sse intrinsics type-punning

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

在C/C++中对齐特定地址边界的内存是否仍能提高x86的性能?

许多低延迟开发指南讨论了在特定地址边界上对齐内存分配:

https://github.com/real-logic/simple-binary-encoding/wiki/Design-Principles#word-aligned-access

http://www.alexonlinux.com/aligned-vs-unaligned-memory-access

但是,第二个链接是从2008年开始的.在2019年,在地址边界上调整内存是否仍能提高英特尔CPU的性能?我认为英特尔CPU不再会因访问未对齐地址而导致延迟损失?如果没有,在什么情况下应该这样做?我应该对齐每个堆栈变量吗?类成员变量?

有没有人有任何例子表明他们在调整内存方面取得了显着的性能提升?

c c++ performance x86 latency

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