diff mbox series

[v3,2/2] firmware: Support position independent execution

Message ID 1615943798-14296-3-git-send-email-vincent.chen@sifive.com
State Accepted
Headers show
Series Support position independent execution | expand

Commit Message

Vincent Chen March 17, 2021, 1:16 a.m. UTC
Enable OpenSBI to support position independent execution. Because the
position independent code will cause an additional GOT reference when
accessing the global variables, it will reduce performance a bit. Therefore,
the position independent execution is disabled by default. Users can
through specifying "FW_PIC=y" on the make command to enable this feature.

In theory, after enabling position-independent execution, the OpenSBI
can run at arbitrary address with appropriate alignment. Therefore, the
original relocation mechanism will be skipped. In other words, OpenSBI will
directly run at the load address without any code movement.

Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
---
 Makefile                |  2 +-
 firmware/fw_base.S      | 62 ++++++++++++++++++++++++++++++++++++++++++++++++-
 firmware/fw_base.ldS    | 13 +++++++++++
 firmware/objects.mk     |  7 ++++++
 include/sbi/riscv_elf.h | 14 +++++++++++
 5 files changed, 96 insertions(+), 2 deletions(-)
 create mode 100644 include/sbi/riscv_elf.h

Comments

Anup Patel March 17, 2021, 11:46 a.m. UTC | #1
> -----Original Message-----
> From: opensbi <opensbi-bounces@lists.infradead.org> On Behalf Of Vincent
> Chen
> Sent: 17 March 2021 06:47
> To: opensbi@lists.infradead.org
> Cc: Vincent Chen <vincent.chen@sifive.com>
> Subject: [PATCH v3 2/2] firmware: Support position independent execution
> 
> Enable OpenSBI to support position independent execution. Because the
> position independent code will cause an additional GOT reference when
> accessing the global variables, it will reduce performance a bit. Therefore, the
> position independent execution is disabled by default. Users can through
> specifying "FW_PIC=y" on the make command to enable this feature.
> 
> In theory, after enabling position-independent execution, the OpenSBI can
> run at arbitrary address with appropriate alignment. Therefore, the original
> relocation mechanism will be skipped. In other words, OpenSBI will directly
> run at the load address without any code movement.
> 
> Signed-off-by: Vincent Chen <vincent.chen@sifive.com>

Looks good to me.

Reviewed-by: Anup Patel <anup.patel@wdc.com>

Regards,
Anup

