What is the difference between the classification of the text, data and bss segments of Clang and GCC?

I compiled FreeRTOS using arm-none-eabi-gcc and clang respectively. When I used the size tool to view the size of each segment, I found the following differences.
gcc-text| gcc-data| gcc-bss| clang-text| clang-data| clang-bss
O0| 4772| 20| 19752| 5228| 16412| 3392|
O1| 3228| 20| 19752| 3596| 16412| 3392|
O2| 3228| 20| 19752| 4368| 16412| 3392|
O3| 4308| 20| 19752| 4732| 16416| 3452|
Og| 3272| 20| 19752| 3596| 16412| 3392|
Os| 2980| 20 | 19752| 3588| 16412| 3392|
Ofast| 4308| 20| 19752| 4732| 16416| 3452|

The total size of the data section and the bss section of the two compilers is similar, but it seems that what is in the bss section is included in the data section by clang, while GCC is just the opposite.What is the specific reason?

I’m assuming you have used the same linker in both cases (arm-none-eabi-ld)? If you haven’t (ld.lld for clang) it will be good to try the same linker to rule out any difference in linker script handling.

A compiler can always choose to put a data value that is 0 into .data instead of .bss, for example at least one compiler I knew of used .data for small amounts of ZI data so that it could use access all local variables in the .data via .data+offset. However in general I expect zero-initialized data to go into .bss. Things like named sections can have an effect though.

I would not expect a significant difference between clang and gcc across all optimisation levels. I expect it may well be down to a handful of large, or heavily aligned variables. Possibly in named sections (__attribute__((section("name"))) although I think both gcc and clang use the same name conventions to allocate these to .bss or .data.

In summary difficult to know why there is a difference without some more data. If it were me I would first try and eliminate linker differences. Then I’d look for differences in individual object files to see if it were limited to a small number of variables, or widely distributed, then I’d look at the source code to see if there any patterns that might hint at what is happening.

The data given above is indeed from two different linkers, arm-none-eabi-ld and lld. I tried to use the arm-none-eabi-ld linker after the program was compiled by Clang. The division of its data segment and bss segment is basically consistent with that of GCC.Although different compilers are used, the link script is used in GCC project, and I haven’t changed it. Do you think the reason for this difference is the link script?

Unless there is a PHDR section of the linker script the linker has to generate “appropriate” program headers (segments) from the linker script and that is at the linker’s discretion. There may also be orphan sections that the linker can place at its discretion.

I would think it more likely that large differences will be down to interpretations of the linker script than clang/gcc. Anyway you can rule it out fairly quickly by using the clang and gcc -fuse-ld=bfd or -fuse-ld=lld to pick the linker.