uboot启动后在内存中运行裸机程序hello

简介: 如题,实现过程中发现3额问题,先写下来,待解答: <p>1、uboot启动后再dnw上打印许多信息,我想改变其中的打印信息或加上自己的打印信息以证明程序运行到何处。修改完后重新编译uboot.bin。</p> <p>在DNW下执行dnw 50008000 USB下载uboot.bin到内存50008000处, go 50008000,从内存50008000处运行我刚下载的程序,发现我修
如题,实现过程中发现3额问题,先写下来,待解答:

1、uboot启动后再dnw上打印许多信息,我想改变其中的打印信息或加上自己的打印信息以证明程序运行到何处。修改完后重新编译uboot.bin。

在DNW下执行dnw 50008000 USB下载uboot.bin到内存50008000处, go 50008000,从内存50008000处运行我刚下载的程序,发现我修改的内容并未显示。

重新执行dnw 50008000,nand erase 0 100000,nand write.uboot 50008000 0 100000,后从nand直接启动,发现我修改的内容被打印出来了。

总结:可能的原因:1、程序下载到50008000,但50008000处并非有执行命令。2、确实从50008000处执行了,但uboot.bin里的start.s会调用原来nand里的uboot.bin执行

 

2、uboot里有个examples文件夹里有hello_world应用程序(姑且这么说吧):

我dnw 50008000 hello_world.bin,go 50008000,执行后重启了。

看了makefile里LOAD_ADDR = 0xc100000,dnw c10000 hello_world.bin,go c1008000,执行后停住了

然后又看了半天makefile,太繁琐,无果,没解决掉。

 

3、自己写了个hello.c

dnw 50008000 ,go 50008000,运行ok,打印出hello world.

参考并引用:http://blog.csdn.net/liushaowei2008/article/details/7739046

printf函数是 uboot 实现的,我们只需要调用就行了。当然了,这个首先得到你u boot 的printf函数地址。这需要你自己 编译 uboot,因为每个人
的printf函数地址不一定一样。查看System.map 文件 ,找到printf地址。就行了。
调用时我们可以这样用:
  1. void (*show)(char*,...) = 0xc7e11650;
  2. ........
  3. show("hello world/n");
  4. .......

现在我们来个hello world 的例子:
贴一下代码:

  1. void (*show)(char *,...) = 0xc7e11650;
  2. int main(void)
  3. {
  4.     show("hello world./n");
  5.     return 0;
  6. }

(hello.c)
就这么简单。(一个hello world 能多复杂啊?嘎嘎~)
下面我们来说一下编译和连接:
你也会用:arm-linux-gcc hello.c
但是这是不对的,为什么呢? 我们来仔细想一个问题,我们是裸机(好吧,我承认稍微穿了一点),没有操作系统 。想想arm 执行时,它希望
执行的第一条指令是什么?肯定是一条有效的指令了。但是我们生成的这个a.out的前面是有效的可执行的语句么?也许你已经想到了,它的头不是什么
有效指令,是ELF头信息,还有你的用户 名呢,用户名不能执行吧?呵呵,开玩笑。

还有一个问题。
gcc默认的连接地址是你想要的么?八成不是吧。
鉴于以上原因我们要分步进行:
1:编译
arm-linux-gcc -c hello.c -o hello.o
生成hello.o文件。
2:链接 指定我们要的链接地址0x50000000
arm-linux-ld -Ttext=0x50000000 hello.o -o hello
这时你用arm-linux-objdump -d hello 反汇编一下,看看指令的起始地址是50000000吧?
3:去除头ELF头信息
arm-linux-objcopy -L elf32-littlearm -O binary hello hello.bin
这里elf32-littlearm 是指定大小端,咱小端的。
就这样,我们可以在裸板上运行 的二进制程序 就这样成了。为了以后方便可以把上面的指令写在Makefile里,一个make就all了。


总结:就是函数的入口地址搞不清楚,不是在50008000,故失败,先放这里,这个不着急,等有时间再来仔细研究研究。

相关文章
|
3月前
|
安全 Linux Shell
Linux上执行内存中的脚本和程序
【9月更文挑战第3天】在 Linux 系统中,可以通过多种方式执行内存中的脚本和程序:一是使用 `eval` 命令直接执行内存中的脚本内容;二是利用管道将脚本内容传递给 `bash` 解释器执行;三是将编译好的程序复制到 `/dev/shm` 并执行。这些方法虽便捷,但也需谨慎操作以避免安全风险。
215 6
|
2月前
|
NoSQL 测试技术
内存程序崩溃
【10月更文挑战第13天】
146 62
|
22天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
54 1
|
1月前
|
存储 缓存 Java
结构体和类在内存管理方面的差异对程序性能有何影响?
【10月更文挑战第30天】结构体和类在内存管理方面的差异对程序性能有着重要的影响。在实际编程中,需要根据具体的应用场景和性能要求,合理地选择使用结构体或类,以优化程序的性能和内存使用效率。
|
2月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
155 21
|
3月前
|
C语言 Android开发 C++
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
本文介绍了使用MTuner软件进行Qt MinGW编译程序的内存泄漏检测的方法,提供了MTuner的下载链接和测试代码示例,并通过将Debug程序拖入MTuner来定位内存泄漏问题。
基于MTuner软件进行qt的mingw编译程序的内存泄漏检测
|
2月前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。
|
3月前
|
存储 运维
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
.NET开发必备技巧:使用Visual Studio分析.NET Dump,快速查找程序内存泄漏问题!
|
4月前
|
Java 容器
【Azure Function App】Java Function在运行中遇见内存不足的错误
【Azure Function App】Java Function在运行中遇见内存不足的错误
|
4月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存