> ---
>  Makefile                |  2 +-
>  firmware/fw_base.S      | 62
> ++++++++++++++++++++++++++++++++++++++++++++++++-
>  firmware/fw_base.ldS    | 13 +++++++++++
>  firmware/objects.mk     |  7 ++++++
>  include/sbi/riscv_elf.h | 14 +++++++++++
>  5 files changed, 96 insertions(+), 2 deletions(-)  create mode 100644
> include/sbi/riscv_elf.h
> 
> diff --git a/Makefile b/Makefile
> index d6f097d..038cc99 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -210,8 +210,8 @@ CFLAGS		+=	-
> mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
>  CFLAGS		+=	-
> mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
>  CFLAGS		+=	$(GENFLAGS)
>  CFLAGS		+=	$(platform-cflags-y)
> -CFLAGS		+=	$(firmware-cflags-y)
>  CFLAGS		+=	-fno-pie -no-pie
> +CFLAGS		+=	$(firmware-cflags-y)
> 
>  CPPFLAGS	+=	$(GENFLAGS)
>  CPPFLAGS	+=	$(platform-cppflags-y)
> diff --git a/firmware/fw_base.S b/firmware/fw_base.S index
> 6cc5f88..2ce3851 100644
> --- a/firmware/fw_base.S
> +++ b/firmware/fw_base.S
> @@ -9,6 +9,7 @@
> 
>  #include <sbi/riscv_asm.h>
>  #include <sbi/riscv_encoding.h>
> +#include <sbi/riscv_elf.h>
>  #include <sbi/sbi_platform.h>
>  #include <sbi/sbi_scratch.h>
>  #include <sbi/sbi_trap.h>
> @@ -67,6 +68,58 @@ _try_lottery:
>  	lla	t1, _start
>  	REG_S	t1, 0(t0)
> 
> +#ifdef FW_PIC
> +	/* relocate the global table content */
> +	lla	t0, _link_start
> +	REG_L	t0, 0(t0)
> +	/* t1 shall has the address of _start */
> +	sub	t2, t1, t0
> +	lla	t3, _runtime_offset
> +	REG_S	t2, (t3)
> +	lla	t0, __rel_dyn_start
> +	lla	t1, __rel_dyn_end
> +	beq	t0, t1, _relocate_done
> +	j	5f
> +2:
> +	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
> +	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
> +	bne	t5, t3, 3f
> +	REG_L	t3, -(REGBYTES*3)(t0)
> +	REG_L	t5, -(REGBYTES)(t0)	/* t5 <-- addend */
> +	add	t5, t5, t2
> +	add	t3, t3, t2
> +	REG_S	t5, 0(t3)		/* store runtime address to the GOT
> entry */
> +	j	5f
> +
> +3:
> +	lla	t4, __dyn_sym_start
> +
> +4:
> +	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
> +	srli	t6, t5, SYM_INDEX	/* t6 <--- sym table index */
> +	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
> +	li	t3, RELOC_TYPE
> +	bne	t5, t3, 5f
> +
> +	/* address R_RISCV_64 or R_RISCV_32 cases*/
> +	REG_L	t3, -(REGBYTES*3)(t0)
> +	li	t5, SYM_SIZE
> +	mul	t6, t6, t5
> +	add	s5, t4, t6
> +	REG_L	t6, -(REGBYTES)(t0)	/* t0 <-- addend */
> +	REG_L	t5, REGBYTES(s5)
> +	add	t5, t5, t6
> +	add	t5, t5, t2		/* t5 <-- location to fix up in RAM */
> +	add	t3, t3, t2		/* t3 <-- location to fix up in RAM */
> +	REG_S	t5, 0(t3)		/* store runtime address to the
> variable */
> +
> +5:
> +	addi	t0, t0, (REGBYTES*3)
> +	ble	t0, t1, 2b
> +	j	_relocate_done
> +_wait_relocate_copy_done:
> +	j	_wait_for_boot_hart
> +#else
>  	/* Relocate if load address != link address */
>  _relocate:
>  	lla	t0, _link_start
> @@ -137,6 +190,7 @@ _wait_relocate_copy_done:
>  	nop
>  	bgt     t4, t5, 1b
>  	jr	t3
> +#endif
>  _relocate_done:
> 
>  	/*
> @@ -144,12 +198,14 @@ _relocate_done:
>  	 * Use _boot_status copy relative to the load address
>  	 */
>  	lla	t0, _boot_status
> +#ifndef FW_PIC
>  	lla	t1, _link_start
>  	REG_L	t1, 0(t1)
>  	lla	t2, _load_start
>  	REG_L	t2, 0(t2)
>  	sub	t0, t0, t1
>  	add	t0, t0, t2
> +#endif
>  	li	t1, BOOT_STATUS_RELOCATE_DONE
>  	REG_S	t1, 0(t0)
>  	fence	rw, rw
> @@ -446,6 +502,10 @@ _skip_trap_exit_rv32_hyp:
>  	j	_start_hang
> 
>  	.align 3
> +#ifdef FW_PIC
> +_runtime_offset:
> +	RISCV_PTR	0
> +#endif
>  _relocate_lottery:
>  	RISCV_PTR	0
>  _boot_status:
> @@ -453,7 +513,7 @@ _boot_status:
>  _load_start:
>  	RISCV_PTR	_fw_start
>  _link_start:
> -	RISCV_PTR	_fw_start
> +	RISCV_PTR	FW_TEXT_START
>  _link_end:
>  	RISCV_PTR	_fw_reloc_end
> 
> diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS index
> 0ac75f2..0d222da 100644
> --- a/firmware/fw_base.ldS
> +++ b/firmware/fw_base.ldS
> @@ -61,6 +61,19 @@
>  		PROVIDE(_data_end = .);
>  	}
> 
> +	.dynsym : {
> +		PROVIDE(__dyn_sym_start = .);
> +		*(.dynsym)
> +		PROVIDE(__dyn_sym_end = .);
> +	}
> +
> +	.rela.dyn : {
> +		PROVIDE(__rel_dyn_start = .);
> +		*(.rela*)
> +		. = ALIGN(8);
> +		PROVIDE(__rel_dyn_end = .);
> +	}
> +
>  	. = ALIGN(0x1000); /* Ensure next section is page aligned */
> 
>  	.bss :
> diff --git a/firmware/objects.mk b/firmware/objects.mk index
> b2ace75..c1f632e 100644
> --- a/firmware/objects.mk
> +++ b/firmware/objects.mk
> @@ -13,6 +13,13 @@ firmware-cflags-y +=
>  firmware-asflags-y +=
>  firmware-ldflags-y +=
> 
> +ifeq ($(FW_PIC),y)
> +firmware-genflags-y +=	-DFW_PIC
> +firmware-asflags-y  +=	-fpic
> +firmware-cflags-y   +=	-fPIE -pie
> +firmware-ldflags-y  +=  -Wl,--no-dynamic-linker endif
> +
>  ifdef FW_TEXT_START
>  firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)  endif diff --
> git a/include/sbi/riscv_elf.h b/include/sbi/riscv_elf.h new file mode 100644
> index 0000000..5d6180a
> --- /dev/null
> +++ b/include/sbi/riscv_elf.h
> @@ -0,0 +1,14 @@
> +#ifndef SBI_RISCV_ELF_H__
> +#define SBI_RISCV_ELF_H__
> +
> +#include <sbi/riscv_asm.h>
> +
> +#define R_RISCV_32		1
> +#define R_RISCV_64		2
> +#define R_RISCV_RELATIVE	3
> +
> +#define RELOC_TYPE		__REG_SEL(R_RISCV_64, R_RISCV_32)
> +#define SYM_INDEX		__REG_SEL(0x20,	0x8)
> +#define SYM_SIZE		__REG_SEL(0x18,0x10)
> +
> +#endif
> --
> 2.7.4
> 
> 
> --
> opensbi mailing list
> opensbi@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
Anup Patel March 19, 2021, 9:41 a.m. UTC | #2
> -----Original Message-----
> From: Anup Patel
> Sent: 17 March 2021 17:17
> To: Vincent Chen <vincent.chen@sifive.com>; opensbi@lists.infradead.org
> Subject: RE: [PATCH v3 2/2] firmware: Support position independent
> execution
> 
> 
> 
> > -----Original Message-----
> > From: opensbi <opensbi-bounces@lists.infradead.org> On Behalf Of
> > Vincent Chen
> > Sent: 17 March 2021 06:47
> > To: opensbi@lists.infradead.org
> > Cc: Vincent Chen <vincent.chen@sifive.com>
> > Subject: [PATCH v3 2/2] firmware: Support position independent
> > execution
> >
> > Enable OpenSBI to support position independent execution. Because the
> > position independent code will cause an additional GOT reference when
> > accessing the global variables, it will reduce performance a bit.
> > Therefore, the position independent execution is disabled by default.
> > Users can through specifying "FW_PIC=y" on the make command to enable
> this feature.
> >
> > In theory, after enabling position-independent execution, the OpenSBI
> > can run at arbitrary address with appropriate alignment. Therefore,
> > the original relocation mechanism will be skipped. In other words,
> > OpenSBI will directly run at the load address without any code movement.
> >
> > Signed-off-by: Vincent Chen <vincent.chen@sifive.com>
> 
> Looks good to me.
> 
> Reviewed-by: Anup Patel <anup.patel@wdc.com>
> 

