【问题标题】:Writing a C program to call another program without using any built-in libraries编写一个 C 程序来调用另一个程序而不使用任何内置库
【发布时间】:2017-06-07 12:15:04
【问题描述】:

我正在尝试为引导加载程序编写一个简单的“go-command”,它将我带到 RAM 中的特定地址,例如 0x18000000,它应该执行一个闪烁 LED 的程序。我有两个 .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() 函数

【问题讨论】:

  • 如果您使用 C 编程,为什么要添加 C++ 标签?只添加您实际编程的语言的标签。您还可以扩展环境,例如为 PC 平台或嵌入式系统执行此操作。请花一些时间到read about how to ask good questions
  • 对不起!如果您好心,请发布解决方案
  • VTC 过于宽泛:这在很大程度上取决于您的环境。例如,您可以定义自己的入口点,使用链接器脚本将其放在二进制文件的最开始并跳转到那里,使用汇编代码或转换为函数指针的起始地址 - 但没有好的答案是不可能的更多细节。
  • 您在哪类计算机上进行编程?普通的操作系统不会让你这样做。
  • 在裸机嵌入式系统上,这不会有任何问题。您可以设置一个正确格式的函数指针指向一个固定地址,然后调用该函数。这通常是调用作为原始汇编程序提供的引导加载程序等的方式。但在 Linux 等托管系统中,它不会工作,因为进程不允许写入彼此的地址空间。

标签: c embedded bootloader


【解决方案1】:

您省略了很多可能相关的内容,但从表面上看,您只需声明一个函数指针,用绝对地址初始化并通过该指针调用函数。

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • 在链接器脚本中我给出了起始地址 0x18000000
    • 那我该怎么做呢?
    • 如果您确定 0x18000000 是您的例程的 RAM 地址,只需将该地址复制到代码的第一行,代替 0x1234567
    • 这不是解释为这个进程的虚拟内存空间中的地址吗?
    • @kni:操作系统是抽象的。如果你想这样编程,我建议使用裸机。
    【解决方案3】:

    所以我有一个 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>
    

    拆卸间距有点破损,但没关系。对于普通程序,入口点不在 MAIN() 处,在这种情况下它位于开头 0x80001000 而不是 0x8000101A 我故意将其命名为 main 以外的其他名称(对于裸机)...您应该没有理由要在 main 输入,您应该在入口点输入...如果您继续尝试,我会让您失败,否则,您只能靠自己了。

    所以这代表了上面的一个srec。

    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 中该主题的其他变体,但似乎已经可以使用。

    【讨论】:

    • 所以如果这是您的问题,请支持/接受 Simone 的回答
    • 请注意,如果您构建了二进制权限 S705800010006A,它们会为您提供入口点
    • 这很简单,如果您之前的程序启用了外围设备的中断或启用了缓存等。那么您需要在启动下一个程序之前清理所有这些东西。 ..
    • 是的。我正在解析然后将程序写入 RAM。
    猜你喜欢
    • 2011-07-24
    • 1970-01-01
    • 2015-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-18
    • 2010-10-25
    相关资源
    最近更新 更多