I am cross compiling with riscv-corev32-elf-gcc
.
In a first file 'generic.S' I have the following code:
.section .text.handlers
.weak u_sw_irq_handler
.weak __no_irq_handler
.section .vectors, "ax"
vector_table:
jal x0, u_sw_irq_handler
jal x0, __no_irq_handler
jal x0, __no_irq_handler
...
.section .text
reset_handler:
la t0, vector_table
csrw mtvec, t0
In a second file 'custom.S' I have the following code:
.section .text.handlers
.<x> u_sw_irq_handler
.<x> __no_irq_handler
.section .vectors, "ax"
vector_table:
jal x0, u_sw_irq_handler
jal x0, ISR_1_handler
jal x0, ISR_2_handler
...
where <x>
is either global
or local
when global
, this is the (partial) result of the disassembly:
00001000 <vector_table>:
1000: 7760d06f j e776 <u_sw_irq_handler>
1004: 1880706f j 81cc <ISR_1_handler>
1008: 1e40706f j 822c <ISR_2_handler>
...
1084: 7760d06f j e776 <u_sw_irq_handler>
1088: 7320d06f j e736 <__no_irq_handler>
108c: 72e0d06f j e736 <__no_irq_handler>
...
00001108 <reset_handler>:
1108: 00000297 auipc t0,0x0
110c: f7c28293 addi t0,t0,-264 # 1000 <vector_table>
1110: 30529073 csrw mtvec,t0
when local
, this is the (partial) result of the disassembly:
00001000 <vector_table>:
1000: 7760d06f j e776 <u_sw_irq_handler>
1004: 1880706f j 81cc <ISR_1_handler>
1008: 1e40706f j 822c <ISR_2_handler>
...
00001084 <vector_table>:
1084: 7760d06f j e776 <u_sw_irq_handler>
1088: 7320d06f j e736 <__no_irq_handler>
108c: 72e0d06f j e736 <__no_irq_handler>
...
00001108 <reset_handler>:
1108: 00000297 auipc t0,0x0
110c: f7c28293 addi t0,t0,-132 # 1084 <vector_table>
1110: 30529073 csrw mtvec,t0
But this not what I want:
I want the generic definition to be taken if there is no other definition of vector_table
I want the generic definition to be overwritten by the custom.S definition if it exists, and the reset_handler in the generic.S to load the custom address of the vector_table
using 'global' is the closer of what I want but the vector_table continues the jal x0, ...
after the last vector
using 'local' the vector_table called in the reset_handler will be the generic one and not the custom.
edit: sorry I missed matched the logs for the reset handler disassembly
assembly
weak
symbol not working as I expected
weak
works differently than you think:
weak
makes a symbol global if the symbol does not exist in another object file and it makes a symbol itself (!) disappear if it exists in another object file.
Example (sorry that my examples are x86 because I don't know riscv32):
.weak some_irq_handler
.weak some_other_irq_handler
vector_table:
jmp some_irq_handler
jmp some_other_irq_handler
some_irq_handler:
iret
some_other_irq_handler:
iret
If no other object file contains .global some_irq_handler
nor .global some_other_irq_handler
, the .weak
lines nearly have the same effect as .global
lines.
However, if another object file contains these two symbols, the example above is more or less equal to:
vector_table:
# This symbol is defined in another object file
jmp some_irq_handler
# This symbol is defined in another object file
jmp some_other_irq_handler
# The code of "some_irq_handler" is still
# present; only the label "some_irq_handler:"
# has been removed by the linker!
iret
iret
# -- Another object file --
some_irq_handler:
...
I want the generic definition to be overwritten by the custom.S definition if it exists ...
Case 1: The vector_table
needs not to be located at a certain address in memory:
In this case you can do it the following way:
.weak vector_table
vector_table:
jmp no_interrupt
jmp no_interrupt
...
If another vector table is present in you project, the resulting code (after linking) will look like this:
# -- "weak" object file --
# vector_table: - Label removed by the linker
# but the table itself is still there
jmp no_interrupt
jmp no_interrupt
...
# -- "overwriting" object file --
vector_table:
jmp interrupt1
jmp interrupt2
...
Case 2: The vector_table
needs to be located at a certain address in memory:
In this case, you can do it the following way:
.weak interrupt1
.weak interrupt2
...
vector_table:
jmp interrupt1
jmp interrupt2
...
__no_irq_handler:
interrupt1:
interrupt2:
...
interrupt256:
iret
You will never overwrite the "generic" interrupt vector table by another one but you only overwrite the symbols interrupt<n>
:
.global interrupt2
interrupt2:
mov al, 0x1234
out 0xE4, ax
mov al, 0x20
out 0x20, al
iret
(This will also work with C-written code. Because the C compiler makes functions .global
and not .weak
by default, the C-written function overwrites the .weak
one.)
The resulting code will then look like this:
# -- "weak" object file --
vector_table:
jmp interrupt1
jmp interrupt2
...
__no_irq_handler:
interrupt1:
# interrupt2: - Label removed by the linker
interrupt3:
...
interrupt256:
iret
# -- "overwriting" object file --
interrupt2:
mov al, 0x1234
out 0xE4, ax
mov al, 0x20
out 0x20, al
iret