在将C代码编译为裸机(Rasberry pi)时,我做错了什么?

时间:2017-05-22 22:28:29

标签: c assembly raspberry-pi

我花了好几天时间试图解决这个问题,而我却无法做到。我有一些C代码。我已经为这个C程序制作了汇编代码,将汇编粘贴到别人的项目(只包含一个汇编文件)并汇总了。在这些情况下,事情有效。但是如果我尝试直接从C编译来生成二进制文件,它就不起作用了。即使其他一切都应该是相同的。这是我的C代码:

 #include <stdint.h>

#define REGISTERS_BASE 0x3F000000
#define MAIL_BASE 0xB880  // Base address for the mailbox registers
// This bit is set in the status register if there is no space to write into the mailbox
#define MAIL_FULL 0x80000000
// This bit is set in the status register if there is nothing to read from the mailbox
#define MAIL_EMPTY 0x40000000

struct Message
{
  uint32_t messageSize;
  uint32_t requestCode;
  uint32_t tagID;
  uint32_t bufferSize;
  uint32_t requestSize;
  uint32_t pinNum;
  uint32_t on_off_switch;
  uint32_t end;
};

struct Message m =
{
  .messageSize = sizeof(struct Message),
  .requestCode =0,
  .tagID = 0x00038041,
  .bufferSize = 8,
  .requestSize =0,
  .pinNum = 130,
  .on_off_switch = 1,
  .end = 0,
};

/** Main function - we'll never return from here */
int _start(void)
{
  uint32_t mailbox = MAIL_BASE + REGISTERS_BASE + 0x18;
  volatile uint32_t status;

  do
  {
    status = *(volatile uint32_t *)(mailbox);
  }
  while((status & 0x80000000));

  *(volatile uint32_t *)(MAIL_BASE + REGISTERS_BASE + 0x20) = ((uint32_t)(&m) & 0xfffffff0) | (uint32_t)(8);

  while(1);
}

这是我从成功方法复制的链接器文件:

/*
 * Very simple linker script, combing the text and data sections
 * and putting them starting at address 0x800.
 */
SECTIONS {
  /* Put the code at 0x80000, leaving room for ARM and
   * the stack. It also conforms to the standard expecations.
   */
  .init 0x8000 : {
    *(.init)
  }

  .text : {
    *(.text)
  }

  /* Put the data after the code */
  .data : {
    *(.data)
  }
}

这就是我编译和链接所有内容的方式:

arm-none-eabi-gcc -O0 -march=armv8-a PiTest.c -nostartfiles -o kernel.o
arm-none-eabi-ld kernel.o -o kernel.elf -T kernel.ld
arm-none-eabi-objcopy kernel.elf -O binary kernel.img

我的目标架构是armv8,因为它是pi模型3使用的。 我不知道生成的程序集是如何工作的,但C代码不直接。请帮助我处于疯狂的边缘。

编辑:预期的行为是让pi的灯亮起。它与我描述的第一种方法有关。使用第二种方法,灯仍然熄灭。

EDIT4:对文件进行了一些更改,删除了之前使用过时信息进行修改以减少帖子大小

  kernel.elf:     file format elf32-littlearm


Disassembly of section .init:

00008000 <_start>:
    8000:   e3a0dd7d    mov sp, #8000   ; 0x1f40
    8004:   eaffffff    b   8008 <kernel_main>

Disassembly of section .text:

00008008 <kernel_main>:
    8008:   e52db004    push    {fp}        ; (str fp, [sp, #-4]!)
    800c:   e28db000    add fp, sp, #0
    8010:   e24dd00c    sub sp, sp, #12
    8014:   e30b3898    movw    r3, #47256  ; 0xb898
    8018:   e3433f00    movt    r3, #16128  ; 0x3f00
    801c:   e50b3008    str r3, [fp, #-8]
    8020:   e51b3008    ldr r3, [fp, #-8]
    8024:   e5933000    ldr r3, [r3]
    8028:   e50b300c    str r3, [fp, #-12]
    802c:   e51b300c    ldr r3, [fp, #-12]
    8030:   e3530000    cmp r3, #0
    8034:   bafffff9    blt 8020 <kernel_main+0x18>
    8038:   e30b38a0    movw    r3, #47264  ; 0xb8a0
    803c:   e3433f00    movt    r3, #16128  ; 0x3f00
    8040:   e3082050    movw    r2, #32848  ; 0x8050
    8044:   e3402001    movt    r2, #1
    8048:   e3c2200f    bic r2, r2, #15
    804c:   e3822008    orr r2, r2, #8
    8050:   e5832000    str r2, [r3]
    8054:   eafffffe    b   8054 <kernel_main+0x4c>

Disassembly of section .data:

00008058 <__data_start>:
    8058:   00000020    andeq   r0, r0, r0, lsr #32
    805c:   00000000    andeq   r0, r0, r0
    8060:   00038041    andeq   r8, r3, r1, asr #32
    8064:   00000008    andeq   r0, r0, r8
    8068:   00000000    andeq   r0, r0, r0
    806c:   00000082    andeq   r0, r0, r2, lsl #1
    8070:   00000001    andeq   r0, r0, r1
    8074:   00000000    andeq   r0, r0, r0

Disassembly of section .ARM.attributes:

00000000 <_stack-0x80021>:
   0:   00002e41    andeq   r2, r0, r1, asr #28
   4:   61656100    cmnvs   r5, r0, lsl #2
   8:   01006962    tsteq   r0, r2, ror #18
   c:   00000024    andeq   r0, r0, r4, lsr #32
  10:   412d3805            ; <UNDEFINED> instruction: 0x412d3805
  14:   070e0600    streq   r0, [lr, -r0, lsl #12]
  18:   09010841    stmdbeq r1, {r0, r6, fp}
  1c:   14041202    strne   r1, [r4], #-514 ; 0xfffffdfe
  20:   17011501    strne   r1, [r1, -r1, lsl #10]
  24:   1a011803    bne 46038 <__bss_end__+0x3dfc0>
  28:   2a012201    bcs 48834 <__bss_end__+0x407bc>
  2c:   Address 0x000000000000002c is out of bounds.


Disassembly of section .comment:

00000000 <.comment>:
   0:   3a434347    bcc 10d0d24 <_stack+0x1050d03>
   4:   35312820    ldrcc   r2, [r1, #-2080]!   ; 0xfffff7e0
   8:   392e343a    stmdbcc lr!, {r1, r3, r4, r5, sl, ip, sp}
   c:   732b332e            ; <UNDEFINED> instruction: 0x732b332e
  10:   33326e76    teqcc   r2, #1888   ; 0x760
  14:   37373131            ; <UNDEFINED> instruction: 0x37373131
  18:   2029312d    eorcs   r3, r9, sp, lsr #2
  1c:   2e392e34    mrccs   14, 1, r2, cr9, cr4, {1}
  20:   30322033    eorscc  r2, r2, r3, lsr r0
  24:   35303531    ldrcc   r3, [r0, #-1329]!   ; 0xfffffacf
  28:   28203932    stmdacs r0!, {r1, r4, r5, r8, fp, ip, sp}
  2c:   72657270    rsbvc   r7, r5, #112, 4
  30:   61656c65    cmnvs   r5, r5, ror #24
  34:   00296573    eoreq   r6, r9, r3, ror r5

3 个答案:

答案 0 :(得分:1)

kernel8.img

12345678
00000800
00080264
00000000
12345678

kernel8-32.img

12345678
00008320
00008224
200001DA
12345678

kernel7.img

12345678
00000700
00008224
200001DA
12345678

kernel.img

12345678
00000000
00008224
200001DA
12345678

当我编写并发布此代码时,这就是我所得到的,如果您将文件命名为kernel.img,那么0x8000就是您的切入点我在您的其他SO问题中给出的答案是一个完整的覆盆子pi起点。您可以简单地添加您的邮箱内容,但如果您正在努力解决这个问题,那么邮箱和视频就不应该启动IMO。

如果您将文件命名为kernel8.img,则输入点为0x80000,请更改链接描述文件以匹配。

我有一个基于串口的引导加载程序,你可以用来保存sd卡舞,可以用很长的路,然后只需使用你正在创建的二进制版本,一旦你的应用程序工作就写入闪存。

修改

好吧这真是令人难以置信的恶心,通过在这里张贴它可能意味着你不能在你的课堂作业中使用它...你应该真正做到这一点而不是为你的引导程序使用内联汇编......

so.c

asm(
".globl _start\n"
"_start:\n"
"mov sp,#0x8000\n"
"bl centry\n"
"b .\n"
);


unsigned int centry ( void )
{
    return(5);
}

构建

arm-none-eabi-gcc -O2 -c so.c -o so.o
arm-none-eabi-ld -Ttext=0x8000 so.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy so.elf -O binary kernel.img

检查

Disassembly of section .text:

00008000 <_start>:
    8000:   e3a0d902    mov sp, #32768  ; 0x8000
    8004:   eb000000    bl  800c <centry>
    8008:   eafffffe    b   8008 <_start+0x8>

0000800c <centry>:
    800c:   e3a00005    mov r0, #5
    8010:   e12fff1e    bx  lr

一个完整的raspberry pi C,带有bootstrap示例,适用于pi的任何风格(据我所知,他们可能在过去几个月内更改了GPU引导加载程序,但假设没有)。

答案 1 :(得分:0)

我在这里看到了一些错误。最明显的是:

  • 您不会在地址0处留下任何内容,因此CPU在启动时会执行空白内存。你需要在0x0

  • 放置一些东西(比如分支指令!)
  • 在ARM Cortex-A上,堆栈指针在启动时未初始化。你必须在_start中自己初始化它 - 这意味着你需要在汇编中编写该函数。

答案 2 :(得分:0)

首先,为了耐心帮助我,给老朋友抱怨。 错误是:

程序的错误入口点,通过创建带有标签_start的汇编文件来设置堆栈指针并使用链接器将init部分放在地址0x8000

来修复

编译行本身也错了,它缺少一个-c参数