下载源代码
https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/old-versions/linux-0.12.tar.gz
====
高版本gcc编译出的镜像有问题,无法正常运行,需要安装低版本gcc进行编译
经测试gcc 3.4、4.8.5、5.4.0、6.5.0、7.3.0、8.2.0 编译出的镜像均可以正常运行,
gcc 7.4.0、7.5.0、8.3.0、8.4.0、9.1.0、9.4.0 编译出的镜像则无法正常运行
安装gcc-3.4
#!/bin/bash
env_install(){
sudo apt-get install -y make bin86 gcc-multilib &> /dev/null \
&& _echo_succ "bin86 is installed." || _echo_err "bin86 is not installed!!!"
if [ ! -z `which gcc-3.4` ];then
_echo_succ "Gcc-3.4 is installed."
return
fi
GCC_DIR="gcc-3.4"
DOWNLOAD_LIST=(
"gcc-3.4-base_3.4.6-6ubuntu3_amd64.deb"
"gcc-3.4_3.4.6-6ubuntu3_amd64.deb"
"cpp-3.4_3.4.6-6ubuntu3_amd64.deb"
"g++-3.4_3.4.6-6ubuntu3_amd64.deb"
"libstdc++6-dev_3.4.6-6ubuntu3_amd64.deb"
)
if [ -z `which gcc-3.4` ]; then
_echo_info "Start installing gcc-3.4..."
for deb in ${DOWNLOAD_LIST[*]}; do
if [ ! -e ${GCC_DIR}/${deb} ]; then
wget http://old-releases.ubuntu.com/ubuntu/pool/universe/g/gcc-3.4/${deb} -P ${GCC_DIR} -q --show-progress && \
_echo_info "Download ${deb} Sucessfully." || ( rm ${deb} & _echo_err "Download ${deb} unsuccessfully!!!" )
fi
done
sudo dpkg -i ${GCC_DIR}/*.deb &> /dev/null
sudo apt-get install -y -f &> /dev/null
if [ ! -z `which gcc-3.4` ];then
_echo_succ "gcc-3.4 is installed."
fi
rm -rf ${GCC_DIR}
fi
}
env_install
搜索全部的Makefile文件
cd linux-0.12
find ./ -name Makefile
./mm/Makefile
./fs/Makefile
./Makefile
./lib/Makefile
./kernel/blk_drv/Makefile
./kernel/Makefile
./kernel/chr_drv/Makefile
./kernel/math/Makefile
修改所有的Makefile中的
CC = gcc-3.4
CFLAGS 增加 -g,如果有 -O 则替换为 -g
修改所有Makefile, 将 $(AS) -c -o $*.o $< 中的 -c 去除。
vi kernel/Makefile
LDFLAGS = -x #-s
vi kernel/math/Makefile
LDFLAGS = -x #-s
====
====
查看已安装的gcc版本
ls /usr/bin/gcc*
gcc版本切换
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-3.4 20 --slave /usr/bin/g++ g++ /usr/bin/g++-3.4 --slave /usr/bin/c++ c++ /usr/bin/c++3.4
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 30 --slave /usr/bin/g++ g++ /usr/bin/g++-8 --slave /usr/bin/c++ c++ /usr/bin/c++8
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 40 --slave /usr/bin/g++ g++ /usr/bin/g++-9 --slave /usr/bin/c++ c++ /usr/bin/c++9
10,20这些表示的是优先级,可根据需要选定,优先级高的即为默认的。
update-alternatives --config gcc
输入数字来选择gcc版本
====
====
或者使用docker gcc:
docker pull gcc:8.2.0
docker run -it -v /home/li/linux-0.12-master/linux-0.12:/opt/ --name gcc820 gcc:8.2.0
cd /opt/
make clean && make
docker cp /bin/as86 gcc820:/bin/
docker cp /bin/ld86 gcc820:/bin/
====
====
重要操作:
vi linux-0.12/tools/build.c
#define DEFAULT_MINOR_ROOT 6
#define DEFAULT_MAJOR_SWAP 0
#define DEFAULT_MINOR_SWAP 0
To:
#define DEFAULT_MINOR_ROOT 1
#define DEFAULT_MAJOR_SWAP 3
#define DEFAULT_MINOR_SWAP 4
vi linux-0.12/tools/build.c
Line 193:
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
//if (((long *) buf)[5] != 0)
// die("Non-GCC header of 'system'");
To:
/**
* 去掉这里的原因是
* 1. 去除a.out格式头部的动作已经在主目录Makefile中进行了,故在这里注释掉。
* 2. 入口位置不应该是((long *) buf)[5],应该为((long *) buf)[6],可以在linux下,通过
* 命令 readelf -h system 和 od -w4 -N 80 -x system 对比看到入口地址应该在第28~31个
* 字节处。
*/
//if (read(id, buf, GCC_HEADER) != GCC_HEADER){
// die("Unable to read header of 'system'");
//}
//if (((long *) buf)[5] != 0)
// die("Non-GCC header of 'system'");
vi linux-0.12/kernel/blk_drv/hd.c
while (--retries && (inb_p(HD_STATUS)&0xc0)!=0x40);
To:
while (--retries && (inb_p(HD_STATUS)&0x80));
启动linux0.12 系统。你会发现,如果输入问号,显示的是_,如果输入分号,终端显示的是|。
原因很简单,linux的作者linus是芬兰人,使用的是芬兰语键盘。我们只需要编辑源代码,把默认的键盘类型改成英语键盘就可以了。
vi kernel/chr_drv/keyboard.S
#define KBD_FINNISH
To:
#define KBD_US
====
====
gcc-3.4 -g -Wall -O -fstrength-reduce -fomit-frame-pointer -m32 -fno-builtin \
-o tools/build tools/build.c
In file included from /usr/include/linux/fs.h:14,
from tools/build.c:30:
/usr/include/linux/ioctl.h:5:23: asm/ioctl.h: No such file or directory
In file included from /usr/include/linux/fs.h:15,
from tools/build.c:30:
编译环境问题,需要卸载有问题的编译器
====
====
make
make: gas: Command not found
make: *** [Makefile:35: boot/head.o] Error 127
gas,gld已经被淘汰,该替换成as和ld(所有的Makefile中)
vi Makefile
AS =as
LD =ld
...其他路径下的Makefile...
====
====
boot/head.s: Assembler messages:
boot/head.s:43: Error: unsupported instruction `mov'
boot/head.s:47: Error: unsupported instruction `mov'
在64位机器上如果要编译32位的code,需要在所有Makefile的AS后面添加 --32,CFLAGS中加-m32
vi Makefile
AS =as --32
CFLAGS =-Wall -O -fstrength-reduce -fomit-frame-pointer \
-fcombine-regs -mstring-insns -m32
...其他路径下的Makefile...
====
====
boot/head.s:231: Error: alignment not a power of 2
汇编程序中,align语句的使用方法已经改变。原来align后的数值是内存位置的幂次值,现在则需要直接给出起始地址的整数值,因此align n -> align 2^n
align 3
要改成
align 8
vi boot/head.s
.align 2
To:
.align 4
.align 3
To:
.align 8
====
====
gcc: error: unrecognized command line option '-fcombine-regs'
gcc: error: unrecognized command line option '-mstring-insns'
现在的编译器不支持-fcombine-regs和-mstring-insns选项,在所有Makefile中删除这两个后缀
====
====
gcc -Wall -O -fstrength-reduce -fomit-frame-pointer -m32 \
-nostdinc -Iinclude -c -o init/main.o init/main.c
In file included from init/main.c:8:
init/main.c:23:29: error: static declaration of 'fork' follows non-static declaration
23 | static inline _syscall0(int,fork)
| ^~~~
include/unistd.h:151:6: note: in definition of macro '_syscall0'
151 | type name(void) \
| ^~~~
include/unistd.h:227:5: note: previous declaration of 'fork' was here
227 | int fork(void);
| ^~~~
init/main.c:24:29: error: static declaration of 'pause' follows non-static declaration
24 | static inline _syscall0(int,pause)
| ^~~~~
include/unistd.h:151:6: note: in definition of macro '_syscall0'
151 | type name(void) \
| ^~~~
include/unistd.h:241:5: note: previous declaration of 'pause' was here
241 | int pause(void);
| ^~~~~
init/main.c:26:29: error: static declaration of 'sync' follows non-static declaration
26 | static inline _syscall0(int,sync)
| ^~~~
include/unistd.h:151:6: note: in definition of macro '_syscall0'
151 | type name(void) \
| ^~~~
include/unistd.h:252:5: note: previous declaration of 'sync' was here
252 | int sync(void);
| ^~~~
init/main.c:26:29:报错是说类型不匹配,前面unistd.h中函数是non-static型,这个main.c文件中是static型的,需要把static inline去掉。后面的printf也是一样。
vi init/main.c
_syscall0(int,fork)
_syscall0(int,pause)
_syscall1(int,setup,void *,BIOS)
_syscall0(int,sync)
int printf(const char *fmt, ...)
====
====
In file included from init/main.c:42:
include/string.h: In function ‘strcpy’:
include/string.h:29:1: error: ‘asm’ operand has impossible constraints
29 | __asm__("cld\n"
| ^~~~~~~
make: *** [Makefile:36: init/main.o] Error 1
类似的问题在后面编译中出现好多,C内嵌汇编的格式__asm__(汇编语句:输入寄存器:输出寄存器:可能被修改的寄存器),
最新的GCC规定输入或输出寄存器不能出现在可能被修改的寄存器中。
由于as的不断改进,现在不需要程序员人为指定寄存器了,因此需要把代码中的__asm__("ax")全部去掉。例如:"si","di","ax","cx"); 改为 );
逐个修改:
vi include/string.h
extern inline char * strcpy(char * dest,const char *src)
{
__asm__("cld\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
::"S" (src),"D" (dest)
);
return dest;
}
extern inline char * strncpy(char * dest,const char *src,int count)
{
__asm__("cld\n"
"1:\tdecl %2\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"rep\n\t"
"stosb\n"
"2:"
::"S" (src),"D" (dest),"c" (count)
);
return dest;
}
extern inline char * strcat(char * dest,const char * src)
{
__asm__("cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff)
);
return dest;
}
extern inline char * strncat(char * dest,const char * src,int count)
{
__asm__("cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n\t"
"movl %4,%3\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %2,%2\n\t"
"stosb"
::"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
);
return dest;
}
extern inline int strcmp(const char * cs,const char * ct)
{
register int __res;
__asm__("cld\n"
"1:\tlodsb\n\t"
"scasb\n\t"
"jne 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"jmp 3f\n"
"2:\tmovl $1,%%eax\n\t"
"jl 3f\n\t"
"negl %%eax\n"
"3:"
:"=a" (__res):"D" (cs),"S" (ct)
);
return __res;
}
extern inline int strncmp(const char * cs,const char * ct,int count)
{
register int __res;
__asm__("cld\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tmovl $1,%%eax\n\t"
"jl 4f\n\t"
"negl %%eax\n"
"4:"
:"=a" (__res):"D" (cs),"S" (ct),"c" (count)
);
return __res;
}
extern inline char * strchr(const char * s,char c)
{
register char * __res;
__asm__("cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"je 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"movl $1,%1\n"
"2:\tmovl %1,%0\n\t"
"decl %0"
:"=a" (__res):"S" (s),"0" (c)
);
return __res;
}
extern inline char * strrchr(const char * s,char c)
{
register char * __res;
__asm__("cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"jne 2f\n\t"
"movl %%esi,%0\n\t"
"decl %0\n"
"2:\ttestb %%al,%%al\n\t"
"jne 1b"
:"=d" (__res):"0" (0),"S" (s),"a" (c)
);
return __res;
}
extern inline int strspn(const char * cs, const char * ct)
{
register char * __res;
__asm__("cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
);
return __res-cs;
}
extern inline int strcspn(const char * cs, const char * ct)
{
register char * __res;
__asm__("cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
);
return __res-cs;
}
extern inline char * strpbrk(const char * cs,const char * ct)
{
register char * __res;
__asm__("cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n\t"
"decl %0\n\t"
"jmp 3f\n"
"2:\txorl %0,%0\n"
"3:"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
);
return __res;
}
extern inline char * strstr(const char * cs,const char * ct)
{
register char * __res;
__asm__("cld\n\t" \
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
"movl %%ecx,%%edx\n"
"1:\tmovl %4,%%edi\n\t"
"movl %%esi,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"repe\n\t"
"cmpsb\n\t"
"je 2f\n\t" /* also works for empty string, see above */
"xchgl %%eax,%%esi\n\t"
"incl %%esi\n\t"
"cmpb $0,-1(%%eax)\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"2:"
:"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
);
return __res;
}
extern inline int strlen(const char * s)
{
register int __res;
__asm__("cld\n\t"
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff)
);
return __res;
}
extern inline void * memcpy(void * dest,const void * src, int n)
{
__asm__("cld\n\t"
"rep\n\t"
"movsb"
::"c" (n),"S" (src),"D" (dest)
);
return dest;
}
extern inline void * memmove(void * dest,const void * src, int n)
{
if (destname),"c" (len)
82 :"cx","di","si");
To:
__asm__(
"cld\n\t"
"fs ; repe ; cmpsb\n\t"
"setz %%al"
:"=a" (same)
:"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len)
);
vi fs/bitmap.c
#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax,%%edx\n\t" \
"je 2f\n\t" \
"addl %%edx,%%ecx\n\t" \
"jmp 3f\n" \
"2:\taddl $32,%%ecx\n\t" \
"cmpl $8192,%%ecx\n\t" \
"jl 1b\n" \
"3:" \
:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
__res;})
To:
#define find_first_zero(addr) ({ \
int __res; \
__asm__( \
"cld\n" \
"1:\tlodsl\n\t" \
"notl %%eax\n\t" \
"bsfl %%eax, %%edx\n\t" \
"je 2f\n\t" \
"addl %%edx, %%ecx\n\t" \
"jmp 3f\n" \
"2:\taddl $32, %%ecx\n\t" \
"cmpl $8192, %%ecx\n\t" \
"jl 1b\n" \
"3:" \
:"=c" (__res) \
:"c" (0), "S" (addr)); \
__res;})
vi fs/bitmap.c
#define clear_block(addr) \
__asm__("cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
To:
#define clear_block(addr) \
__asm__( \
"cld\n\t" \
"rep\n\t" \
"stosl" \
::"a" (0), "c" (BLOCK_SIZE / 4), "D" ((long) (addr)))
vi kernel/blk_drv/floppy.c
#define copy_buffer(from,to) \
__asm__("cld ; rep ; movsl" \
::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
:"cx","di","si")
To:
#define copy_buffer(from,to) \
__asm__("cld ; rep ; movsl" \
::"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \
)
vi kernel/blk_drv/hd.c
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
To:
#define port_write(port,buf,nr) \
__asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr))
vi kernel/blk_drv/hd.c
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
To:
#define port_read(port,buf,nr) \
__asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr))
vi include/asm/memory.h
__asm__ ("cld;rep;movsb" \
::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
:"di","si","cx"); \
To:
__asm__ ("cld;rep;movsb" \
::"D" ((long)(_res)),"S" ((long)(src)),"c" ((long) (n)) \
); \
vi kernel/chr_drv/console.c
199 __asm__("cld\n\t"
200 "rep\n\t"
201 "movsl\n\t"
202 "movl _video_num_columns,%1\n\t"
203 "rep\n\t"
204 "stosw"
205 ::"a" (video_erase_char),
206 "c" ((video_num_lines-1)*video_num_columns>>1),
207 "D" (video_mem_start),
208 "S" (origin)
209 :"cx","di","si");
To:
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl video_num_columns,%1\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((video_num_lines-1)*video_num_columns>>1),
"D" (video_mem_start),
"S" (origin)
);
vi kernel/chr_drv/console.c
214 __asm__("cld\n\t"
215 "rep\n\t"
216 "stosw"
217 ::"a" (video_erase_char),
218 "c" (video_num_columns),
219 "D" (scr_end-video_size_row)
220 :"cx","di");
To:
__asm__("cld\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" (video_num_columns),
"D" (scr_end-video_size_row)
);
vi kernel/chr_drv/console.c
224 __asm__("cld\n\t"
225 "rep\n\t"
226 "movsl\n\t"
227 "movl _video_num_columns,%%ecx\n\t"
228 "rep\n\t"
229 "stosw"
230 ::"a" (video_erase_char),
231 "c" ((bottom-top-1)*video_num_columns>>1),
232 "D" (origin+video_size_row*top),
233 "S" (origin+video_size_row*(top+1))
234 :"cx","di","si");
To:
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*top),
"S" (origin+video_size_row*(top+1))
);
vi kernel/chr_drv/console.c
239 __asm__("cld\n\t"
240 "rep\n\t"
241 "movsl\n\t"
242 "movl _video_num_columns,%%ecx\n\t"
243 "rep\n\t"
244 "stosw"
245 ::"a" (video_erase_char),
246 "c" ((bottom-top-1)*video_num_columns>>1),
247 "D" (origin+video_size_row*top),
248 "S" (origin+video_size_row*(top+1))
249 :"cx","di","si");
To:
__asm__("cld\n\t"
"rep\n\t"
"movsl\n\t"
"movl video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*top),
"S" (origin+video_size_row*(top+1))
);
vi kernel/chr_drv/console.c
259 __asm__("std\n\t"
260 "rep\n\t"
261 "movsl\n\t"
262 "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
263 "movl _video_num_columns,%%ecx\n\t"
264 "rep\n\t"
265 "stosw"
266 ::"a" (video_erase_char),
267 "c" ((bottom-top-1)*video_num_columns>>1),
268 "D" (origin+video_size_row*bottom-4),
269 "S" (origin+video_size_row*(bottom-1)-4)
270 :"ax","cx","di","si");
To:
__asm__("std\n\t"
"rep\n\t"
"movsl\n\t"
"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
"movl video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*bottom-4),
"S" (origin+video_size_row*(bottom-1)-4)
);
vi kernel/chr_drv/console.c
274 __asm__("std\n\t"
275 "rep\n\t"
276 "movsl\n\t"
277 "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
278 "movl _video_num_columns,%%ecx\n\t"
279 "rep\n\t"
280 "stosw"
281 ::"a" (video_erase_char),
282 "c" ((bottom-top-1)*video_num_columns>>1),
283 "D" (origin+video_size_row*bottom-4),
284 "S" (origin+video_size_row*(bottom-1)-4)
285 :"ax","cx","di","si");
To:
__asm__("std\n\t"
"rep\n\t"
"movsl\n\t"
"addl $2,%%edi\n\t" /* %edi has been decremented by 4 */
"movl video_num_columns,%%ecx\n\t"
"rep\n\t"
"stosw"
::"a" (video_erase_char),
"c" ((bottom-top-1)*video_num_columns>>1),
"D" (origin+video_size_row*bottom-4),
"S" (origin+video_size_row*(bottom-1)-4)
);
vi kernel/chr_drv/console.c
599 __asm__("movb %2,%%ah\n\t"
600 "movw %%ax,%1\n\t"
601 ::"a" (translate[c-32]),
602 "m" (*(short *)pos),
603 "m" (attr)
604 :"ax");
To:
__asm__("movb %2,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (translate[c-32]),
"m" (*(short *)pos),
"m" (attr)
);
vi kernel/chr_drv/console.c
345 __asm__("cld\n\t"
346 "rep\n\t"
347 "stosw\n\t"
348 ::"c" (count),
349 "D" (start),"a" (video_erase_char)
350 :"cx","di");
To:
__asm__("cld\n\t"
"rep\n\t"
"stosw\n\t"
::"c" (count),
"D" (start),"a" (video_erase_char)
);
vi kernel/chr_drv/console.c
376 __asm__("cld\n\t"
377 "rep\n\t"
378 "stosw\n\t"
379 ::"c" (count),
380 "D" (start),"a" (video_erase_char)
381 :"cx","di");
To:
__asm__("cld\n\t"
"rep\n\t"
"stosw\n\t"
::"c" (count),
"D" (start),"a" (video_erase_char)
);
vi kernel/chr_drv/console.c
1015 __asm__("movb %2,%%ah\n\t"
1016 "movw %%ax,%1\n\t"
1017 ::"a" (c),
1018 "m" (*(short *)pos),
1019 "m" (attr)
1020 :"ax");
To:
__asm__("movb %2,%%ah\n\t"
"movw %%ax,%1\n\t"
::"a" (c),
"m" (*(short *)pos),
"m" (attr)
);
====
====
ld: relocatable linking with relocations from format elf32-i386 (sched.o) to format elf64-x86-64 (kernel.o) is not supported
make[1]: *** [Makefile:32: kernel.o] Error 1
在64位机器上如果要编译32位的code,需要在所有Makefile的ld后面添加 -m elf_i386
====
====
undefined reference to `__stack_chk_fail_local'
ld: kernel/kernel.o: in function `schedule':
在所有Makefile文件中gcc编译选项CFLAGS后添加 -fno-stack-protector
gcc 3.4不需要添加此参数
====
====
fs/buffer.c:125: undefined reference to `invalidate_buffers'
ld: kernel/blk_drv/blk_drv.a(floppy.o): in function `seek_interrupt':
vi fs/buffer.c
void inline invalidate_buffers(int dev)
To:
static void inline invalidate_buffers(int dev)
====
====
kernel/blk_drv/blk.h:111: multiple definition of `unlock_buffer';
vi kernel/blk_drv/blk.h
extern inline void unlock_buffer(struct buffer_head * bh)
extern inline void end_request(int uptodate)
To:
static inline void unlock_buffer(struct buffer_head * bh)
static inline void end_request(int uptodate)
====
====
kernel/blk_drv/floppy.c:302: undefined reference to `setup_rw_floppy'
vi kernel/blk_drv/floppy.c
inline void setup_rw_floppy(void)
To:
static inline void setup_rw_floppy(void)
====
====
ld: traps.o: in function `oom':
traps.c:(.text+0x4f7): multiple definition of `oom'; sched.o:sched.c:(.text+0x131): first defined here
函数重定义错误,全局搜索对应错误函数,extern 改为 static
grep -r "oom(" ./
./mm/swap.c: oom();
./mm/memory.c: oom();
./mm/memory.c: oom();
./mm/memory.c: oom();
./mm/memory.c: oom();
./mm/memory.c: oom();
./include/linux/mm.h:extern inline volatile void oom(void)
vi ./include/linux/mm.h
extern inline volatile void oom(void)
To:
static inline volatile void oom(void)
grep -r "memset(" ./
...所有的异常函数均按照此方法修改...
====
====
exec.c: In function 'copy_strings':
exec.c:162:44: error: lvalue required as left operand of assignment
162 | !(pag = (char *) page[p/PAGE_SIZE] =
| ^
应该是gcc版本兼容性问题
vi fs/exec.c
161 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
162 !(pag = (char *) page[p/PAGE_SIZE] =
163 (unsigned long *) get_free_page()))
164 return 0;
To:
161 if (!(pag = (char *) page[p/PAGE_SIZE]) &&
162 !(pag = (char *) (page[p/PAGE_SIZE] = get_free_page()))) {
163 return 0;
164 }
====
====
gar rcs blk_drv.a ll_rw_blk.o floppy.o hd.o ramdisk.o
make[1]: gar: Command not found
修改所有的AR = gar为 AR = ar
grep gar -r ./
./fs/Makefile:#AR =gar
./lib/Makefile:AR =gar
./kernel/blk_drv/Makefile:AR =gar
./kernel/Makefile:AR =gar
./kernel/chr_drv/Makefile:AR =gar
./kernel/math/Makefile:AR =gar
vi ./fs/Makefile
AR =ar
...其他路径下的Makefile...
====
====
get_put.c:129:1: error: unsupported size for integer register
129 | }
| ^
vi kernel/math/get_put.c
97 #define MUL10(low,high) \
98 __asm__("addl %0,%0 ; adcl %1,%1\n\t" \
99 "movl %0,%%ecx ; movl %1,%%ebx\n\t" \
100 "addl %0,%0 ; adcl %1,%1\n\t" \
101 "addl %0,%0 ; adcl %1,%1\n\t" \
102 "addl %%ecx,%0 ; adcl %%ebx,%1" \
103 :"=a" (low),"=d" (high) \
104 :"0" (low),"1" (high):"cx","bx")
To:
#define MUL10(low,high) \
__asm__("addl %0,%0 ; adcl %1,%1\n\t" \
"movl %0,%%ecx ; movl %1,%%ebx\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %0,%0 ; adcl %1,%1\n\t" \
"addl %%ecx,%0 ; adcl %%ebx,%1" \
:"=a" (low),"=d" (high) \
:"0" (low),"1" (high))
====
====
super.c:271: error: can't find a register in class `AREG' while reloading `asm'
super.c:277: error: can't find a register in class `AREG' while reloading `asm'
原因 :as的不断改进,不需要人工指定一个变量需要的CPU寄存器。
解决 :代码中所有的 __asm__("ax")都需要去掉。此外,所有类似 :"si","di","ax","cx"); 改为 );
vi fs/super.c
21 /* set_bit uses setb, as gas doesn't recognize setc */
22 #define set_bit(bitnr,addr) ({ \
23 register int __res __asm__("ax"); \
24 __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
25 __res; })
To:
#define set_bit(bitnr, addr) ({ \
register int __res; \
__asm__("bt %2, %3; setb %%al" \
:"=a" (__res) \
:"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })
vi fs/bitmap.c
20 #define set_bit(nr,addr) ({\
21 register int res __asm__("ax"); \
22 __asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \
23 "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
24 res;})
25
26 #define clear_bit(nr,addr) ({\
27 register int res __asm__("ax"); \
28 __asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \
29 "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
30 res;})
To:
#define set_bit(nr, addr) ({ \
register int res; \
__asm__ __volatile__("btsl %2, %3\n\tsetb %%al" \
:"=a" (res) \
:"0" (0),"r" (nr),"m" (*(addr))); \
res;})
#define clear_bit(nr, addr) ({ \
register int res; \
__asm__ __volatile__("btrl %2, %3\n\tsetnb %%al" \
:"=a" (res) \
:"0" (0), "r" (nr), "m" (*(addr))); \
res;})
====
====
ld: warning: cannot find entry symbol _start; defaulting to 0000000008049000
ld: boot/head.o: in function `startup_32':
(.text+0x10): undefined reference to `_stack_start'
原因 :ld在将所有目标文件链接起来时,不知道程序的入口点在哪里。
解决 :给head.s的 .text 段添加一句 .globl startup_32,然后给 Makefile 中的ld加上选项 -e startup_32 以指定入口点, 添加 -Ttext 0 选项使startup_32标号对应的地址为0x0。
vi boot/head.s
17 startup_32:
To:
.globl startup_32
startup_32:
vi Makefile
# -s(去除): 输出文件中省略所有的符号信息
# -x: 删除所有局部符号
# -M: 用于输出符号表
# -e startup_32(新增): 指定入口
# -Ttext 0(新增): 使`startup_32`标号对应的地址为`0x0`
LDFLAGS = -M -x -Ttext 0 -e startup_32
vi boot/head.s
替换 _stack_start 为 stack_start
vi boot/head.s
141 pushl $_main
To:
141 pushl $main
vi boot/head.s
163 call _printk
To:
163 call printk
vi kernel/sys_call.s
替换 _current 为 current
====
====
ld: init/main.o: in function `init':
main.c:(.text+0x50b): undefined reference to `puts'
由于GCC会对printf进行优化,把无参的printf优化成puts,而linux0.12的libc中又没有实现puts才会导致新的问题。
在所有的 Makefile 中 CFLAGS 项增加 -fno-builtin
# -fno-builtin(新增): 阻止gcc会把没有参数的printf优化成puts
====
====
ld: kernel/kernel.o: in function `schedule':
(.text+0x3bc): undefined reference to `_current'
ld: (.text+0x3c9): undefined reference to `_current'
grep "_current" -r ./
./include/linux/sched.h:__asm__("cmpl %%ecx,_current\n\t" \
./include/linux/sched.h: "xchgl %%ecx,_current\n\t" \
vi include/linux/sched.h
222 #define switch_to(n) {\
223 struct {long a,b;} __tmp; \
224 __asm__("cmpl %%ecx,_current\n\t" \
225 "je 1f\n\t" \
226 "movw %%dx,%1\n\t" \
227 "xchgl %%ecx,_current\n\t" \
228 "ljmp %0\n\t" \
229 "cmpl %%ecx,_last_task_used_math\n\t" \
230 "jne 1f\n\t" \
231 "clts\n" \
232 "1:" \
233 ::"m" (*&__tmp.a),"m" (*&__tmp.b), \
234 "d" (_TSS(n)),"c" ((long) task[n])); \
235 }
To:
#define switch_to(n) { \
struct {long a,b;} __tmp; \
__asm__("cmpl %%ecx,current\n\t" \
"je 1f\n\t" \
"movw %%dx,%1\n\t" \
"xchgl %%ecx,current\n\t" \
"ljmp *%0\n\t" \
"cmpl %%ecx,last_task_used_math\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n)),"c" ((long) task[n])); \
}
====
====
../include/string.h: In function `strtok':
../include/string.h:288: error: can't find a register in class `SIREG' while reloading `asm'
vi include/string.h
285 static inline char * strtok(char * s,const char * ct)
286 {
287 register char * __res __asm__("si");
288 __asm__("testl %1,%1\n\t"
289 "jne 1f\n\t"
290 "testl %0,%0\n\t"
291 "je 8f\n\t"
292 "movl %0,%1\n"
293 "1:\txorl %0,%0\n\t"
294 "movl $-1,%%ecx\n\t"
295 "xorl %%eax,%%eax\n\t"
296 "cld\n\t"
297 "movl %4,%%edi\n\t"
298 "repne\n\t"
299 "scasb\n\t"
300 "notl %%ecx\n\t"
301 "decl %%ecx\n\t"
302 "je 7f\n\t" /* empty delimeter-string */
303 "movl %%ecx,%%edx\n"
304 "2:\tlodsb\n\t"
305 "testb %%al,%%al\n\t"
306 "je 7f\n\t"
307 "movl %4,%%edi\n\t"
308 "movl %%edx,%%ecx\n\t"
309 "repne\n\t"
310 "scasb\n\t"
311 "je 2b\n\t"
312 "decl %1\n\t"
313 "cmpb $0,(%1)\n\t"
314 "je 7f\n\t"
315 "movl %1,%0\n"
316 "3:\tlodsb\n\t"
317 "testb %%al,%%al\n\t"
318 "je 5f\n\t"
319 "movl %4,%%edi\n\t"
320 "movl %%edx,%%ecx\n\t"
321 "repne\n\t"
322 "scasb\n\t"
323 "jne 3b\n\t"
324 "decl %1\n\t"
325 "cmpb $0,(%1)\n\t"
326 "je 5f\n\t"
327 "movb $0,(%1)\n\t"
328 "incl %1\n\t"
329 "jmp 6f\n"
330 "5:\txorl %1,%1\n"
331 "6:\tcmpb $0,(%0)\n\t"
332 "jne 7f\n\t"
333 "xorl %0,%0\n"
334 "7:\ttestl %0,%0\n\t"
335 "jne 8f\n\t"
336 "movl %0,%1\n"
337 "8:"
338 :"=b" (__res),"=S" (___strtok)
339 :"0" (___strtok),"1" (s),"g" (ct)
340 :"ax","cx","dx","di");
341 return __res;
}
To:
static inline char * strtok(char * s,const char * ct)
{
register char * __res;
__asm__("testl %1,%1\n\t"
"jne 1f\n\t"
"testl %0,%0\n\t"
"je 8f\n\t"
"movl %0,%1\n"
"1:\txorl %0,%0\n\t"
"movl $-1,%%ecx\n\t"
"xorl %%eax,%%eax\n\t"
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"je 7f\n\t" /* empty delimeter-string */
"movl %%ecx,%%edx\n"
"2:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 7f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 2b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 7f\n\t"
"movl %1,%0\n"
"3:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 5f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 3b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 5f\n\t"
"movb $0,(%1)\n\t"
"incl %1\n\t"
"jmp 6f\n"
"5:\txorl %1,%1\n"
"6:\tcmpb $0,(%0)\n\t"
"jne 7f\n\t"
"xorl %0,%0\n"
"7:\ttestl %0,%0\n\t"
"jne 8f\n\t"
"movl %0,%1\n"
"8:"
:"=b" (__res),"=S" (___strtok)
:"0" (___strtok),"1" (s),"g" (ct)
);
return __res;
}
====
====
ld: kernel/kernel.o: in function `sched_init':
(.text+0xf94): undefined reference to `gdt'
grep "gdt" -r ./
vi boot/head.s
修改以下变量名,去除前缀下划线,整个文件中的对应变量名要全部替换
注 : 现在的gcc能直接识别汇编中引用的C变量, 不需要再加下划线。
.globl _idt,_gdt,_pg_dir,_tmp_floppy_area
To:
.globl idt, gdt, pg_dir, tmp_floppy_area
====
====
ld: kernel/kernel.o: in function `sched_init':
(.text+0x105d): undefined reference to `timer_interrupt'
vi kernel/sys_call.s
修改
.globl _system_call,_sys_fork,_timer_interrupt,_sys_execve
.globl _hd_interrupt,_floppy_interrupt,_parallel_interrupt
.globl _device_not_available, _coprocessor_error
全部去除下划线,并修改整个文件对应变量名
vi kernel/asm.s
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_irq13,_reserved
.globl _alignment_check
全部去除下划线,并修改整个文件对应变量名
vi mm/page.s
修改
.globl _page_fault
去除下划线,并修改整个文件对应变量名
vi kernel/chr_drv/keyboard.S
修改
.globl _keyboard_interrupt
去除下划线,并修改整个文件对应变量名
====
====
ld: kernel/kernel.o: in function `reschedule':
sys_call.o:(.text+0x10b0): undefined reference to `_schedule'
grep "_schedule" -r ./
vi kernel/sys_call.s
jmp _schedule
To:
jmp schedule
其他的类似的下划线问题也按照此方法解决
====
====
fork.c:130: error: can't find a register in class `GENERAL_REGS' while reloading `asm'
fork.c:131: error: can't find a register in class `GENERAL_REGS' while reloading `asm'
原因 :as的不断改进,不需要人工指定一个变量需要的CPU寄存器。
解决 :代码中所有的 __asm__("ax")都需要去掉。此外,所有类似 :"si","di","ax","cx"); 改为 );
====
====
undefined reference to `memset'
undefined reference to `memcpy'
vi include/string.h
extern inline void * memset(void * s,char c,int count)
extern inline void * memcpy(void * dest,const void * src, int n)
注意不要把 extern 改为了 static
gcc 9需要改为static
====
====
malloc.c:156:46: error: lvalue required as left operand of assignment
156 | bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
| ^
vi lib/malloc.c
Line 156:
bdesc->page = bdesc->freeptr = (void *) cp = get_free_page();
To:
cp = get_free_page();
bdesc->page = bdesc->freeptr = (void *) cp;
====
====
get_put.c: In function 'put_BCD':
get_put.c:240:1: error: unsupported size for integer register
240 | }
| ^
上述错误需要关闭编译优化来解决,将文件所在的kernel/math/Makefile中的CFLAGS后的-O删除,然后重新编译。
gcc 3.4无此问题
====
====
/usr/bin/ld: /tmp/cc1nZIvk.o: in function `main':
build.c:(.text+0xf2): undefined reference to `MAJOR'
/usr/bin/ld: build.c:(.text+0x110): undefined reference to `MINOR'
/usr/bin/ld: build.c:(.text+0x19d): undefined reference to `MAJOR'
/usr/bin/ld: build.c:(.text+0x1bb): undefined reference to `MINOR'
build.c中包含的是标准库的头文件 /usr/include/linux/fs.h ,但是这个头文件里并没有实现MAJOR和MINOR宏。解决方法很简单,从include/linux/fs.h中把这两个宏复制到build.c中即可.
vi tools/build.c
Line 33 add:
#ifndef MAJOR
#define MAJOR(a) (((unsigned)(a))>>8)
#endif
#ifndef MINOR
#define MINOR(a) ((a)&0xff)
#endif
====
====
/dev/hd6: No such file or directory
这是因为在源代码顶层目录的Makefile中所指定的根设备为/dev/hd6(代表第二个硬盘的第一个分区), 而本机上并不存在这个设备所致。Linus当年之所以指定根设备为/dev/hd6, 是因为他把Linux 0.11安装在了机子的第二块硬盘上。我们这里打算通过在bochs中模拟软盘来启动编译好的系统,故在顶层目录Makefile中设定根设备为软盘:
vi Makefile
ROOT_DEV=FLOPPY
SWAP_DEV=
====
====
Non-GCC header of 'system'
vi tools/build.c
195 if (((long *) buf)[5] != 0)
196 die("Non-GCC header of 'system'");
To:
195 //if (((long *) buf)[5] != 0)
196 // die("Non-GCC header of 'system'");
====
====
System is 485552 bytes.
System is too big
make: *** [Makefile:43: Image] Error 1
vi tools/build.c
202 if (i > SYS_SIZE*16)
203 die("System is too big");
To:
202 //if (i > SYS_SIZE*16)
203 // die("System is too big");
====
====
-o tools/build tools/build.c
/usr/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-linux-gnu/7/libgcc.a when searching for -lgcc
/usr/bin/ld: cannot find -lgcc
apt-get install gcc-7-multilib
====
gcc 3.4:
Root device is (3, 1)
Swap device is (3, 4)
Boot sector 512 bytes.
Setup is 1372 bytes.
System is 153249 bytes.
编译成功
gcc 9.4:
Root device is (3, 1)
Swap device is (3, 4)
Boot sector 512 bytes.
Setup is 1372 bytes.
System is 202465 bytes.
编译成功,无法正常运行,待排查
====
内核代码bug修复
buffer.c
insert_into_queues()函数中,插入到hash表时
bh->b_next->b_prev = bh;
改为:
if (bh->b_next) /* bug修复!第一次hash()会返回NULL,需要判断一下 */
{
bh->b_next->b_prev = bh;
}
breada()函数中,处理预读取块时
ll_rw_block(READA,bh);
改为:
ll_rw_block(READA, tmp); /* bug修复! 这里的 bh 改为 tmp */
ctype.h
#define isascii(c) (((unsigned) (c))<=0x7f)
#define toascii(c) (((unsigned) (c))&0x7f)
这里需要对c用括号包起来,用来应对参数c为a+b的情况。如果不加括号,展开则变成了 (unsigned)a+b 而不是 (unsigned)(a+b)。
改为:
#define isascii(c) (((unsigned) (c))<=0x7f) // 是ASCII字符
#define toascii(c) (((unsigned) (c))&0x7f) // 转换成ASCII字符
====
====
VSCode调试时崩溃在page_fault
执行:
-exec handle SIGSEGV nostop noprint ignore
====
====
apt-get install qemu
apt-get install qemu-system-i386
或者编译
apt-get install ninja-build libsdl2-dev
wget https://download.qemu.org/qemu-7.1.0.tar.xz
tar xvJf qemu-7.1.0.tar.xz
cd qemu-7.1.0
./configure --enable-sdl
make -j8
make isntall
qemu-system-x86_64 -m 16 -boot a -fda Image -hda hdc.img -s -S
-s: 开启gdb 1234端口
-S: 开始执行就挂住
gdb tools/system
directory ./
set architecture i386:x86-64
set disassembly-flavor intel
target remote 192.168.31.221:1234
b *0x7c00
layout split
c
#target remote localhost:1234
#set architecture i8086
#b main
====