如何将变量传递给使用 gcc 编译的 intel 格式内联 asm 代码

2023-12-31

我想向您寻求一些帮助!我有一个包含大量 C 源代码的项目。大多数是用gcc编译的,但也有一些是用Intel编译器编译的。后面的代码在微软有很多内联asm代码MASM格式。我想用 gcc 编译整个项目并修改尽可能少的代码。所以我编写了一个 perl 脚本,它将 intel 格式内联 asm 转换为 GAS 格式。 (顺便说一句:我在 64 位 Linux 机器上编译为 32 位)。

我的问题是我必须在内联中为 gcc 指定asm("...")哪些 C 变量被传递到代码中添加:: [var1] "m" var1, [var2] "m" var2, ...线在最后。

这是避免这种明确规范的方法吗?

我的尝试:

虚拟测试 C 代码只是将目标 char 数组的 4 个字符替换为源 char 数组的元素(我知道这不是最好的方法。这只是一个愚蠢的例子)。

在原始函数中没有明确的规范,但它可以使用Intel编译器进行编译(对我来说很遗憾,但我没有测试这个,但它应该与Intel编译器一起工作,因为我是根据真实代码制作的)。LOOP标签被多次使用,甚至在同一个 C 源文件中也是如此。

#include <stdio.h>

void cp(char *pSrc, char *pDst) {
    __asm
    { 
        mov esi, pSrc
        mov edi, pDst
        mov edx, 4
LOOP:
        mov al, [esi]
        mov [edi], al
        inc esi
        inc edi
        dec edx
        jnz LOOP
    };
}   

int main() {
    char src[] = "abcd";
    char dst[] = "ABCD";

    cp(src, dst);
    printf("SRC: '%s', DST: '%s'\n", src, dst);
    return 0;
}

结果是:SRC: 'abcd', DST: 'abcd'

工作转换cp代码是(用gcc编译)。

GAS (AT&T) 格式(编译:gcc -ggdb3 -std=gnu99 -m32 -o asm asm.c)

void cp(char *pSrc, char *pDst) {
    asm(
        "mov %[pSrc], %%esi\n\t"
        "mov %[pDst], %%edi\n\t"
        "mov $4, %%edx\n\t"
"LOOP%=:\n\t"
        "mov (%%esi), %%al\n\t"
        "mov %%al, (%%edi)\n\t"
        "inc %%esi\n\t"
        "inc %%edi\n\t"
        "dec %%edx\n\t"
        "jnz LOOP%=\n\t"
        : [pDst] "=m" (pDst)
        : [pSrc] "m" (pSrc)
        : "esi", "edi", "edx", "al"
    );
}

Intel格式(编译:gcc -ggdb3 -std=gnu99 -m32 -masm=intel -o asm asm.c)

void cp(char *pSrc, char *pDst) {
    asm(".intel_syntax noprefix\n\t");
    asm(
        "mov esi, %[pSrc]\n\t"
        "mov edi, %[pDst]\n\t"
        "mov edx, 4\n\t"
"LOOP%=:\n\t"
        "mov al, [esi]\n\t"
        "mov [edi], al\n\t"
        "inc esi\n\t"
        "inc edi\n\t"
        "dec edx\n\t"
        "jnz LOOP%=\n\t"
        : [pDst] "=m" (pDst)
        : [pSrc] "m" (pSrc)
        : "esi", "edi", "edx", "al"
    );
    asm(".intel_syntax prefix");
}

两个代码都可以工作,但需要一些代码修改(插入“%”字符,收集变量,修改跳转标签和jump功能)。

我也尝试过这个版本:

void cp(char *pSrc, char *pDst) {
    asm(".intel_syntax noprefix\n\t");
    asm(
        "mov esi, pSrc\n\t"
        "mov edi, pDst\n\t"
        "mov edx, 4\n\t"
    "LOOP:\n\t"
        "mov al, [esi]\n\t"
        "mov [edi], al\n\t"
        "inc esi\n\t"
        "inc edi\n\t"
        "dec edx\n\t"
        "jnz LOOP\n\t"
    );
    asm(".intel_syntax prefix");
}

但它下降了

