GCC是否优化程序集源文件?

如何解决GCC是否优化程序集源文件?

我可以使用GCC将汇编代码文件转换为可重新分配的文件。

gcc -c source.S -o object.o -O2

优化选项是否有效?我可以期望GCC优化我的汇编代码吗?

解决方法

否。

GCC将您的汇编源传递给预处理器,然后传递给汇编器。任何时候都不会进行任何优化。

,

如果您不想手动优化汇编语言,那么汇编语言是您选择源语言的错误选择。如果您想要类似asm的东西,但实际上是优化编译器的输入,也许可以考虑使用LLVM-IR。 (并且独立于ISA。)

公平地说,有 一些二进制到二进制的重新编译器/优化器,它们试图弄清楚什么是实现细节,什么是重要逻辑,并据此进行优化。 (也可以从asm源而不是机器代码中进行读取; asm和机器代码易于来回转换,并且具有接近1:1的映射)。但这不是汇编程序的工作。

汇编程序的工作通常只是忠实地将您编写的内容转换为asm。有一个工具可以做到这一点,这对于尝试更快地找出真正的 很有必要,而无需手工编写实际的机器代码。


有趣的是,对于GAS来说,GNU汇编器 具有一些针对x86的有限优化选项,即使您运行{{1 }}。 (您可以运行gcc -O2来查看前端如何调用其他程序来完成实际工作,以及使用哪些选项。)

