7

I need to call a function at address 0xDD2:

// foo.h
void foo(void) __at(0xDD2);

// foo.c
#include "foo.h"
void foo(void)
{
    // some code
}

This code works:

#include "foo.h"
void main(void)
{
    void (*a)(void) = &foo;
    a();
}

However, this one doesn't:

#include "foo.h"
void main(void)
{
    void (*a)(void) = (void (*)(void))(0x0DD2);
    a();
}

The compiler (XC8) says: main.c:5:: warning: (759) expression generates no code and debugger passes these lines while debugging.

I need second one (call function just by its address). Why compiler optimizes it out? Is there any mistake in pointer assignment? Changing optimization level of compiler didn't help.

25
  • 2
    If the function is never called, you probably have to force it to get linked with some trick in the linker script. Why should the function never get called though, is it a bootloader or something?
    – Lundin
    Commented Jun 9, 2020 at 11:59
  • 3
    Can you provide a minimal context where it can be reproduced? Where exactly these lines are placed?
    – Alex Lop.
    Commented Jun 9, 2020 at 11:59
  • 1
    @underscore_d: This particular compiler uses a (non-standard) dialect of C in which main is supposed to return void. This is documented at D.3.1 in the manual. So that's not the issue here. Commented Jun 9, 2020 at 12:43
  • 1
    Section 5.4.5.4 of the compiler manual, page 161, seems to be saying that such casts are simply not allowed. It may be that the __at construct is the only way to call an absolute address. Can you explain, perhaps with an example, why this won't work in the application you have in mind? Maybe there will be a different approach that would work. Commented Jun 9, 2020 at 12:50
  • 1
    Based on what @NateEldredge wrote, you need to reuse the same foo.h and foo.c for both projects. Create a 'shared' directory which will be used by both projects and place those files in it.
    – Alex Lop.
    Commented Jun 9, 2020 at 13:03

3 Answers 3

1

This seems to do what you asked for:

/*
 * File:   main.c
 * Author: dan1138
 * Target: PIC18F47Q10
 * Compiler: XC8 v2.20
 * 
 * See: https://stackoverflow.com/questions/62282036/compiler-optimizes-out-pointer-to-function-when-address-is-assigned-manually/62297967#62297967
 *
 * Created on June 9, 2020, 11:42 PM
 */
#pragma config FEXTOSC = OFF, RSTOSC = HFINTOSC_64MHZ, CLKOUTEN = OFF
#pragma config CSWEN = ON, FCMEN = OFF, MCLRE = EXTMCLR, PWRTE = OFF
#pragma config LPBOREN = OFF, BOREN = SBORDIS, BORV = VBOR_190
#pragma config ZCD = OFF, PPS1WAY = OFF, STVREN = ON, XINST = OFF
#pragma config WDTCPS = WDTCPS_31, WDTE = OFF, WDTCWS = WDTCWS_7, WDTCCS = SC
#pragma config WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF
#pragma config WRT4 = OFF, WRT5 = OFF, WRT6 = OFF, WRT7 = OFF
#pragma config WRTC = OFF, WRTB = OFF, WRTD = OFF
#pragma config SCANE = ON, LVP = OFF, CP = OFF, CPD = OFF
#pragma config EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF
#pragma config EBTR4 = OFF, EBTR5 = OFF, EBTR6 = OFF, EBTR7 = OFF
#pragma config EBTRB = OFF

#include <xc.h>

void main(void)
{
    extern void foo(void) __at(0xDD2);
    void (* volatile a)(void) = foo;

    a();
}    

Disassembly:

!void main(void)
!{
!    extern void foo(void) __at(0xDD2);
!    void (* volatile a)(void) = foo;
0x1FFD4: MOVLW 0xD2
0x1FFD6: MOVWF __pcstackCOMRAM, ACCESS
0x1FFD8: MOVLW 0xD
0x1FFDA: MOVWF 0x2, ACCESS
0x1FFDC: MOVLW 0x0
0x1FFDE: MOVWF 0x3, ACCESS
!    a();
0x1FFE0: RCALL 0xFFE6
0x1FFE2: GOTO 0x1FFFA
0x1FFE4: NOP
0x1FFE6: PUSH
0x1FFE8: MOVWF PCLATH, ACCESS
0x1FFEA: MOVF __pcstackCOMRAM, W, ACCESS
0x1FFEC: MOVWF TOS, ACCESS
0x1FFEE: MOVF 0x2, W, ACCESS
0x1FFF0: MOVWF TOSH, ACCESS
0x1FFF2: MOVF 0x3, W, ACCESS
0x1FFF4: MOVWF TOSU, ACCESS
0x1FFF6: MOVF PCLATH, W, ACCESS
0x1FFF8: RETURN 0
!}
0x1FFFA: BSF _ccovbit2_1, 0, ACCESS
0x1FFFC: GOTO 0x0
0x1FFFE: NOP
0

Should really be a comment, but it contains code and reference from standard.

I have no XC8 compiler at hand so I tried to mimic something with CLang. This compiles with no warning and correctly display In foo:

#include <stdio.h>
#include <stdint.h>

void foo(void) {
    printf("In foo\n");
}

int main() {
    intptr_t f = (intptr_t) &foo;
    printf("%lx\n", f);
    void (*a)(void) = (void (*)(void))f;
    (*a)();        // Same behaviour with a();
    return 0;
}

I controlled in C11 reference manual (draft n1570) at 6.3.2.3 Language/Conversions/Other operands/Pointers §5-6:

5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined...

6 Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined....

My understanding is that converting from a plain integer to a function pointer is legal but implementation defined. What is the compatibility level of your compiler, and are there any flags that could control that behaviour?

0

Based on what I read in XC8 manual and some discussions at another forum, it's not a good idea to put objects at a fixed address to use them in another project because of compiled stack and some other reasons.
However, if you just need to prevent compiler from optimizing out pointer to function when address is assigned manually, Use code in this comment or this answer.

Not the answer you're looking for? Browse other questions tagged or ask your own question.