gcc -ggdb3 -std=gnu99 -masm=intel -m32 -o ./asm.exe ./asm.c
/tmp/cc2F9i0u.o: In function `cp':
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pSrc'
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pDst'
collect2: ld returned 1 exit status

有没有办法避免输入参数的定义并避免局部标签的修改?

ADDITION

我尝试使用全局变量。为了这g必须使用约束来代替m.

char pGlob[] = "qwer";
void cp(char *pDst) {
    asm(".intel_syntax noprefix\n\t"
            "mov esi, %[pGlob]\n\t"
            "mov edi, %[pDst]\n\t"
            "mov edx, 4\n\t"
    "LOOP%=:\n\t"
            "mov al, [esi]\n\t"
            "mov [edi], al\n\t"
            "inc esi\n\t"
            "inc edi\n\t"
            "dec edx\n\t"
            "jnz LOOP%=\n\t"
            ".intel_syntax prefix" : [pDst] "=m" (pDst) : [pGlob] "g" (pGlob) 
            : "esi", "edi", "edx", "al");
}

添加#2

I tried

            "lea esi, pGlob\n\t"  // OK
            "lea esi, %[_pGlob]\n\t"  // BAD
            //"lea esi, pGlob_not_defined\n\t"  // BAD
            //gcc failed with: undefined reference to `pGlob_not_defined'

编译为

            lea esi, pGlob
            lea esi, OFFSET FLAT:pGlob // BAD
            //compilation fails with: Error: suffix or operands invalid for `lea'

似乎只需要定义函数局部变量。全局变量可以添加到预告片中,但并不是真正必要的。两者都在工作:

            "mov esi, pGlob\n\t" // OK
            "mov esi, %[_pGlob]\n\t" // OK

编译为

             mov esi, OFFSET FLAT:pGlob
             mov esi, OFFSET FLAT:pGlob

我定义了一个函数局部变量。它必须在约束部分定义:

