当前位置: 首页 > 知识库问答 >
问题:

GCC访问双机器字类型中的高/低机器字(包括asm)

白飞飙
2023-03-14

我使用各种双机字类型,例如x86_64上的(u)int128_t和i386上的(u)int64_t以及GCC中的ARM等。我正在寻找一个正确的/便携的/干净的方式来访问和操作单个实际的机器单词(大多数在汇编程序中)。例如。在32位计算机上,我想直接访问gcc内部使用的int64_t的高/低32位部分,而不使用下面这样愚蠢的易出错代码。类似地,对于我想要访问的“本机”128bit类型,gcc正在使用的64b部分(下面的示例不是“add”,因为“add”足够简单,而是一般的)。

考虑以下代码中的32bit ASM路径,将两个int128_t加在一起(可能是gcc的“本机”、机器的“本机”或机器的“半本机”);这是可怕的和难以维持(和缓慢)。

#define BITS 64
#if defined(USENATIVE)
// USE "NATIVE" 128bit GCC TYPE
typedef __int128_t int128_t;
typedef __uint128_t uint128_t;
typedef int128_t I128;
     #define HIGH(x) x
     #define HIGHVALUE(x) ((uint64_t)(x >> BITS))
     #define LOW(x) x
     #define LOWVALUE(x) (x & UMYINTMAX)
#else
typedef struct I128 {
    int64_t high;
    uint64_t low;
} I128;
     #define HIGH(x) x.high
     #define HIGHVALUE(x) x.high
     #define LOW(x) x.low
     #define LOWVALUE(x) x.low
#endif
     #define HIGHHIGH(x) (HIGHVALUE(x) >> (BITS / 2))
     #define HIGHLOW(x) (HIGHVALUE(x) & 0xFFFFFFFF)
     #define LOWHIGH(x) (LOWVALUE(x) >> (BITS / 2))
     #define LOWLOW(x) (LOWVALUE(x) & 0xFFFFFFFF)

inline I128 I128add(I128 a, const I128 b) {
#if defined(USENATIVE)
    return a + b;
#elif defined(USEASM) && defined(X86_64)
    __asm(
            "ADD %[blo], %[alo]\n"
            "ADC %[bhi], %[ahi]"
            : [alo] "+g" (a.low), [ahi] "+g" (a.high)
            : [blo] "g" (b.low), [bhi] "g" (b.high)
            : "cc"
            );
    return a;
#elif defined(USEASM) && defined(X86_32)
    // SLOWER DUE TO ALL THE CRAP
    int32_t ahihi = HIGHHIGH(a), bhihi = HIGHHIGH(b);
    uint32_t ahilo = HIGHLOW(a), bhilo = HIGHLOW(b);
    uint32_t alohi = LOWHIGH(a), blohi = LOWHIGH(b);
    uint32_t alolo = LOWLOW(a), blolo = LOWLOW(b);
    __asm(
            "ADD %[blolo], %[alolo]\n"
            "ADC %[blohi], %[alohi]\n"
            "ADC %[bhilo], %[ahilo]\n"
            "ADC %[bhihi], %[ahihi]\n"
            : [alolo] "+r" (alolo), [alohi] "+r" (alohi), [ahilo] "+r" (ahilo), [ahihi] "+r" (ahihi)
            : [blolo] "g" (blolo), [blohi] "g" (blohi), [bhilo] "g" (bhilo), [bhihi] "g" (bhihi)
            : "cc"
            );
    a.high = ((int64_t)ahihi << (BITS / 2)) + ahilo;
    a.low = ((uint64_t)alohi << (BITS / 2)) + alolo;
    return a;
#else
    // this seems faster than adding to a directly
    I128 r = {a.high + b.high, a.low + b.low};
    // check for overflow of low 64 bits, add carry to high
    // avoid conditionals
    r.high += r.low < a.low || r.low < b.low;
    return r;
#endif
}

请注意,我使用C/ASM不多,事实上这是我第一次尝试内联ASM。习惯了Java/C#/JS/PHP等,意味着一些对常规C开发程序来说非常明显的东西对我来说可能并不明显(除了代码风格中明显的不安全的怪异;))。此外,所有这些也可以被称为完全不同的东西,因为我很难在网上找到关于这个主题的东西(非母语者也是如此)。

多谢!