使用gcc -v ...可以对C进行全面优化,并针对ASM进行GAS的次要窥孔优化。(或者gcc -Wa,-Os -O3 foo.c bar.S,不幸的是手册是错误的,{{1 }}错过了-Wa,-O2的一些优化,-Os-O2命令行中传递了-Wa,...,就像...通过GCC前面板传递链接器选项一样,结束。

GCC通常不会启用as的优化,因为它通常会提供GAS已经优化的asm。


GAS的优化仅适用于单独的单个指令,因此,仅当一条指令可以被具有完全相同架构效果的另一条指令替换(长度,因此对RIP的影响有所不同)。 micro -建筑效果(性能)也可以不同。这就是非尺寸优化的重点。

as(1) man page中,请注意,这些是-Wl,...选项,不是 as选项。

as

以较小的指令大小优化指令编码。 gcc-O0 | -O | -O1 | -O2 | -Os用64位编码64位寄存器加载指令 立即作为具有31位或32位的32位寄存器加载指令 32位立即数,对64位寄存器清除指令进行编码
具有32位寄存器清除指令,编码256位/ 512位 带128位VEX的VEX / EVEX向量寄存器清除指令 向量寄存器清除指令,对128位/ 256位EVEX进行编码 向量寄存器,带有VEX向量寄存器的加载/存储指令 加载/存储指令,并编码打包的128位/ 256位EVEX 打包128位/ 256位VEX的整数逻辑指令 整数逻辑。

-O包括-O1优化,并对256位/ 512位EVEX进行编码 具有128位EVEX向量的向量寄存器清除指令 注册清算说明。在64位模式下VEX编码 带有可交换源操作数的指令也将具有 如果允许使用2字节VEX前缀,则交换源操作数 形式,而不是3字节的形式。某些形式的AND和OR 两次指定相同的(寄存器)操作数也将是 更改为“测试”。

-O2包括-O1优化,并编码16位,32位和
64位寄存器测试,立即变为8位寄存器测试,
即时。 -Os关闭此优化。

(re:一些VEX / EVEX操作数大小和代码大小优化:Is vxorps-zeroing on AMD Jaguar/Bulldozer/Zen faster with xmm registers than ymm?以及我对Instruction Lengths的回答接近结尾的部分re:2 vs. 3字节VEX前缀)

很遗憾,-O2-O0发生了冲突,-O2实际上并未包含-Os中的所有内容。您无法获得将-Os优化为-O2test [re]dx,1test dl,1优化为-Os({{ }}。

or al,al不可编码,因此edx版本需要一个imm32。
test al,alnot useful for x86的一种过时的8080习语,除了有时在P6家族中,是为了避免寄存器读取停顿,而故意避免重写寄存器实际上是更好的,而不是避免加长寄存器。深度链。

-O2

test r/m32,imm8组装在一起(出于某些疯狂的原因,or al,al对现代AMD CPU具有.intel_syntax noprefix shufps xmm0,xmm0,0 vxorps zmm31,zmm31,zmm31 vxorps zmm1,zmm1,zmm1 vxorps ymm15,ymm15,ymm15 vpxord zmm15,zmm15,zmm15 vpxord ymm3,ymm14,ymm15 vpxord ymm3,ymm4,ymm15 vmovd xmm16,[rdi + 256] # can use EVEX scaled disp8 vmovd xmm0,[rdi + 256] # could use EVEX scaled disp8 but doesn't even with a -march enabling AVX512 xor rax,rax or al,al cmp dl,0 test rdx,1 mov rax,1 mov rax,-1 mov rax,0xffffffff80000000 .att_syntax movabs $-1,%rax movq $1,%rax movabs $1,%rax 支持,但对Intel最高不超过gcc -g -Wa,-msse2avx -Wa,-O2 -Wa,-march=znver2+avx512dq+avx512vl -c foo.s和某些Xeon Phi, Skylake-avx512就像GCC一样。所以我必须手动启用AVX512进行测试。

as源+反汇编

-march=

因此,不幸的是,即使没有必要使用EVEX,即使显式启用AVX512VL和AVX512DQ也无法使GAS为corei7选择较短的EVEX编码。也许这仍然是故意的:您可能希望一些函数使用AVX512,而有些则可以避免。如果使用ISA选项限制来捕获对ISA扩展的意外使用,则必须为整个此类文件启用AVX512。意外地找到使用EVEX的汇编器,可能会令人惊讶。

您可以使用objdump -dwrC -Mintel -S手动强制它。 (不幸的是,在编译C时,GCC并没有执行,0000000000000000 <.text>: .intel_syntax noprefix shufps xmm0,0 # -msse2avx just for fun 0: c5 f8 c6 c0 00 vshufps xmm0,0x0 vxorps zmm31,zmm31 # avoids triggering AVX512 frequency limit 5: 62 01 04 00 57 ff vxorps xmm31,xmm31,xmm31 vxorps zmm1,zmm1 # shorter,using VEX b: c5 f0 57 c9 vxorps xmm1,xmm1,xmm1 vxorps ymm15,ymm15 # missed optimization,could vxorps xmm15,xmm0 for a 2-byte VEX and still be a zeroing idiom f: c4 41 00 57 ff vxorps xmm15,xmm15,xmm15 vpxord zmm15,zmm15 # AVX512 mnemonic optimized to AVX1,same missed opt for source operands. 14: c4 41 01 ef ff vpxor xmm15,xmm15 vpxord ymm3,ymm15 # no optimization possible 19: c4 c1 0d ef df vpxor ymm3,ymm15 # reversed operands to allow 2-byte VEX 1e: c5 85 ef dc vpxor ymm3,ymm4 vmovd xmm16,[rdi + 256] # uses EVEX scaled disp8 because xmm16 requires EVEX anyway 22: 62 e1 7d 08 6e 47 40 vmovd xmm16,DWORD PTR [rdi+0x100] vmovd xmm0,[rdi + 256] # could use EVEX scaled disp8 but doesn't even with a -march enabling AVX512 29: c5 f9 6e 87 00 01 00 00 vmovd xmm0,DWORD PTR [rdi+0x100] xor rax,rax # dropped REX prefix 31: 31 c0 xor eax,eax or al,al 33: 84 c0 test al,0 # optimization to test dl,dl not quite legal: different effect on AF 35: 80 fa 00 cmp dl,0x0 test rdx,1 # partial optimization: only to 32-bit,not 8-bit 38: f7 c2 01 00 00 00 test edx,0x1 mov rax,1 3e: b8 01 00 00 00 mov eax,0x1 mov rax,-1 # sign-extended imm8 required 43: 48 c7 c0 ff ff ff ff mov rax,0xffffffffffffffff mov rax,0xffffffff80000000 4a: 48 c7 c0 00 00 00 80 mov rax,%rax # movabs forces imm64,despite -O2 51: 48 b8 ff ff ff ff ff ff ff ff movabs rax,0xffffffffffffffff movq $1,%rax # but explicit q operand size doesn't stop opt 5b: b8 01 00 00 00 mov eax,0x1 movabs $1,%rax 60: 48 b8 01 00 00 00 00 00 00 00 movabs rax,0x1 肯定是可以自由支配在任何地方使用AVX512指令。)

,

so.s

#define HELLO 0x5
mov $HELLO,%eax
mov $0x5,%eax
retq

gcc -O2 -c so.s -o so.o
objdump -d so.o

0000000000000000 <.text>:
   0:   b8 00 00 00 00          mov    $0x0,%eax
   5:   b8 05 00 00 00          mov    $0x5,%eax
   a:   b8 05 00 00 00          mov    $0x5,%eax
   f:   b8 05 00 00 00          mov    $0x5,%eax
  14:   c3                      retq  

它甚至没有预处理定义。

将so.s重命名为so

gcc -O2 -c so.S -o so.o
objdump -d so.o

0000000000000000 <.text>:
   0:   b8 05 00 00 00          mov    $0x5,%eax
  14:   c3                      retq 

它对定义进行预处理,但是没有进行优化。

更深入地了解以及传递给的内容

gcc -O2 -c -save-temps so.s -o so.o
[0][as]
[1][--64]
[2][-o]
[3][so.o]
[4][so.s]

cat so.s

#define HELLO 0x5
mov $HELLO,%eax
retq

gcc -O2 -c -save-temps so.S -o so.o
[0][as]
[1][--64]
[2][-o]
[3][so.o]
[4][so.s]

cat so.s
# 1 "so.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "so.S"


mov $0x5,%eax
retq

仍然没有优化。

应该足以证明。您可以执行一些链接时间优化,以正确构建对象,然后告知链接器。但是我怀疑它不是在机器代码级别上执行,而是在更高级别上重新生成代码。

int main ( void )
{
    return(5);
}
gcc -O2 so.c -save-temps -o so.o
cat so.s

    .file   "so.c"
    .section    .text.unlikely,"ax",@progbits
.LCOLDB0:
    .section    .text.startup,@progbits
.LHOTB0:
    .p2align 4,15
    .globl  main
    .type   main,@function
main:
.LFB0:
    .cfi_startproc
    movl    $5,%eax
    ret
    .cfi_endproc
.LFE0:
    .size   main,.-main
    .section    .text.unlikely
.LCOLDE0:
    .section    .text.startup
.LHOTE0:
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

从上方使用so.S

gcc -flto -O2 so.S -save-temps -o so.o
cat so.s

# 1 "so.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "so.S"


mov $0x5,%eax
retq

从上方使用so.c

gcc -flto -O2 so.c -save-temps -o so.o
cat so.s

.file   "so.c"
.section    .gnu.lto_.profile.3f5dbe2a70110b8,"e",@progbits
.string "x\234ca`d`a`"
.string "\222L\214"
.string ""
.string "o"
.ascii  "\016"
.text
.section    .gnu.lto_.icf.3f5dbe2a70110b8,@progbits
.string "x\234ca`d"
.string "\001\016\006\004`d\330|\356\347Nv\006"
.ascii  "\017\243\003I"
.text
.section    .gnu.lto_.jmpfuncs.3f5dbe2a70110b8,@progbits
.string "x\234ca`d"
.string "\001V\006\004"
.string "\213"
.string ""
.string ""
.string "\356"
.ascii  "\f"
.text
.section    .gnu.lto_.inline.3f5dbe2a70110b8,@progbits
.string "x\234ca`d"
.string "\001\021\006\004"
.string "\21203120\001\231l\013\344\231\300b"
.string "\n\031"
.ascii  "\352"
.text
.section    .gnu.lto_.pureconst.3f5dbe2a70110b8,@progbits
.string "x\234ca`d`f`"
.string "\222\f"
.string ""
.string "X"
.ascii  "\n"
.text
.section    .gnu.lto_main.3f5dbe2a70110b8,@progbits
.ascii  "x\234\035\216\273\016\001a\020\205\347\314\277\313\026\210\236"
.ascii  "B\253\3610^\301\003(<\300\376\330B\024\262\005\211\210r\223-"
.ascii  "\334[\3256\n\005\2117\020\n\211NH(\0043&9\2319\231o.\016\201"
.ascii  "4f\242\264\250 \202!p\270'jz\fha=\220\317\360\361bkp\b\226c\363"
.ascii  "\344\216`\216\330\333nt\316\251\005Jb/Qo\210rl%\216\233\276\327"
.ascii  "\r\3211L-\201\247(b\202\242^\230\241L\302\236V\237A6\025([RD"
.ascii  ":s\244\364\243E5\261\337o\333&q\336e\242\273H\037y0k6W\264\362"
.ascii  "\272`\033\255\337\031\275\315p\261\370\357\026\026\312\310\204"
.ascii  "\333\250Wj\364\003\t\210<\r"
.text
.section    .gnu.lto_.symbol_nodes.3f5dbe2a70110b8,@progbits
.string "x\234ca`d\020f"
.string "\002&\206z\006\206\t\347\030@\324\256\206@\240\b"
.ascii  "'\370\004\002"
.text
.section    .gnu.lto_.refs.3f5dbe2a70110b8,@progbits
.string "x\234ca`\004B "
.string ""
.string ""
.string "9"
.ascii  "\007"
.text
.section    .gnu.lto_.decls.3f5dbe2a70110b8,@progbits
.string "x\234\205PMK\002Q\024\275\347\315h\222\021R-\\\270\020\027\355\222\244\020\367A\355b6A\264\013\261p\221AmZ^\377\200DB\340N\004)\320j~A\bA\021\371\007J!\241e\277@\b\354\276y3\216\320\242\013\367\343\335w\3369\367]\233@\332\372\222V%\357\213O\304\224\344\003\nM\243\\\372k\272g\211/\211\257\210;\377\340\331\302w{\370\025\031\340\035\242\201D\202\022\004xC\350\344\225\306\275\243\024\312\213\024\266\020"
.ascii  "\375\263\nJ_\332\300u\317\344I`\001\211O\345\253i\006\302tB\363"
.ascii  "\b\360X\303\247Se\005\337h\226\330\260\316\360\032q\177\023A"
.ascii  "\224\337\337<\266\027\207\370\2502s\223\331\301T\322[#Q\224\331"
.ascii  "\326\373\204\2058\321\302S\203\235+\301\266\270\247\367%\004"
.ascii  "\215\376[\335\262\226\241\353\317\361\355v\266+\327|\311\254"
.ascii  "\n\341\216;?\265\227x\362Z\337\214\252\234\006\234yl\244\260"
.ascii  "\236\022\261\007$%\036\331\0069~\346V4\323d\327\345Q\375U\325"
.ascii  "\270\247GS\032\205;\031\342\036Y=\241\224\022\273\030\002\035"
.ascii  "\fd`\027\031\232\273(\344\327\362\233\024;.UJg\345\"\331'\207"
.ascii  "\345Jlgw/\275\225\313Q\344\3744[\244_\320\267k~"
.text
.section    .gnu.lto_.symtab.3f5dbe2a70110b8,@progbits
.string "main"
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
.string "\260"
.string ""
.string ""
.text
.section    .gnu.lto_.opts,@progbits
.string "'-fmath-errno' '-fsigned-zeros' '-ftrapping-math' '-fno-trapv' '-fno-openmp' '-fno-openacc' '-mtune=generic' '-march=x86-64' '-O2' '-flto' '-fstack-protector-strong'"
.text
.comm   __gnu_lto_v1,1,1
.comm   __gnu_lto_slim,1
.ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
.section    .note.GNU-stack,@progbits

因此,gcc似乎仍未进行任何优化,以删除这些重复的指令,这些指令没有功能优势,并且基本上是无效代码。它确实表明如果文件具有.S,则gcc将对其进行预处理,而如果.s没有,gcc将对其进行预处理(可以尝试或阅读其他.asm上的文档吗?)。这些文件在Linux上运行,gcc是gcc,binutils是binutils,特定文件名的扩展名敏感性可能因目标主机而异。

链接时间的优化似乎与高级代码有关,因为人们不希望汇编语言代码。人们期望链接时间优化基于中端代码而不是后端。

我们知道gcc不是汇编程序,即使它是从C生成的,它也只是将其传递给它,因此它需要一个汇编器解析器,然后需要逻辑来处理该语言,然后挑选出要传递的东西进行链接时间优化。

您可以阅读有关链接时间优化的更多信息,并查看是否有一种方法可以将其应用于汇编程序...我想没有,但是您的整个问题都与如何使用工具以及它们如何工作有关。

汇编语言优化并不一定是一回事,这很重要,现在对于伪指令有一些伪代码,汇编器可以选择优化的实现

ldr r0,=0x12345678
ldr r0,=0x1000
ldr r0,=0xFFFFFF12

00000000 <.text>:
   0:   e59f0004    ldr r0,[pc,#4]    ; c <.text+0xc>
   4:   e3a00a01    mov r0,#4096   ; 0x1000
   8:   e3e000ed    mvn r0,#237    ; 0xed
   c:   12345678    .word   0x12345678

但这是伪代码,因此支持它的汇编器可以自由地执行他们想要的任何事情。 (汇编程序定义汇编语言(而不是目标语言),因此根据定义,他们可以执行自己想要的任何事情)。关于这一点,当工具链中也有汇编器时,使用编译器作为汇编器,因为该工具定义了汇编语言,因此将其更改为另一种汇编语言。因此,当您允许gcc预处理代码时,您基本上使用的是与as不同的汇编语言。就像编译器的内联汇编一样,是另一种汇编语言。对于gnu工具链,每个目标至少需要三种汇编语言。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res