void cp(char *pDst) {
    char pLoc[] = "yxcv";
    asm(".intel_syntax noprefix\n\t"
...
        //"mov esi, pLoc\n\t" // BAD
        "mov esi, %[_pLoc]\n\t" // OK, 'm' BAD
...
       ".intel_syntax prefix" : [_pDst] "=m" (pDst) : [_pLoc] "g" (pLoc) 
       : "esi", "edi", "edx", "al");

不幸的是,应该确定什么是全局变量,什么是局部变量。这并不容易,因为 asm 代码可以定义在C宏甚至周围的函数都是不确定的。我认为只有预编译器有足够的信息。也许代码必须预编译gcc -E ....

我意识到,如果不在约束部分定义输出,优化器可以消除一些代码。

TIA!


是的,您确实需要明确指定寄存器。 GCC 不会为你做这件事。而且(通常)您不能将 C 变量名称放入 ASM 字符串中。

对我来说,你的最终代码块看起来非常好,但在 GCC 中你不需要选择自己使用哪些寄存器。您还应该使用volatile关键字以防止编译器认为代码没有执行任何操作,因为它没有输出。

尝试这个:

char pGlob[] = "qwer";
void cp(char *pDst) {
    asm volatile (".intel_syntax noprefix\n\t"
            "mov edx, 4\n\t"
    "LOOP%=:\n\t"
            "mov al, [%[pGlob]]\n\t"
            "mov [%[pDst]], al\n\t"
            "inc %[pGlob]\n\t"
            "inc %[pDst]\n\t"
            "dec edx\n\t"
            "jnz LOOP%=\n\t"
            ".intel_syntax prefix" :: [pGlob] "g" (pGlob), [pDst] "g" (pDst) : "edx");
}

通过这种方式,编译器会处理加载变量并为您选择寄存器(从而消除从一个寄存器到另一个寄存器的无意义的复制)。理想情况下,您还应该消除显式使用edx,但这里并不是真的有必要。

当然,在这个愚蠢的例子中,我只是用 C 重新编码整个事情,然后让编译器完成它的工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将变量传递给使用 gcc 编译的 intel 格式内联 asm 代码 的相关文章

随机推荐

  • dbExpress/未指定键

    我正在开发一个数据库程序 使用 dbExpress 组件 Delphi 7 通过以下组件从数据库检索数据 TSQLDataSet gt TDataSetProvider gt TClientDataSet gt TDatasource gt
  • 恢复已删除的存储库 github 问题

    我在 github 中的存储库已被删除 代码已恢复 但我们有很多 Github 问题想要恢复 有没有办法在删除后恢复它们 Thanks 您需要发电子邮件 email protected cdn cgi l email protection发
  • 如何检查编译后的二进制文件是 32 位还是 64 位?

    我有一台运行 Lion 的 Mac 并且刚刚下载了最新版本的 apache 我做了平常的事情 configure prefix Users daniels Sandbox make make install httpd 二进制文件是针对什么
  • 如何使用Android设计库中的TabLayout获取当前所选项目的位置

    我正在使用 android 设计库 TabLayout 来获取当前所选项目选项卡的位置 ViewPager pager ViewPager view findViewById R id pager MyPagerAdapter adapte
  • 如何处理 RSpec 和 Rails 中的模拟嵌套资源?

    我有一个用户阅读列表的嵌套资源 用户有很多阅读列表 我试图模拟控制器规格中的所有内容 但无法保持简洁 这是 show 操作之前的代码 reading lists mock Reading lists reading lists stub f
  • f2py 的附加编译器标志

    我想使用旗帜 ftree vectorize 编译器手册 https gcc gnu org projects tree ssa vectorization html 作为 f2py 使用的 gnu fortran 编译器的附加参数 根据f
  • 测试连接内解析 DnsName

    我想知道如何退回Resolve DnsName我的输出Test Connection脚本并将其添加到我创建的 CSV 中 我喜欢从中捕获名称 类型 TTL 部分 仅调用Resolve DnsName当 ping 不成功时 servers G
  • 在Java中,两个字符相加的结果是int还是char?

    添加时 a b 它产生 195 是输出数据类型char or int 添加 Java 字符 短整型或字节的结果是int 关于二进制数字提升的 Java 语言规范 http docs oracle com javase specs jls s
  • 在 Java 中反序列化序列化的 php 对象

    有谁知道是否有可能 实际上是否已经完成 在 php 中序列化对象并在 Java 中反序列化 java php 通信 也许需要一个适配器 你怎么认为 Thanks 有serialized php parser http code google
  • 使用 Jinja2 对 JavaScript 进行转义字符串?

    如何使用 Jinja2 转义 HTML 以便它可以用作 JavaScript jQuery 中的字符串 如果我使用 Django 的模板系统 我可以这样写 mydiv append html string escapejs 姜戈的 esca
  • 减去双打时的奇怪结果[重复]

    这个问题在这里已经有答案了 可能的重复 为什么 C 中的浮点运算不精确 https stackoverflow com questions 753948 why is floating point arithmetic in c impre
  • Matplotlib:重新排序子图

    Say that I have a figure fig which contains two subplots as in the example from the documentation http matplotlib org ex
  • 为什么 nuget 要安装一堆系统命名空间引用?

    我正在尝试从 nuget 安装一个库 我原本期望可能有 3 或 4 个不同的依赖项 但它安装了一大堆System依赖关系 这是日志 Attempting to gather dependency information for packag
  • Android Studio 2.3.3 首次运行时卡住

    我下载了安卓工作室2 3 3 https developer android com studio index html for Linux并将内容解压到 usr local then cd android studio bin 编辑了文件
  • 当我从 MainLayout 停止代码时,防止代码在我的页面上运行

    我有一个带有 MainLayout 的 Blazor PWA 应用程序和一堆页面 每当用户未登录时 我想将他们重定向到登录屏幕 如果我可以将它们从 MainLayout 重定向到登录屏幕 我已经知道用户尚未登录 那就太好了 我只是检查 co
  • 房间失效跟踪器初始化两次

    我有一个水平回收器视图 其中包含自定义项目 每个项目都可以保留当前项目在回收器视图中的位置 我想在使用拖放移动项目时更新项目位置 但是 当水平视图中的项目超过三个时 数据将被删除 请帮助我 源代码 https github com parm
  • 使用 Parse 和 PubNub 的 Android 聊天应用程序指南

    我正在尝试创建一个简单的 Android 聊天应用程序 用户可以在其中注册并拥有好友列表来开始对话 我打算使用Parse https parse com 对于数据库后端和PubNub http www pubnub com 对于实际的聊天频
  • 如何使用 AWS Amplify 和 Next.js 创建生产环境变量

    我有一个 API 密钥 需要它来访问 API 端点 在我的 Next js 应用程序中 我将此密钥存储在 env local像这样 API KEY qwerty123 我在我的getStaticProps与 process env 一起使用
  • Gcm电话注册错误

    我正在尝试设置一个应用程序来与 gcm 一起使用 但每次我收到phone registration error 错误 根据 Gcm 文档 此错误意味着 Incorrect phone registration with Google Thi
  • 如何将变量传递给使用 gcc 编译的 intel 格式内联 asm 代码

    我想向您寻求一些帮助 我有一个包含大量 C 源代码的项目 大多数是用gcc编译的 但也有一些是用Intel编译器编译的 后面的代码在微软有很多内联asm代码MASM格式 我想用 gcc 编译整个项目并修改尽可能少的代码 所以我编写了一个 p