0

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

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Guillaume D
  • 2,202
  • 2
  • 10
  • 37
  • Your title talks about `weak` symbols not working like you expect, but it's not clear to me what you expect `weak` to be doing here. In both cases you're putting the whole `vector_table` in. – Thomas Jager Aug 12 '22 at 15:02
  • In C if I declare a function `foo()` weak in `generic.c` and then declare `foo()` in `custom.c` when calling `foo()` from `generic.c:main()` and linking with `custom.c` I expect `generic.c:main()` to call `custom.c:foo()`. This is what happen. I would like the same in assembly – Guillaume D Aug 12 '22 at 15:07
  • 2
    Declaring symbols as `weak` doesn't make their uses disappear. You vector table still exists in both places, you're not doing anything to make one copy replace the other. It seems like what you want would be to have a single instance of the vector table in `generic.S`, using `ISR_1_handler`, `ISR_2_handler`, etc., and then define those as `weak` in `generic.S`, and being equal to `__no_irq_handler`. Then, you define them as non-weak in other places to override that. – Thomas Jager Aug 12 '22 at 15:27

1 Answers1

3

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
Martin Rosenau
  • 17,897
  • 3
  • 19
  • 38