求助:RISCV GCC汇编结果错误

shubao
书包 10月26日 字数 1613

安装riscv的官方工具链(.ident  "GCC: (GNU) 7.2.0"),后对一个c文件进行编译,启动-O3选项时候,编译得到的汇编程序与c代码不一致。

c代码为一个memset的实现,编译错误对应于第二个while语句对应的汇编:

void* memset(void* dest, int byte, size_t len)

{

if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) {

uintptr_t word = byte & 0xFF;

word |= word << 8;

word |= word << 16;

word |= word << 16 << 16;

uintptr_t *d = dest;

while (d < (uintptr_t*)(dest + len))

*d++ = word;

} else {

char *d = dest;

while (d < (char*)(dest + len))

*d++ = byte;

}

return dest;

}

gcc汇编产生的代码如下:

memset:

addi    sp,sp,-16

or      a5,a0,a2

sd      s0,0(sp)

sd      ra,8(sp)

andi    a5,a5,7

mv      s0,a0

add     a2,a0,a2      ## a2=dest+len

beqz    a5,.L345      ## 跳入第一个if{}

bleu    a2,a0,.L347   ## 第2个while不成立则跳转到return

sub     a2,a2,a0      ## ======

andi    a1,a1,0xff    ## ==着3行出错

call    memset        ## ======递归

.L347:

mv      a0,s0

ld      ra,8(sp)

ld      s0,0(sp)

addi    sp,sp,16

jr      ra

.L345:

andi    a4,a1,0xff

slli    a1,a4,8

or      a4,a4,a1

slli    a1,a4,16

or      a4,a4,a1

slli    a5,a4,32

or      a4,a4,a5

bleu    a2,a0,.L347

mv      a5,a0

.L348:

addi    a5,a5,8

sd      a4,-8(a5)

bgtu    a2,a5,.L348

mv      a0,s0

ld      ra,8(sp)

ld      s0,0(sp)

addi    sp,sp,16

jr      ra

这个可能是什么问题,如何避免?谢谢!

CSArch 计算机体系结构
5 个回复
zkr
Just Waiting. 10月26日

memset memcpy memmove等函数,不要用C写

特定情况下,GCC在C代码编译时,会自动调用这些函数进行优化,摊手

观察到过类似现象,在GCC 10.2下。或许有选项关闭,但没深入调研此事

【 在 shubao (书包) 的大作中提到: 】

: 安装riscv的官方工具链(.ident  "GCC: (GNU) 7.2.0"),后对一个c文件进行编译,启动-O3选项时候,编译得到的汇编程序与c代码不一致。

: c代码为一个memset的实现,编译错误对应于第二个while语句对应的汇编:

: void* memset(void* dest, int byte, size_t len)

: ...................

ArchLinux
a lightweight and flexible distribution 10月26日

你这个是因为GCC识别到你的一些代码和memset功能相同,所以把这些代码变成了一个call memset,而刚好你的函数名叫memset,所以变成了一个递归。

你可以用GCC的-ffreestanding选项让GCC不生成这个调用。

【 在 shubao (书包) 的大作中提到: 】

: 安装riscv的官方工具链(.ident  "GCC: (GNU) 7.2.0"),后对一个c文件进行编译,启动-O3选项时候,编译得到的汇编程序与c代码不一致。

: c代码为一个memset的实现,编译错误对应于第二个while语句对应的汇编:

: void* memset(void* dest, int byte, size_t len)

: ...................

zkr
Just Waiting. 10月26日

印象中,-nostartfiles -nostdlib -ffreestanding都不能关闭这种调用,10.2

【 在 ArchLinux (a lightweight and flexible distribution) 的大作中提到: 】

: 你这个是因为GCC识别到你的一些代码和memset功能相同,所以把这些代码变成了一个call memset,而刚好你的函数名叫memset,所以变成了一个递归。

: 你可以用GCC的-ffreestanding选项让GCC不生成这个调用。

ArchLinux
a lightweight and flexible distribution 10月27日

-ffreestanding可以,-fno-builtin也可以,glibc和musl这些C库编译的时候就会用这些选项。-nostartfiles和-nostdlib只影响链接时的行为,不影响代码生成,所以不能阻止GCC生成这些调用。

Compiler Explorer 的结果:

https://godbolt.org/z/bos4obchd

【 在 zkr (Just Waiting.) 的大作中提到: 】

: 印象中,-nostartfiles -nostdlib -ffreestanding都不能关闭这种调用,10.2

zkr
Just Waiting. 10月27日

Nice,有机会我再复现一下

工程默认带着-ffreestanding的,也出现过这个问题

【 在 ArchLinux (a lightweight and flexible distribution) 的大作中提到: 】

: -ffreestanding可以,-fno-builtin也可以,glibc和musl这些C库编译的时候就会用这些选项。-nostartfiles和-nostdlib只影响链接时的行为,不影响代码生成,所以不能阻止GCC生成这些调用。

: Compiler Explorer 的结果:

https://godbolt.org/z/bos4obchd

: ...................