It is possible, with some work, to make this happen. So, the first thing you need to do is to separate the .text and .rodata segments, which I was only able to do by creating MEMORY areas manually, and then using them for each part of the code. GCC will never emit data into the code segments (and if it does, it's a bug). Here's an example 64-bit RISC-V linker script:
https://gist.github.com/fwsGonzo/9184d9352ef37bce0ad03e4cef0c0f13
However, the linker will refuse to remove the read-bit from the executable segment. To combat that we need to post-process the binary using chperm:
https://gist.github.com/fwsGonzo/e3dbcd9097953e7e113fd3f3ada04316
Simply call it like this:
chperm <file> 0 x
In CMake you would post-process it like this:
add_custom_command(
TARGET ${NAME} POST_BUILD
COMMAND ${CHPERM} ${CMAKE_CURRENT_SOURCE_DIR}/${NAME} 0 x
)
I wrote some words when I was implementing this feature for myself:
https://github.com/riscv/riscv-gnu-toolchain/issues/668