预处理
// a.c
#include <stdio.h>
#define MSG "Hello \
World!\n"
#define _str(x) #x
#define _concat(a, b) a##b
int main() {printf(MSG /* "hi!\n" */);
#ifdef __riscvprintf("Hello RISC-V!\n");
#endif_concat(pr, intf)(_str(RISC-V));return 0;
}
运行gcc -E a.c,gcc过程分为预处理-编译-汇编-链接-E就是做到预处理这一步
_str _concat都是函数式宏定义
ifdef ... #endif条件编译指令:__riscv:这是一个 编译器内置的预定义宏,只有在「编译 RISC-V 架构的程序」时,编译器才会自动定义这个宏;在 x86/x64(电脑常用)、ARM 等架构下,这个宏是未定义的。我电脑运行后 直接跳过他。
运行指令后变为:
# 6 "a.c"
int main() {printf("Hello World!\n" );printf("RISC-V");return 0;
}
verbose加入指令后会在终端输出两类关键信息:
1.gcc自身的版本,编译配置信息。2.gcc查找/加载头文件的全过程
终端输出:
#include "..." search starts here:
#include <...> search starts here:/usr/lib/gcc/x86_64-linux-gnu/11/include/usr/local/include/usr/include/x86_64-linux-gnu/usr/include

gcc -I 就是gcc一些新的头文件如果找不到了话用gcc -I 地址既可
前面其实都说到了,-risc_v部分
# 6 "a.c"
int main() {printf("Hello World!\n" );printf("Hello RISC-V!\n");printf("RISC-V");return 0;
}
执行
echo | gcc -dM -E - | sort > x86_64_macros.txt
echo | riscv64-linux-gnu-gcc -dM -E - | sort > riscv64_macros.txt
diff --color=auto x86_64_macros.txt riscv64_macros.txt
多出了这么一坨:

编译
语法解析与语义分析阶段该阶段对输入文件进行语法解析,将预处理记号转换为语法分析树。在生成语法分析树后,该阶段会执行语义分析,一方面计算表达式的类型,另一方面检查代码的语法合法性。此阶段不仅负责产生大部分编译器警告,还会捕获各类语法解析错误。该阶段的输出产物是抽象语法树(Abstract Syntax Tree,AST)。
!4 = !{i32 7, !"frame-pointer", i32 2} 没了,简单查了下这玩意是方便调试的,等于把它删了后gdb不太方便了
正如前文讲义所讲:volatile(禁止编译器对变量的优化)会被“严格执行”
源代码:
#include <stdio.h>
int main() { // compute 10 + 20int x = 10, y = 20;int z = x + y;printf("z = %d\n", z);return 0;
}
x86:.text.file "b.c".globl main # -- Begin function main.p2align 4, 0x90.type main,@function
main: # @main.cfi_startproc
# %bb.0:pushq %rbp.cfi_def_cfa_offset 16.cfi_offset %rbp, -16movq %rsp, %rbp.cfi_def_cfa_register %rbpsubq $16, %rspmovl $0, -4(%rbp)movl $10, -8(%rbp)movl $20, -12(%rbp)movl -8(%rbp), %eaxaddl -12(%rbp), %eaxmovl %eax, -16(%rbp)movl -16(%rbp), %esileaq .L.str(%rip), %rdimovb $0, %alcallq printf@PLTxorl %eax, %eaxaddq $16, %rsppopq %rbp.cfi_def_cfa %rsp, 8retq
.Lfunc_end0:.size main, .Lfunc_end0-main.cfi_endproc# -- End function.type .L.str,@object # @.str.section .rodata.str1.1,"aMS",@progbits,1
.L.str:.asciz "z = %d\n".size .L.str, 8.ident "Ubuntu clang version 14.0.0-1ubuntu1.1".section ".note.GNU-stack","",@progbits.addrsig.addrsig_sym printf
risc_v32:.text.attribute 4, 16.attribute 5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0".file "b.c".globl main # -- Begin function main.p2align 1.type main,@function
main: # @main
# %bb.0:addi sp, sp, -48 //开辟栈空间sd ra, 40(sp) # 8-byte Folded Spillsd s0, 32(sp) # 8-byte Folded Spilladdi s0, sp, 48li a0, 0sd a0, -40(s0) # 8-byte Folded Spillsw a0, -20(s0)li a0, 10sw a0, -24(s0) //从这开始复制相加li a0, 20sw a0, -28(s0)lw a0, -24(s0)lw a1, -28(s0)addw a0, a0, a1sw a0, -32(s0)lw a1, -32(s0)
.LBB0_1: # Label of block must be emittedauipc a0, %pcrel_hi(.L.str)addi a0, a0, %pcrel_lo(.LBB0_1)call printf@plt // 调用printf# kill: def $x11 killed $x10ld a0, -40(s0) # 8-byte Folded Reloadld ra, 40(sp) # 8-byte Folded Reloadld s0, 32(sp) # 8-byte Folded Reloadaddi sp, sp, 48ret
.Lfunc_end0:.size main, .Lfunc_end0-main# -- End function.type .L.str,@object # @.str.section .rodata.str1.1,"aMS",@progbits,1
.L.str:.asciz "z = %d\n".size .L.str, 8.ident "Ubuntu clang version 14.0.0-1ubuntu1.1".section ".note.GNU-stack","",@progbits.addrsig.addrsig_sym printf
优化后:.text.attribute 4, 16.attribute 5, "rv64i2p0_m2p0_a2p0_f2p0_d2p0_c2p0".file "b.c".globl main # -- Begin function main.p2align 1.type main,@function
main: # @main
# %bb.0:addi sp, sp, -16sd ra, 8(sp) # 8-byte Folded Spill
.LBB0_1: # Label of block must be emittedauipc a0, %pcrel_hi(.L.str)addi a0, a0, %pcrel_lo(.LBB0_1)li a1, 30 //直接加载立即数结果了call printf@pltli a0, 0ld ra, 8(sp) # 8-byte Folded Reloadaddi sp, sp, 16ret
.Lfunc_end0:.size main, .Lfunc_end0-main# -- End function.type .L.str,@object # @.str.section .rodata.str1.1,"aMS",@progbits,1
.L.str:.asciz "z = %d\n".size .L.str, 8.ident "Ubuntu clang version 14.0.0-1ubuntu1.1".section ".note.GNU-stack","",@progbits.addrsig