经过大量的挖掘,我找到了以下理论解决方案,这是可行的,但不必要的慢(慢于更长的gcc输出!)因为它迫使所有东西都存储起来,我正在寻找一个通用的解决方案(reg/mem/可能是imm)。我还发现,如果在32bit机器上对例如64bit int使用“r”约束,那么gcc实际上会将这两个值放入两个寄存器(例如eax和ebx)中。问题是无法可靠地访问第二部分。我肯定有一些隐藏运算符修饰符,很难找到它来告诉gcc我要访问第二部分。

    uint32_t t1, t2;
    __asm(
            "MOV %[blo], %[t1]\n"
            "MOV 4+%[blo], %[t2]\n"
            "ADD %[t1], %[alo]\n"
            "ADC %[t2], 4+%[alo]\n"
            "MOV %[bhi], %[t1]\n"
            "MOV 4+%[bhi], %[t2]\n"
            "ADC %[t1], %[ahi]\n"
            "ADC %[t2], 4+%[ahi]\n"
            : [alo] "+o" (a.low), [ahi] "+o" (a.high), [t1] "=&r" (t1), [t2] "=&r" (t2)
            : [blo] "o" (b.low), [bhi] "o" (b.high)
            : "cc"
            );
    return a;

共有1个答案

葛鸿熙
2023-03-14

我听说这个站点并不是真正用于“代码审查”的,但由于这对我来说是一个有趣的方面,我想我可以提供一些建议:

在32位版本中,您可以通过巧妙地叠加int/uint数组来执行highhigh和co.,而不是移位和安定。使用联合是实现这一点的一种方法,另一种是指针“魔术”。由于代码的汇编程序部分首先并不是特别可移植性,因此使用类型双关转换或非可移植性联合形式的非可移植性代码并不是什么大不了的事情。

编辑:依靠文字内的位置也可以。例如,只需在寄存器中传入输入和输出的地址,然后使用(%0+4)和(%1+4)来完成其余部分就可以了。

 类似资料:
  • 这不是重复的:| 我添加了一个用于管理goup的新机器人。通过此信息: 我的机器人是管理员 我的机器人隐私被禁用 “启用”-您的机器人只会接收以“/”符号开头或通过用户名提及机器人的消息。“禁用”-您的机器人将接收人们发送到组的所有消息。当前状态是:禁用成功!新状态是:禁用 bot可以读取除其他bot消息外的所有成员!但可以在回复中看到信息。 我的tg api是:https://github.co

  • 我在本地机器(Mac)上工作,其中有一个名为sqlvm的遗留虚拟机(这意味着我可以通过http://sqlvm:从本地主机访问这个虚拟机)。现在,我在应该连接到vm的同一个本地主机(我的Mac)中设置了几个docker容器(使用docker-compose)。< code>pymysql会引发一个异常: 如何将外部的“sqlvm”公开给内部 Docker 网络? 编辑:我尝试在yml文件中为相关容

  • 一些秘密需要通过PODS获取,秘密存储在GCP秘密管理器中,什么是安全有效的方法来获取pod中的秘密? 谢谢你!

  • 我有一个docker应用程序,我使用以下docker compose。yml运行它: 我有一个没有docker化的服务器在我的机器上运行,我可以通过访问它。我希望我的服务能够访问它。 我发现有人建议在我的服务配置中添加以下内容: 但是当我添加这个时,并尝试,我得到。当我尝试<code>curl时,也会出现同样的错误http://host.docker.internal:3000。 我拼命地尝试将端

  • 本文向大家介绍在Java中生成随机双精度型数字,包括了在Java中生成随机双精度型数字的使用技巧和注意事项,需要的朋友参考一下 为了在Java中生成随机双精度类型数字,我们使用java.util.Random类的方法。这将从随机生成器序列返回下一个介于0.0(含)和1.0(不含)之间的随机double值。 声明 -java.util.Random.nextDouble()方法声明如下- 让我们看一

  • 问题内容: 我正在尝试从Java签名的applet中读取便携式设备。…我在http://code.google.com/p/jmtp/w/list上找到了一个jmtp库 ,可以访问便携式设备,但是当我在其中运行时netbeans它给出了错误 我搜索后发现,我必须将.dll文件作为本机库包含在jmtp项目中…我右键单击项目并导航至属性,然后选择“运行”和“选择的VM选项”作为 并将该jmtp.dll