嵌入式linux应用开发手册笔记

2019-07-12 22:15发布

嵌入式linux应用开发手册笔记

嵌入式linux应用开发手册笔记嵌入式linux应用开发手册笔记嵌入式linux应用开发手册笔记 -O 大写 嵌入式linux应用开发手册笔记

连接器选项 下面的选项用于连接obj文件,输出可执行文件或库文件 -llibrary 连接名为library的库文件 -nostartfiles 不连接系统标准启动文件,用于编译bootloader、内核 -nostdlib 不连接系统标准启动文件和标准库文件,用于编译内核、bootloader,他们不需要启动文件标准库文件 -static   阻止使用连接共享库 -shared 生成一个共享obj库

目录选项 -Idir 在头文件的搜索路径列表中添加dir目录 头文件的搜索方法:#include<>只从标准库目录开始搜索(包括使用-Idir选项定义的目录) #include“”先从用户的工作目录开始搜索,在搜索标准库目录 -I- 只是用于#includ“”,在-I-前面的-I搜索路径只是用于#include “”  ;如果用“-I”选项指定的搜索路径位于-I-选项后面,就可以在这些路径中搜索所有的#include指令, -I选项能够阻止当前目录成为搜索“#include”的第一选择
-Ldir 在-I选项的搜索路径列表中添加dir目录 在-I选项的搜索路径列表中添加dir目录


