【龙芯1c库】移植标准c库libc(libm类似)

本文将pmon中的libc移植到龙芯1c库中,用于龙芯1c的纯裸机编程。实际上标准的clibc不应该属于龙芯1c库,狭义的“龙芯1c库”应该是像“STM32库”那样只封装了各个外设的功能,这里说的“龙芯1c库”我认为应该是“广义的”,泛指裸机编程需要的各种常用功能的集合。先不咬文嚼字了,暂且这样理解吧。

除了libc外,标准数学库libm的移植也是类似的。

龙芯1c库的git地址是https://gitee.com/caogos/OpenLoongsonLib1c

为什么需要移植libc

为什么需要移植libc?因为需要用到libc中的一些函数啊。比如printfstrcpystrcatstrstr等等。

Libc中包括两类函数:字符串处理相关的函数(比如strcpy, strcat, strstr等等)和文件相关的函数(比如fopen, fclose, fgetc, fputc, fread, fwrite, printf等等)。对于单片机的裸机编程来说,只需要字符串处理相关的函数和printf就够了,其中printf是个特例,是我们移植的唯一一个文件相关的函数。

使用printf()函数打印调试信息时非常实用、非常常见的。而printf()函数的作用就是将字符串格式化,即在字符串中携带一些变量的值,比如用printf()函数打印“当前温度值=xxx”。

Printf()在格式化字符串的时候就需要使用各种字符串处理函数。除此之外,在解析或组建一些协议时,可能也需要使用字符串相关的一些函数。

怎样移植libc

字符串处理相关的函数

参考pmonPmon本身就是一个纯粹的裸机程序,里面也包含了libclibm。先来看下pmon里面的libc目录长什么样。如下


细心的读者可能已经注意到了,libc文件夹中的文件名好像有点熟悉也,对不对?^__^,对,就是在常用的strcpy, strcat, strcmp, strlen等函数后面加了“.c”。难倒每个函数单独放一个c文件吗?经过验证,是的,同一个源文件中,要么只有一个函数,要么就是功能相似的多个函数。比如:strcpy()strlcpy()都位于strcpy.c中。下面来看下只有一个函数的情况,比如strcat.c,如下


其它的函数也类似,好,明白了这点就好移植了。说是移植,其实就是把需要的文件拷贝过去,然后编译,根据错误提示逐个解决即可。大致思路就这样。

函数printf()

函数printf()详解

Printf()是文件相关的函数,功能是把信息打印到文件。而对于裸机编程来说没有文件系统那一套,所以需要对printf稍微修改一下。下面把修改前和修改后的printf源码贴出来

Pmon中的printf()源码(修改前),

#include <stdio.h>
#include <stdarg.h>

/** printf(fmt,va_alist) -- print formatted output to stdout */
extern unsigned int output_mode;
int 
printf (const char *fmt, ...)
{
    int             len;
    va_list	    ap;

#ifdef	FAST_STARTUP
    if (output_mode == 0)
	    return 0;
#endif

    va_start(ap, fmt);
    len = vfprintf (stdout, fmt, ap);
    va_end(ap);
    
    return (len);
}

(修改后的)龙芯1c库中的printf源码

#include <stdio.h>
#include <stdarg.h>
#include "../lib/ls1c_uart.h"


#define PRINTF_BUF_SIZE                 (512)

int printf (const char *fmt, ...)
{
    int     len;
    va_list ap;
    char    buf[PRINTF_BUF_SIZE];

    va_start(ap, fmt);

    // 格式化字符串
    len = vsprintf (buf, fmt, ap);

    // 调用龙芯1c库中的串口函数打印字符串
    uart_debug_print(buf);
    
    va_end(ap);
    
    return (len);
}

函数vsprintf()就是将传递给printf()的入参按照指定的格式,将其转换为一个字符串并放入buf中,函数uart_debug_print()就只需要一个字符一个字符慢慢发送即可。

函数uart_debug_print()源码如下

/*
 * 在调试串口打印字符串
 * @str 待打印的字符串
 */
void uart_debug_print(const char *str)
{
    uart_print(debug_uart_info.UARTx, str);
    return ;
}

函数uart_print()的源码为

/*
 * 打印一个字符串到指定串口
 * @uartx 串口号
 * @str 待打印的字符串
 */
void uart_print(ls1c_uart_t uartx, const char *str)
{
    while ('\0' != *str)                // 判断是否为字符串结束符
    {
        uart_putc(uartx, *str);   // 发送一个字符
        str++;
    }

    return ;
}

函数uart_putc()就是操作cpu的寄存器发送一个字符。

/*
 * 发送一个字节
 * @uartx 串口号
 * @ch 待发送的字符串
 */
void uart_putc(ls1c_uart_t uartx, unsigned char ch)
{
    void *uart_base = uart_get_base(uartx);
    
    // 等待
    while (FALSE == uart_is_transmit_empty(uartx))
        ;

    // 发送
    reg_write_8(ch, uart_base + LS1C_UART_DAT_OFFSET);

    return ;
}


用函数printf()打印浮点数

前面分析了函数printf()的流程,对于打印字符串和整数来说,有了libc中的字符串处理函数就足够了。但是要打印浮点数,首先需要支持浮点运算(不论是软浮点,还是硬浮点都可以),其次是需要几个libm中的函数。博文【龙芯1c库】移植硬浮点FPU讲了如何使能龙芯1c的FPU,这里重点讨论一下printf()是如何打印浮点数的,需要使用到那些libm函数。