Applied this patch to the riscv/opensbi repo

Thanks,
Anup

> 
> > ---
> >  Makefile                |  2 +-
> >  firmware/fw_base.S      | 62
> > ++++++++++++++++++++++++++++++++++++++++++++++++-
> >  firmware/fw_base.ldS    | 13 +++++++++++
> >  firmware/objects.mk     |  7 ++++++
> >  include/sbi/riscv_elf.h | 14 +++++++++++
> >  5 files changed, 96 insertions(+), 2 deletions(-)  create mode 100644
> > include/sbi/riscv_elf.h
> >
> > diff --git a/Makefile b/Makefile
> > index d6f097d..038cc99 100644
> > --- a/Makefile
> > +++ b/Makefile
> > @@ -210,8 +210,8 @@ CFLAGS		+=	-
> > mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
> >  CFLAGS		+=	-
> > mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
> >  CFLAGS		+=	$(GENFLAGS)
> >  CFLAGS		+=	$(platform-cflags-y)
> > -CFLAGS		+=	$(firmware-cflags-y)
> >  CFLAGS		+=	-fno-pie -no-pie
> > +CFLAGS		+=	$(firmware-cflags-y)
> >
> >  CPPFLAGS	+=	$(GENFLAGS)
> >  CPPFLAGS	+=	$(platform-cppflags-y)
> > diff --git a/firmware/fw_base.S b/firmware/fw_base.S index
> > 6cc5f88..2ce3851 100644
> > --- a/firmware/fw_base.S
> > +++ b/firmware/fw_base.S
> > @@ -9,6 +9,7 @@
> >
> >  #include <sbi/riscv_asm.h>
> >  #include <sbi/riscv_encoding.h>
> > +#include <sbi/riscv_elf.h>
> >  #include <sbi/sbi_platform.h>
> >  #include <sbi/sbi_scratch.h>
> >  #include <sbi/sbi_trap.h>
> > @@ -67,6 +68,58 @@ _try_lottery:
> >  	lla	t1, _start
> >  	REG_S	t1, 0(t0)
> >
> > +#ifdef FW_PIC
> > +	/* relocate the global table content */
> > +	lla	t0, _link_start
> > +	REG_L	t0, 0(t0)
> > +	/* t1 shall has the address of _start */
> > +	sub	t2, t1, t0
> > +	lla	t3, _runtime_offset
> > +	REG_S	t2, (t3)
> > +	lla	t0, __rel_dyn_start
> > +	lla	t1, __rel_dyn_end
> > +	beq	t0, t1, _relocate_done
> > +	j	5f
> > +2:
> > +	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
> > +	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
> > +	bne	t5, t3, 3f
> > +	REG_L	t3, -(REGBYTES*3)(t0)
> > +	REG_L	t5, -(REGBYTES)(t0)	/* t5 <-- addend */
> > +	add	t5, t5, t2
> > +	add	t3, t3, t2
> > +	REG_S	t5, 0(t3)		/* store runtime address to the GOT
> > entry */
> > +	j	5f
> > +
> > +3:
> > +	lla	t4, __dyn_sym_start
> > +
> > +4:
> > +	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
> > +	srli	t6, t5, SYM_INDEX	/* t6 <--- sym table index */
> > +	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
> > +	li	t3, RELOC_TYPE
> > +	bne	t5, t3, 5f
> > +
> > +	/* address R_RISCV_64 or R_RISCV_32 cases*/
> > +	REG_L	t3, -(REGBYTES*3)(t0)
> > +	li	t5, SYM_SIZE
> > +	mul	t6, t6, t5
> > +	add	s5, t4, t6
> > +	REG_L	t6, -(REGBYTES)(t0)	/* t0 <-- addend */
> > +	REG_L	t5, REGBYTES(s5)
> > +	add	t5, t5, t6
> > +	add	t5, t5, t2		/* t5 <-- location to fix up in RAM */
> > +	add	t3, t3, t2		/* t3 <-- location to fix up in RAM */
> > +	REG_S	t5, 0(t3)		/* store runtime address to the
> > variable */
> > +
> > +5:
> > +	addi	t0, t0, (REGBYTES*3)
> > +	ble	t0, t1, 2b
> > +	j	_relocate_done
> > +_wait_relocate_copy_done:
> > +	j	_wait_for_boot_hart
> > +#else
> >  	/* Relocate if load address != link address */
> >  _relocate:
> >  	lla	t0, _link_start
> > @@ -137,6 +190,7 @@ _wait_relocate_copy_done:
> >  	nop
> >  	bgt     t4, t5, 1b
> >  	jr	t3
> > +#endif
> >  _relocate_done:
> >
> >  	/*
> > @@ -144,12 +198,14 @@ _relocate_done:
> >  	 * Use _boot_status copy relative to the load address
> >  	 */
> >  	lla	t0, _boot_status
> > +#ifndef FW_PIC
> >  	lla	t1, _link_start
> >  	REG_L	t1, 0(t1)
> >  	lla	t2, _load_start
> >  	REG_L	t2, 0(t2)
> >  	sub	t0, t0, t1
> >  	add	t0, t0, t2
> > +#endif
> >  	li	t1, BOOT_STATUS_RELOCATE_DONE
> >  	REG_S	t1, 0(t0)
> >  	fence	rw, rw
> > @@ -446,6 +502,10 @@ _skip_trap_exit_rv32_hyp:
> >  	j	_start_hang
> >
> >  	.align 3
> > +#ifdef FW_PIC
> > +_runtime_offset:
> > +	RISCV_PTR	0
> > +#endif
> >  _relocate_lottery:
> >  	RISCV_PTR	0
> >  _boot_status:
> > @@ -453,7 +513,7 @@ _boot_status:
> >  _load_start:
> >  	RISCV_PTR	_fw_start
> >  _link_start:
> > -	RISCV_PTR	_fw_start
> > +	RISCV_PTR	FW_TEXT_START
> >  _link_end:
> >  	RISCV_PTR	_fw_reloc_end
> >
> > diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS index
> > 0ac75f2..0d222da 100644
> > --- a/firmware/fw_base.ldS
> > +++ b/firmware/fw_base.ldS
> > @@ -61,6 +61,19 @@
> >  		PROVIDE(_data_end = .);
> >  	}
> >
> > +	.dynsym : {
> > +		PROVIDE(__dyn_sym_start = .);
> > +		*(.dynsym)
> > +		PROVIDE(__dyn_sym_end = .);
> > +	}
> > +
> > +	.rela.dyn : {
> > +		PROVIDE(__rel_dyn_start = .);
> > +		*(.rela*)
> > +		. = ALIGN(8);
> > +		PROVIDE(__rel_dyn_end = .);
> > +	}
> > +
> >  	. = ALIGN(0x1000); /* Ensure next section is page aligned */
> >
> >  	.bss :
> > diff --git a/firmware/objects.mk b/firmware/objects.mk index
> > b2ace75..c1f632e 100644
> > --- a/firmware/objects.mk
> > +++ b/firmware/objects.mk
> > @@ -13,6 +13,13 @@ firmware-cflags-y +=  firmware-asflags-y +=
> > firmware-ldflags-y +=
> >
> > +ifeq ($(FW_PIC),y)
> > +firmware-genflags-y +=	-DFW_PIC
> > +firmware-asflags-y  +=	-fpic
> > +firmware-cflags-y   +=	-fPIE -pie
> > +firmware-ldflags-y  +=  -Wl,--no-dynamic-linker endif
> > +
> >  ifdef FW_TEXT_START
> >  firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)  endif diff
> > -- git a/include/sbi/riscv_elf.h b/include/sbi/riscv_elf.h new file
> > mode 100644 index 0000000..5d6180a
> > --- /dev/null
> > +++ b/include/sbi/riscv_elf.h
> > @@ -0,0 +1,14 @@
> > +#ifndef SBI_RISCV_ELF_H__
> > +#define SBI_RISCV_ELF_H__
> > +
> > +#include <sbi/riscv_asm.h>
> > +
> > +#define R_RISCV_32		1
> > +#define R_RISCV_64		2
> > +#define R_RISCV_RELATIVE	3
> > +
> > +#define RELOC_TYPE		__REG_SEL(R_RISCV_64,
> R_RISCV_32)
> > +#define SYM_INDEX		__REG_SEL(0x20,	0x8)
> > +#define SYM_SIZE		__REG_SEL(0x18,0x10)
> > +
> > +#endif
> > --
> > 2.7.4
> >
> >
> > --
> > opensbi mailing list
> > opensbi@lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/opensbi
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index d6f097d..038cc99 100644
--- a/Makefile
+++ b/Makefile
@@ -210,8 +210,8 @@  CFLAGS		+=	-mabi=$(PLATFORM_RISCV_ABI) -march=$(PLATFORM_RISCV_ISA)
 CFLAGS		+=	-mcmodel=$(PLATFORM_RISCV_CODE_MODEL)
 CFLAGS		+=	$(GENFLAGS)
 CFLAGS		+=	$(platform-cflags-y)
