最近在跟着《CPU设计实战》这本书学习MIPS指令集CPU的设计,在进行到4.3.1节快速上手CPU设计的开发环境的第4步,编译测试程序时,遇到了一个报错,网上也没找到方法,故记录一下自己的解决方法。
书上这一步的要求是:将一个有预先写好程序的func目录(此书的资源里已经提供)设置为一个已经安装了MIPS-GCC交叉编译工具的Linux虚拟机的共享目录,然后在虚拟机中进入soft/func目录,先运行make clean,再运行make进行编译。我采用的是openEuler20.03系统照着https://blog.csdn.net/alfiy/article/details/121653881https://blog.csdn.net/alfiy/article/details/121653881 这篇文章所描述的方法装了buildroot。但是如果用的是其他操作系统或其他编译工具,或者在进行其他项目时,如果遇到类似的问题,应该也能通过以下方式解决。
这是运行make时遇到的报错内容,部分无关的省略掉了:
[openeuler@test func]$ make
make compile
(--------------中间部分内容省略-----------------)
make[2]: Leaving directory '/mnt/hgfs/func/inst'
mipsel-linux-gcc -E -P -Umips -D_LOADER -U_MAIN -D_KERNEL -fno-builtin -mips1 -DMEMSTART=0x80000000 -DMEMSIZE=0x04000 -DCPU_COUNT_PER_US=1000 -I /mnt/hgfs/func/include -fno-reorder-blocks -fno-reorder-functions -EL bin.lds.S -o bin.lds
mipsel-linux-ld -g -EL -T bin.lds -o main.elf start.o -L . -linst
mipsel-linux-ld: section .MIPS.abiflags LMA [00000000bfcb0c48,00000000bfcb0c5f] overlaps section .data LMA [00000000bfcb0c48,00000000bfcb0c57]
make[1]: *** [Makefile:33: main.elf] Error 1
make[1]: Leaving directory '/mnt/hgfs/func'
make: *** [Makefile:13: all] Error 2
[openeuler@test func]$
执行mipsel-linux-ld -g -EL -T bin.lds -o main.elf start.o -L . -linst这句时报section重叠。网上搜索了一圈发现,问题应该是这本书提供的源代码里没有给.data和.MIPS.abiflags的内容分配空间或是分配的不合理,导致了内容过多时存储会有重叠,导致报错。参考了另一篇有类似报错的文章,https://blog.csdn.net/weixin_39871788/article/details/78858791,尝试了以下方法,问题解决。
在文件夹中找到bin.lds文件(做完后发现改动bin.lds.S也可以,但是最后一步的操作有所不同)。因为这个文件夹是虚拟机和主机的共享文件夹,所以在主机上打开修改就行。
如果是在其他地方或项目里出现了这种问题,就去找项目里的以.ld或者.lds为后缀的文件打开修改。.ld文件里面的格式和不同语句分别代表什么意思网上都有,而且很详细。这里就不多介绍。
用任意文本编辑器打开后在第二行和第三行之间插入如下内容,给不同的内容分配不同的空间。如果已经存在MEMORY模块,就往里面加语句(也就是定义新空间)或者数字改大。
MEMORY
{
RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 1024K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
加上上面的语句后就可以使用定义的空间了。在.data的大括号后面加上 >RAM,表示这块内容使用刚才的分配空间。
.data : AT(rodata_end)
{
(中间部分省略,完整的代码会贴在后面)
} >RAM
这个报错是因为.MIPS.abiflags存在冲突,于是就在文件中另找一个地方插入如下几行,表示给.MIPS.abiflags使用刚才分配的另一个空间,避免冲突。在哪个位置插入似乎影响不大,我是插入到了.bss块的大括号后面的一行。如果是其他文件或项目的问题,对照插入或者找到相应的地方修改即可。
.MIPS.abiflags : {
. = ALIGN(4);
*(.MIPS.abiflags*)
. = ALIGN(4);
} >FLASH
改好后完整的bin.lds文件如下:
OUTPUT_ARCH(mips)
ENTRY(_start)
MEMORY
{
RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 1024K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
SECTIONS
{
. = 0xbfc00000;
.text :
{
_ftext = . ;
*(.text)
*(.rodata*)
*(.reginfo)
*(.init)
*(.stub)
*(.gnu.warning)
rodata_end = .;
} =0
_etext = .;
PROVIDE (etext = .);
.fini : { *(.fini) } =0
. = 0x80000000;
.data : AT(rodata_end)
{
_fdata = . ;
_stack = _fdata + 0x04000 -32;
*(.data)
*(.data*)
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2)
*(.ctors)
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2)
*(.dtors)
LONG(0)
__DTOR_END__ = .;
_gp = ALIGN(16) + 0x7ff0;
*(.got.plt) *(.got)
*(.sdata)
*(.lit8)
*(.lit4)
} >RAM
_edata = .;
PROVIDE (edata = .);
data_size = SIZEOF(.data);
data_load_start = LOADADDR(.data);
__bss_start = .;
_fbss = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
.MIPS.abiflags : {
. = ALIGN(4);
*(.MIPS.abiflags*)
. = ALIGN(4);
} >FLASH
. = ALIGN(8);
_end = . ;
PROVIDE (end = .);
. = ALIGN(32);
.bigdata : { *(.bigdata) }
. = ALIGN(256);
_heap = . ;
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.debug 0 : { *(.debug) }
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_sfnames 0 : { *(.debug_sfnames) }
.line 0 : { *(.line) }
.gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
.gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
}
将改好的文件保存好即可。如果你是在bin.lds文件里改动的,则需要再打开相同目录下的Makefile文件,找到下面这一段,把其中第一行注释掉,避免重新编译时刚才所做的改动被覆盖。如果上面的内容是在bin.lds.S文件中改动,则可忽略这一步。
main.elf: start.o libinst.a
#把下面这行注释掉,避免重新编译时刚才所做的改动被覆盖
#${CROSS_COMPILE}gcc -E -P -Umips -D_LOADER -U_MAIN $(CFLAGS) bin.lds.S -o bin.lds
${CROSS_COMPILE}ld -g -EL -T bin.lds -o $@ start.o -L . -linst
${CROSS_COMPILE}objdump -alD $@ > test.s
改动完成,再次在Linux上重新运行make clean和make命令(如果是在bin.lds.S里做的改动,就运行make reset),成功编译。如果是其他工程或项目中报错,那就按照对应项目中的说明重新运行。