函数printf()中调用函数vsprintf()将浮点数转换为字符串并打印出来,下面来看下是如何转换的,函数vsprintf()中打印浮点相关的代码如下

#ifdef FLOATINGPT
				else if (strchr ("eEfgG", *s)) {
					dbl = va_arg(ap, double);
					dtoa (d, dbl, *s, width, trunc);
					trunc = 0;
				}
#endif

从代码可知,首先定义宏FLOATINGPT,否则这段代码将不会被编译,即printf()  将不支持打印浮点数。宏FLOATINGPT定义如下

// printf支持打印浮点,如果不需要打印浮点,则注释掉该宏
#define FLOATINGPT

假设定义了宏FLOATINGPT,那么代码中每次调用printf()函数时,都会执行这段代码。这段代码的含义是,调用函数strchr()判断是否有“eEfgG”中的至少其中一个字符,如果有,则说明需要打印浮点数。即printf()的参数中有%e、%E、%f、%g或者%G。

然后就是调用dtoa()将浮点数转换为字符串,其中dtoa()中会调用一些libm中的函数,具体就自己查看源码吧。我已经把相关函数从pmon的libm中移植到龙芯1c库中了,直接使用printf()即可。这里主要是想提一下,宏FLOATINGPT控制printf()是否支持打印浮点


Makefile

Pmon中是把libc中的源文件编译为静态库libc.a,然后再与其它源文件一起编译链接的。考虑到目前龙芯1c库中的源文件个数并不多,暂时没有先把libc编译为libc.a,而是和其它源文件一样,直接把c文件编译为.o,然后直接连接。

但这里还是顺便把pmon中生成libc.a的过程提一下。

创建静态库

首先还是需要把c文件编译为.o文件,然后再用arranlib生成libc.apmonlibc的完整的Makefile如下

LIB=c
NOPIC=

MACHINE=	${XMACHINE}
MACHINE_ARCH=	${XMACHINE_ARCH}
CURDIR=$(shell pwd)

M=	${CURDIR}/arch/${MACHINE_ARCH}

CPPFLAGS=	-I$M ${CLIBCPPFLAGS} -U_KERNEL

VPATH+=	${M} ${CLIBDIR}
 
include ${M}/Makefile.inc

# Files to clean up
CLEANFILES+= ${OBJDIR}/lib${LIB}.a

include ${PMONDIR}/tools/scripts/pmon.lib.gmk

${OBJDIR}/lib${LIB}.a: ${OBJS}
	@echo building standard ${LIB} library
	@rm -f $@
	@${AR} cq $@ ${OBJS}
	${RANLIB} $@

注意,@表示在make时不输出make的信息(类似Windows下的echo   off)。所以想要把完整的编译过程打印出来,需要把命令前面的@去掉。完整的编译过程如下

building standard c library
mipsel-linux-ar cq /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/libc.a /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/abs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/argvize.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atob.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atof.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atoi.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/atol.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/bzero.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/bcmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/calloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cc2str.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/close.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ctype_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/dbl2asci.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/errno.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ethers.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/exit.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fclose.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/feof.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fflush.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ffs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fls.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fgetc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fgets.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fileno.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fputs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fread.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fseek.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/fwrite.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getchar.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/gethostnamadr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getopt.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getprotoname.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/gets.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getservbyname.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getservent.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getword.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/index.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/inet_addr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/lseek.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/malloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/memchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/memset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/misc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/modf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/open.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/pmalloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/printf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/putc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/putchar.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/puts.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/qsort.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/queue.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/rand.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/read.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/realloc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/recv.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_comp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_init.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_mkquery.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_query.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/res_send.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/rindex.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sbrk.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/scanf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/send.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/signal.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sigsetops.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sizemem.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/sprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/stdio.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/str2cc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/str_fmt.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strbalp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strbequ.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcasecmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strccat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcpy.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strcspn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strdchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strempty.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strichr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/striequ.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/stristr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strlen.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strmerge.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strnchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strncpy.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strnwrd.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strpat.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strpbrk.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strposn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrchr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrpset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrrot.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strrset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strset.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strsort.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strspn.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strstr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strtok.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/strtoupp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/terms.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/time.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tolower_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/toupper_.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ungetc.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/vfprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/vsprintf.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/write.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/getbaud.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcdrain.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcflow.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcflush.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcgetattr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcgetpgrp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsendbreak.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsetattr.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/tcsetpgrp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfgetispeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfgetospeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfmakeraw.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetispeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetospeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/cfsetspeed.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ulmin.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/lmin.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ioctl.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/filefs.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/parseurl.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/crc32.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/poweroff.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/reboot.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/video_set_lut.o   /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/longjmp.o /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/ovbcopy.o
mipsel-linux-ranlib /home/develop/loongson1-pmon-master/Targets/LS1X/compile/ls1c/lib/libc/libc.a

头文件

虽然libc的各个函数可能都单独在一个源文件中,但是他们都按照惯例分门别类位于几个常见的头文件,比如stdio.h stdlib.h string.h……。常常把这几个头文件单独放一个文件夹,然后把该文件夹的路径添加到Makefile中的变量VPATH中,如下

VPATH += include

这样就可以在其它源文件中使用了。用法不变,如下

#include <stdio.h>

#include <stdlib.h>

……


感谢阅读!







猜你喜欢

转载自blog.csdn.net/caogos/article/details/79551884