-CFLAGS		+=	$(firmware-cflags-y)
 CFLAGS		+=	-fno-pie -no-pie
+CFLAGS		+=	$(firmware-cflags-y)
 
 CPPFLAGS	+=	$(GENFLAGS)
 CPPFLAGS	+=	$(platform-cppflags-y)
diff --git a/firmware/fw_base.S b/firmware/fw_base.S
index 6cc5f88..2ce3851 100644
--- a/firmware/fw_base.S
+++ b/firmware/fw_base.S
@@ -9,6 +9,7 @@ 
 
 #include <sbi/riscv_asm.h>
 #include <sbi/riscv_encoding.h>
+#include <sbi/riscv_elf.h>
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_scratch.h>
 #include <sbi/sbi_trap.h>
@@ -67,6 +68,58 @@  _try_lottery:
 	lla	t1, _start
 	REG_S	t1, 0(t0)
 
+#ifdef FW_PIC
+	/* relocate the global table content */
+	lla	t0, _link_start
+	REG_L	t0, 0(t0)
+	/* t1 shall has the address of _start */
+	sub	t2, t1, t0
+	lla	t3, _runtime_offset
+	REG_S	t2, (t3)
+	lla	t0, __rel_dyn_start
+	lla	t1, __rel_dyn_end
+	beq	t0, t1, _relocate_done
+	j	5f
+2:
+	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
+	li	t3, R_RISCV_RELATIVE	/* reloc type R_RISCV_RELATIVE */
+	bne	t5, t3, 3f
+	REG_L	t3, -(REGBYTES*3)(t0)
+	REG_L	t5, -(REGBYTES)(t0)	/* t5 <-- addend */
+	add	t5, t5, t2
+	add	t3, t3, t2
+	REG_S	t5, 0(t3)		/* store runtime address to the GOT entry */
+	j	5f
+
+3:
+	lla	t4, __dyn_sym_start
+
+4:
+	REG_L	t5, -(REGBYTES*2)(t0)	/* t5 <-- relocation info:type */
+	srli	t6, t5, SYM_INDEX	/* t6 <--- sym table index */
+	andi	t5, t5, 0xFF		/* t5 <--- relocation type */
+	li	t3, RELOC_TYPE
+	bne	t5, t3, 5f
+
+	/* address R_RISCV_64 or R_RISCV_32 cases*/
+	REG_L	t3, -(REGBYTES*3)(t0)
+	li	t5, SYM_SIZE
+	mul	t6, t6, t5
+	add	s5, t4, t6
+	REG_L	t6, -(REGBYTES)(t0)	/* t0 <-- addend */
+	REG_L	t5, REGBYTES(s5)
+	add	t5, t5, t6
+	add	t5, t5, t2		/* t5 <-- location to fix up in RAM */
+	add	t3, t3, t2		/* t3 <-- location to fix up in RAM */
+	REG_S	t5, 0(t3)		/* store runtime address to the variable */
+
+5:
+	addi	t0, t0, (REGBYTES*3)
+	ble	t0, t1, 2b
+	j	_relocate_done
+_wait_relocate_copy_done:
+	j	_wait_for_boot_hart
+#else
 	/* Relocate if load address != link address */
 _relocate:
 	lla	t0, _link_start
