Ubuntu 编译 linux kernel 0.12

下载源代码
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
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 30 --slave /usr/bin/g++ g++ /usr/bin/g++-8
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 40 --slave /usr/bin/g++ g++ /usr/bin/g++-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
====