Minimal reproducer: $ echo 'int main(){}' | sh4-unknown-linux-gnu-gcc-8.1.0 -fPIE -pie -x c - -o a.out -ggdb3 -Wl,-z,text /usr/libexec/gcc/sh4-unknown-linux-gnu/ld: read-only segment has dynamic relocations. collect2: error: ld returned 1 exit status Analysis: $ echo 'int main(){}' | sh4-unknown-linux-gnu-gcc-8.1.0 -fPIE -pie -x c - -o a.out -ggdb3 $ objdump -d -R a.out | fgrep -C30 R_SH_ 000003f8 <_start>: 3f8: 00 ee mov #0,r14 3fa: f6 65 mov.l @r15+,r5 3fc: f3 66 mov r15,r6 3fe: 46 2f mov.l r4,@-r15 400: 06 d0 mov.l 41c <_start+0x24>,r0 ! 5cc <__libc_csu_fini> 402: 06 2f mov.l r0,@-r15 404: 03 d4 mov.l 414 <_start+0x1c>,r4 ! 54c <main> 406: 04 d7 mov.l 418 <_start+0x20>,r7 ! 564 <__libc_csu_init> 408: 05 d1 mov.l 420 <_start+0x28>,r1 ! 0 40a: 0b 41 jsr @r1 40c: 09 00 nop 40e: 05 d1 mov.l 424 <_start+0x2c>,r1 ! 0 410: 0b 41 jsr @r1 412: 09 00 nop 414: 4c 05 mov.b @(r0,r4),r5 414: R_SH_RELATIVE *ABS*+0x54c 416: 00 00 .word 0x0000 418: 64 05 mov.b r6,@(r0,r5) 418: R_SH_RELATIVE *ABS*+0x564 41a: 00 00 .word 0x0000 41c: cc 05 mov.b @(r0,r12),r5 41c: R_SH_RELATIVE *ABS*+0x5cc ... 420: R_SH_DIR32 __libc_start_main@GLIBC_2.2 424: R_SH_DIR32 abort@GLIBC_2.2 Note: _start symbol refers to abort, __libc_start_main via dynamic relocation right in .text section: https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sh/start.S;h=f52077abca02fd624b22d8477b1a4406d7094a1d;hb=HEAD#l91 Ideally it ought to go through GOT+PLT mechanism (if possible) and not store absolute address in the .text section. Thanks!