@@ -137,6 +190,7 @@  _wait_relocate_copy_done:
 	nop
 	bgt     t4, t5, 1b
 	jr	t3
+#endif
 _relocate_done:
 
 	/*
@@ -144,12 +198,14 @@  _relocate_done:
 	 * Use _boot_status copy relative to the load address
 	 */
 	lla	t0, _boot_status
+#ifndef FW_PIC
 	lla	t1, _link_start
 	REG_L	t1, 0(t1)
 	lla	t2, _load_start
 	REG_L	t2, 0(t2)
 	sub	t0, t0, t1
 	add	t0, t0, t2
+#endif
 	li	t1, BOOT_STATUS_RELOCATE_DONE
 	REG_S	t1, 0(t0)
 	fence	rw, rw
@@ -446,6 +502,10 @@  _skip_trap_exit_rv32_hyp:
 	j	_start_hang
 
 	.align 3
+#ifdef FW_PIC
+_runtime_offset:
+	RISCV_PTR	0
+#endif
 _relocate_lottery:
 	RISCV_PTR	0
 _boot_status:
@@ -453,7 +513,7 @@  _boot_status:
 _load_start:
 	RISCV_PTR	_fw_start
 _link_start:
-	RISCV_PTR	_fw_start
+	RISCV_PTR	FW_TEXT_START
 _link_end:
 	RISCV_PTR	_fw_reloc_end
 
