编写C程序以调用另一个程序而不使用任何内置库

时间:2017-06-07 12:15:05

标签: c embedded bootloader

我正在尝试写一个简单的“命令”'对于引导加载程序,它将我带到RAM中的特定地址,例如0x18000000,它应该执行一个闪烁的程序。我有两个.c文件说led.c和go.c,其中led.c闪烁两个LED。但我想知道并且不知道如何将控制/调用其main()传递给此go.c文件以转到该地址并开始闪烁LED?但它应该在不包含其他头文件,库等的情况下完成。请帮助我!!提前致谢。以下代码适用于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;
    }
}

在我的go.c文件中,我想传递一个控件来调用这个led.c main()func

3 个答案:

答案 0 :(得分:2)

有很多你省略的可能是相关的,但是在面值上,你只需声明一个函数指针,用绝对地址初始化并通过该指针调用函数。

然而,它可能不那么简单,因为被调用的程序将使用调用程序的C运行时环境;任何全局静态对象都不会被初始化 - 您需要调用程序入口点(不是main())来建立程序所期望的运行时环境。在简单的情况下,它可能在某种程度上起作用或似乎起作用。

答案 1 :(得分:1)

GCC有一个允许跳转到任意地址的扩展名,所以如果你知道你的led.c主地址,你可以这样做:

void *func_ptr = (void *)0x1234567;  // address of your led routine
goto *func_ptr;                      

但是,您可能没有led例程的地址,这不是一个非常安全的操作。跳到某个未知地址可能会导致崩溃!!

答案 2 :(得分:1)

所以我有一个sifive riscv板,会比你的有点不同但这里是一个led闪光灯程序(编译版):

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>

拆卸间距有点破,但没关系。入口点IS不是MAIN()用于正常程序,它在这种情况下是开始的0x80001000 NOT 0x8000101A我故意为主要名称之外的东西命名(对于裸机)...应该没有理由你要进入主要区域,你应该进入入口点...如果你继续尝试,我会让你失败,你自己就可以了。

所以这代表了上述的结果。

S00F00006E6F746D61696E2E737265631F
S3158000100037410080EF006001029001A0828023209A
S31580001010B500828003250500828001114AC83729E0
S31580001020011013058900B705680006CE26CA4EC68C
S3158000103022CCF13F1305C900B7056800C93F1305E7
S3158000104009048145B7841E00D937B709680031097C
S3158000105093840448CE854A855D3F014422850504F4
S315800010607537E31D94FE81454A85553701442285AF
S30F800010700504693FE31D94FEF1BFFD
S705800010006A

我/我们假设您实际上并没有将其下载到ram中,它永远不会执行,您的引导程序必须解析该程序然后将程序写入ram,两个不同的东西(程序本身和描述该程序的文件格式)程序)。

假设你到达那一点,你需要做的就是在我的案例中分支到0x80001000或在你的案例中分支到0x18000000。

因此,如果已经提供给您的答案,您可以执行此操作以启动下载的程序

void hop ( void )
{
    void *func_ptr = (void *)0x80001000;
    goto *func_ptr;
}

导致

Disassembly of section .text:

00000000 <hop>:
   0:   800017b7            lui x15,0x80001
   4:   8782                    jr  x15

或者我个人的偏好是:

.globl HOP
HOP:
    jr x11

来自C我会用

打电话
HOP(0x80001000);

这样我可以确保使用我想要的指令。 YMMV。

你走这条路有多远?你是不是最后一步了? Simone提供了一个应该可以正常工作的答案,你可以使用C的那个主题还有其他的变化,但那个似乎已经有用了。