嵌入式linux应用开发手册笔记 -T可以直接指定代码段数据段,bss段的起始地址也可以用来指定一个连接脚本,在连接脚本中进行更复杂的地址设置;只用于bootloader、内核等“没有底层软件支持”的软件;连接运行与操作系统之上的应用程序无需指定-T选项, 格式如下: -Ttext startaddr -Tdata startaddr -Tbss startaddr嵌入式linux应用开发手册笔记 b、bl、mov 不依赖于-Ttext选项,ldr依赖。
2.使用连接脚本设置地址 arm-linux-ld -Ttimer.lds -o xxx 他使用连接脚本timer.lds来设置可执行文件timer_elf的地址信息,timer_elf文件内容如下: SECTIONS { .=0X30000000;    //设置“当前运行地址”为0x30000000 .text             : {*(.text)} //定义了一个名为‘.text'的段它的内容为“*(.text)”,表示所有输入文件的代码段。这些代码段被集合在一起,起始运行地址为0x30000000. .rodata ALIGN(4) :{*(.rodata)}//定义“.rodata”段,ALIGN(4)表示起始运行地址为4字节对齐,假设前面段的地址范围是0x30000000~0x300003f0,则“.rodata”段的地址是4字节对齐后的0x300003f4 .data ALIGN(4)     :{*(.data)} .bss ALINGN(4)     :{*(.bss     *(COMMON)} } 完整的连接脚本格式如下: SECTIONS { ... secname start ALIGN(align)(NOLOAD) :AT(ldadr) {contents}>region:phdr =fill ... } secname 和contents是必需的,前者用来命名这个段,后者用来确定代码中的说明部分 (NOLOAD):用来告诉加载器,在运行时不用加载这个段, AT(ldadr):指定这个段在编译出来的映像文件中的加载地址如果不使用这个选项,则加载地址等于运行地址

3.1.3 arm-linux-objcopy用来将elf格式的可执行文件转换为二进制文件 被用来复制一个目标文件的内容到另一个文件,可以使用不同于源文件的格式来输出目的文件,即可以进行格式转换。  arm-linux-objcopy -O binary -S led_elf led.bin
arm-linux-objdump -D xxx > xxx.dis  反汇编指令

3.2 Makefile target..:依赖 ....   (command) eg:  hello:hello.c      gcc -o hello  hello.c   //执行编译hello.c clean:       rm -f hello     //清除编译出来的文件    注意:每个命令行前面必须是一个tab字符,即命令行第一个字符是tab,这是容易出错的地方

3.2.2 MAKEFILE 赋值  分为延时变量和立即变量区别在于前者在使用时才扩展开(才确定),后者是在定义时它的值已经确定了。 immeddiate=deferred  //延时变量 immeddiate?=deferred  //用来定义第一次出现的延时变量 immeddiate:=deferred //立即变量 immeddiate+=deferred  or immediate  //若右边变量在前面使用(:=)定义为立即变量则它也是立即变量,否则均为延时变量
3.2.3 函数格式:$(function arguments) $(subst from,to,text) 在文本中to替换每一处from(字母) $(patsubst pattern,replacement,text)//寻找text中符合pattern的字用replacement替换它们(字符串?) $(strip string)//去掉前导和结尾空格,并将中间的多个空格压缩为单个空格,如$(strip a   b  c)结果为a b c $(findstring find,in)在字符串“in”中搜寻“find”,如果找到,则返回值是“find”,否则返回值为空 $(filter pattern...,text) //返回text中由空格隔开且匹配格式“pattern...”的字 $(sort list) //将list中的字按字母顺序排序,并去掉重复的字
以options程序的Makefile为例,options目录下所有的文件为main.c Makefile sub.c sub.h 。Makefile 内容如下: src :=$(shell ls *.c)   //src=main.c sub.c objs:=$(patsubst %.c,%.o,$(src)) //objs=main.o sub.o
test:$(objs)    //test:main.o sub.o      gcc -o $@ $^
%.o:%.c      gcc -c -o $@ $<
clean:      rm -f test *.o
3.3.1 arm asm and atpcs rules
跳转指令b、bl  bl除了跳转之外,还将返回地址(bl的下一条指令的地址)保存在lr寄存器中,这两条指令的可调转范围是当前指令的前后32mb

mov  mov r1,r2     //r1=r2 mov r1,#4096   //传送的常数必须能用立即数来表示 

ldr:从内存中读取数据到寄存器,str :相反,它们的操作数据都是32位 ldr 即可能是大范围的地址读取指令可能是内存访问指令,当第二个参数有=时表示伪指令 ldr r1,=4097  //r1=4097// d ldr r1,=label label: ....

ldr r1,[r2,#4]   //将r2+4的内存地址数据读取到r1中 ldr r1,[r2],#4  //将r2的内存地址数据读取到r1中然后r2=r2+4 str r1,[r2,#4]  //[r2+4]=r1 str r1,[r2],#4   //[r2]=r1,r2=r2+2 ldmia strdb add sub
add r1,r2,#4  .r1=r2+4 sub r1,r2,#4  .r1=r2-4
msr and mrs ARM有一个程序状态寄存器cpsr,它用来控制处理器的工作模式、设置中断的总开关 msr cpsr,r0  .复制r0到cpsr中 mrs r0,cpsr .复制cpsr到r0中

other asm eg: .extern      main   //定义一个外部符号变量或函数,在这里指引用外部函数main .text                //表示下面的语句都是代码段 .global      _start          //.global将文件中的某个程序标号定义为全局的 _start:

汇编指令执行条件2012年9月3日 15:10:34 嵌入式linux应用开发手册笔记


ATPCS(子程序调用规则) 1.寄存器使用规则 arm 处理器中有r0~r15共16个寄存器 嵌入式linux应用开发手册笔记
FD:Full Descending 满递减 ED:Empty Descending 空递减 FA:Full Ascending 满递增 EA:empty ascending 空递增
数据栈为FD,8字节对齐使用stmdb/ldmia批量内存访问指令来操作fd数据栈 使用stmdb命令玩数据栈中保存内容时先递减sp指针,在保存数据(入栈) eg:stmdb sp!,{fp,ip,lr} 使用ldmia命令从数据栈中恢复数据先获得数据在递增sp指针,sp指针总是指向栈顶元素 eg:ldmia sp,{fp,sp,pc}

3.参数传递规则 int copycode2sdram(unsigned char *buf,unsigned long strart_addr,int size) 在汇编代码中,使用下面的代码调用它并判断返回值 ldr r0,=0x30000000 //  *buf=0x30000000 mov r1,#0    // start_addr=0 mov r2,#16*1024  //size=16*1024 cmp a0,#0  //return value



第五章  gpio接口 s3c2440有130个I/O口:gpa、gpb...gpj。 通过寄存器来操作gpio引脚 GPXCON(32位) GPXCON用于选择引脚功能、gpxdat用于读/写引脚数据;gpxup用于确定是否使用上拉电阻。 gpacon寄存器对应gpa(共23个引脚),当gpacon某位=0,我们可以在gpadat相应位写入0或1让此引脚输出低电平或高电平,gpacon=1,gpa相应引脚为地址线或用于地址控制,一般gpacon全设为1以便访问外部存储器件 gpbcon~gpjcon 没两位控制一根引脚:00=输入;01=输出;10=特殊功能;11=保留不用 gpb=[10:0]
GPXDAT GPXDAT根据gpxcon设置来读/写引脚状态
GPXUP gpxup=1,相应引脚无内部上拉电阻;gpxup=0,使用内部上拉电阻 嵌入式linux应用开发手册笔记 1.访问单引脚 #define GPBCON   (*(volatile unsigned long *)0x56000010) #define GPBDAT    (*(volatile unsigned long*) 0x56000014) #define GPB5_out  (1<<(5*2)) GPBCON=GPB5_out;     // gpb5=out, GPBDAT&=~(1<<5);   //GPB5=0

2.总线方式访问
5.2 点亮第一个led灯 tq2440 4个灯 嵌入式linux应用开发手册笔记嵌入式linux应用开发手册笔记 gpbcon对应地址 0x56000010  gpbdat对应地址0x56000014 估汇编程序如下:  1 .text
  2 .global _start
  3 _start:
  4         LDR R0,=0x56000010
  5         MOV R1,#0x400
  6         STR R1,[R0]    @GPBCON  SET OK
  7
  8
  9         LDR R0,=0x56000014
10         MOV R1,#0x0
11         STR R1,[R0]       @GPBDAT SET OK
12
13 main:
14         B main 

对应makefile 如下:
  1 led.bin:led.s
  2         arm-linux-gcc -g -c -o led.o led.s       //-g 可执行程序中包含标准调试信息  -s只编译不连接生成汇编代码  -c只编译不链接生成目标文件”o“  
  3         arm-linux-ld -Ttext 0x30000000 -g led.o -o led_elf   //链接
  4         arm-linux-objcopy -O binary -S led_elf led.bin  -O//elf转为二进制bin并优化
  5 clean:
  6         rm -f *elf *.o  //删除



使用C语言点灯 嵌入式linux应用开发手册笔记 crt0.s @*****************
@trun to c
@*******************
.text
.global _start
_start:
     ldr r0,=0x56000010  @watchdog conf addr
     mov r1,#0x0
     str r1,[r0]         @stop watchdog
    
     ldr sp,=1024*4         @sp<=4kb
    

     bl main            @use c main

halt_loop:
     b      halt_loop



ledonc.c #define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
int main()
{
     GPBCON=0X400;//GPB5C5=01 OUT
     GPBDAT=0X00;     //GPB5=0
     return 0;
}

MAKEFILE: ledonc.bin:crto.s ledonc.c
     arm-linux-gcc -g -c -o crto.o     crto.s
     arm-linux-gcc -g -c -o ledonc.o ledonc.c
     arm-linux-ld -Ttext 0x0000000 -g crto.o ledonc.o -o ledonc_elf
     arm-linux-objcopy -O binary -S ledonc_elf ledonc.bin
     arm-linux-objdump -D -m arm ledonc_elf >ledonc.dis

clean:
     rm -f ledonc.dis ledonc.bin ledonc_elf *.o


3.使用按键是对应灯亮 嵌入式linux应用开发手册笔记嵌入式linux应用开发手册笔记 gpfcon=0x56000050 gpfdat=0x56000054
crt0.s @*****************
@trun to c
@*******************
.text
.global _start
_start:
     ldr r0,=0x56000010  @watchdog conf addr
     mov r1,#0x0
     str r1,[r0]         @stop watchdog
    
     ldr sp,=1024*4         @sp<=4kb
    

     bl main            @use c main

halt_loop:
     b      halt_loop

keyledon.c #define GPBCON (*(volatile unsigned long*)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
#define GPFCON (*(volatile unsigned long *)0x56000050)
#define GPFDAT (*(volatile unsigned long *)0x56000054)

int main()
{
     GPBCON=0x15400; //gpbcon=010101010000000000
     GPFCON=0x00; //00 means input

     int rdat; //use toread gpfdat
     while(1)
     {
          rdat=GPFDAT;
          if(rdat&0x01)
               GPBDAT=0x10;//led0 off
          else
               GPBDAT=0xef; //led0 on
            //     if(rdt&)
     }


}

Makefile keyled.bin:crto.s keyledon.c
     arm-linux-gcc -g -c -o crto.o  crto.s
     arm-linux-gcc -g -c -o keyledon.o keyledon.c
     arm-linux-ld -Ttext 0x00000000 -g crto.o keyledon.o -o keyledelf
     arm-linux-objcopy -O binary -S keyledelf keyledelf.bin
    

clean:
     rm -f  *.o *.bin *elf