diff --git a/firmware/fw_base.ldS b/firmware/fw_base.ldS
index 0ac75f2..0d222da 100644
--- a/firmware/fw_base.ldS
+++ b/firmware/fw_base.ldS
@@ -61,6 +61,19 @@ 
 		PROVIDE(_data_end = .);
 	}
 
+	.dynsym : {
+		PROVIDE(__dyn_sym_start = .);
+		*(.dynsym)
+		PROVIDE(__dyn_sym_end = .);
+	}
+
+	.rela.dyn : {
+		PROVIDE(__rel_dyn_start = .);
+		*(.rela*)
+		. = ALIGN(8);
+		PROVIDE(__rel_dyn_end = .);
+	}
+
 	. = ALIGN(0x1000); /* Ensure next section is page aligned */
 
 	.bss :
diff --git a/firmware/objects.mk b/firmware/objects.mk
index b2ace75..c1f632e 100644
--- a/firmware/objects.mk
+++ b/firmware/objects.mk
@@ -13,6 +13,13 @@  firmware-cflags-y +=
 firmware-asflags-y +=
 firmware-ldflags-y +=
 
+ifeq ($(FW_PIC),y)
+firmware-genflags-y +=	-DFW_PIC
+firmware-asflags-y  +=	-fpic
+firmware-cflags-y   +=	-fPIE -pie
+firmware-ldflags-y  +=  -Wl,--no-dynamic-linker
+endif
+
 ifdef FW_TEXT_START
 firmware-genflags-y += -DFW_TEXT_START=$(FW_TEXT_START)
 endif
diff --git a/include/sbi/riscv_elf.h b/include/sbi/riscv_elf.h
new file mode 100644
index 0000000..5d6180a
--- /dev/null
+++ b/include/sbi/riscv_elf.h
@@ -0,0 +1,14 @@ 
+#ifndef SBI_RISCV_ELF_H__
+#define SBI_RISCV_ELF_H__
+
+#include <sbi/riscv_asm.h>
+
+#define R_RISCV_32		1
+#define R_RISCV_64		2
+#define R_RISCV_RELATIVE	3
+
+#define RELOC_TYPE		__REG_SEL(R_RISCV_64, R_RISCV_32)
+#define SYM_INDEX		__REG_SEL(0x20,	0x8)
+#define SYM_SIZE		__REG_SEL(0x18,0x10)
+
+#endif