Home > Mobile >  assembly weak symbol not working as (I) expected
assembly weak symbol not working as (I) expected

Time:08-30

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

CodePudding user response:

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
  • Related