问题
I am trying to write a simple 'go-command' for boot-loader that takes me to specific address in RAM say 0x18000000 and it should execute a program that blinks led. I have two .c files say led.c and go.c in which led.c blinks two leds. But I am wondering and don't know that how can I pass a control/invoke its main() to this go.c file to go to that address and start blinking leds? But it should be done without including other header files, libraries, etc. Kindly help me!! Thanks in advance. Below code is for led.c
void delay ()
{
volatile int i;
for(i=0;i<1000000;i++)
{}
}
int main(void)
{
*led0=0;
*led1=0;
while(1)
{
*led0=1;
delay();
*led0=0;
*led1=1;
delay();
*led1=0;
}
}
In my go.c file I want to pass a control to invoke this led.c main() func
回答1:
GCC has an extension that allows jumping to an arbitrary address, so if you know the address of your led.c main you could do something like that:
void *func_ptr = (void *)0x1234567; // address of your led routine
goto *func_ptr;
However, you probably don't have the address of the led routine and it is not a very safe operation. Jumping to some unknown address will probably result in a crash!!
回答2:
There is a lot you have omitted that is likely to be relevant, but taken at face value, you simply declare a function pointer, initialised with the absolute address and invoke the function through that pointer.
However it may not be that simple since the called program will use the C run-time environment of the calling program; any global static objects will not be initialised - you need to call the program entry point (which is notmain()
) to establish the run-time environment expected by the program. In simple case it may work or appear to work to some extent.
回答3:
So I have an sifive riscv board, going to be a little different than yours but here is an led blinker program (compiled version):
Disassembly of section .text:
80001000 <_start>:
80001000: 80004137 lui x2,0x80004
80001004: 016000ef jal x1,8000101a <notmain>
80001008: 9002 ebreak
8000100a: a001 j 8000100a <_start+0xa>
8000100c <dummy>:
8000100c: 8082 ret
8000100e <PUT32>:
8000100e: 00b52023 sw x11,0(x10)
80001012: 8082 ret
80001014 <GET32>:
80001014: 00052503 lw x10,0(x10)
80001018: 8082 ret
8000101a <notmain>:
8000101a: 1101 addi x2,x2,-32
8000101c: c84a sw x18,16(x2)
8000101e: 10012937 lui x18,0x10012
80001022: 00890513 addi x10,x18,8 # 10012008 <_start-0x6ffeeff8>
80001026: 006805b7 lui x11,0x680
8000102a: ce06 sw x1,28(x2)
8000102c: ca26 sw x9,20(x2)
8000102e: c64e sw x19,12(x2)
80001030: cc22 sw x8,24(x2)
80001032: 3ff1 jal 8000100e <PUT32>
80001034: 00c90513 addi x10,x18,12
80001038: 006805b7 lui x11,0x680
8000103c: 3fc9 jal 8000100e <PUT32>
8000103e: 04090513 addi x10,x18,64
80001042: 4581 li x11,0
80001044: 001e84b7 lui x9,0x1e8
80001048: 37d9 jal 8000100e <PUT32>
8000104a: 006809b7 lui x19,0x680
8000104e: 0931 addi x18,x18,12
80001050: 48048493 addi x9,x9,1152 # 1e8480 <_start-0x7fe18b80>
80001054: 85ce mv x11,x19
80001056: 854a mv x10,x18
80001058: 3f5d jal 8000100e <PUT32>
8000105a: 4401 li x8,0
8000105c: 8522 mv x10,x8
8000105e: 0405 addi x8,x8,1
80001060: 3775 jal 8000100c <dummy>
80001062: fe941de3 bne x8,x9,8000105c <notmain+0x42>
80001066: 4581 li x11,0
80001068: 854a mv x10,x18
8000106a: 3755 jal 8000100e <PUT32>
8000106c: 4401 li x8,0
8000106e: 8522 mv x10,x8
80001070: 0405 addi x8,x8,1
80001072: 3f69 jal 8000100c <dummy>
80001074: fe941de3 bne x8,x9,8000106e <notmain+0x54>
80001078: bff1 j 80001054 <notmain+0x3a>
the disassembly spacing is a little broken but thats okay. The entry point IS NOT AT MAIN() for a normal program it is at the start in this case 0x80001000 NOT 0x8000101A which I intentionally name something other than main on purpose (for bare metal)...There should be no reason for you to to enter at main you should enter at the entry point...I will let you simply fail if you continue to try otherwise, you are on your own with that.
So this represents an srec of the above.
S00F00006E6F746D61696E2E737265631F
S3158000100037410080EF006001029001A0828023209A
S31580001010B500828003250500828001114AC83729E0
S31580001020011013058900B705680006CE26CA4EC68C
S3158000103022CCF13F1305C900B7056800C93F1305E7
S3158000104009048145B7841E00D937B709680031097C
S3158000105093840448CE854A855D3F014422850504F4
S315800010607537E31D94FE81454A85553701442285AF
S30F800010700504693FE31D94FEF1BFFD
S705800010006A
I/we assume you are not actually downloading that to ram as is, that will never execute, your bootloader has to parse that then write the program to ram, two different things (the program itself and a file format that describes that program).
Assuming you get to that point, all you need to do is branch to 0x80001000 in my case or 0x18000000 in yours.
so taking the answer already provided to you you can do this to launch the downloaded program
void hop ( void )
{
void *func_ptr = (void *)0x80001000;
goto *func_ptr;
}
which results in
Disassembly of section .text:
00000000 <hop>:
0: 800017b7 lui x15,0x80001
4: 8782 jr x15
Or my personal preference would be:
.globl HOP
HOP:
jr x11
which from C I would call with
HOP(0x80001000);
that way I can insure the instruction I wanted is used. YMMV.
How far along this path have you gotten? Are you stuck at the last step? Simone provided an answer that should work just fine, there are other variations on that theme from C that you can use, but that one already appears to work.
来源:https://stackoverflow.com/questions/44412356/writing-a-c-program-to-call-another-program-without-using-any-built-in-libraries