终于编译OK了。。可链接就是一大堆错误

问题1:

boot/head.o: In function `startup_32':
(.text+0x10): undefined reference to `_stack_start'
boot/head.o: In function `startup_32':
(.text+0x2e): undefined reference to `_stack_start'
boot/head.o: In function `after_page_tables':
(.text+0x540c): undefined reference to `_main'
boot/head.o: In function `ignore_int':
(.text+0x5440): undefined reference to `_printk'

一堆的undefined reference to xxxxx,stack_start 定义在kernel/sched.c中,main 定义在init/main.c中,实际上这些符号是存在的,可为什么链接的时候找不到呢。最终找到原因,是由于现在GCC在编译C时不会在函数前加"_"了,即以前GCC编译一个C函数,例如:fun() 编译后会变成_fun(), 而现在还是fun(),所以就导致了符号找不到,这个叫name magling,有兴趣的可以自行google下。

解决的思路有两种:

1. 网上的是把把有引用C符号的.s 和 .S中的变量前的"_"全部删掉,这个用正则不太好弄,得一个个删。

2. 在查name magling的时候,有幸让我看到了-fleading-underscore这个option, 可以让让GCC在编译的时候强制加上"_",这种只需要在CFLAGS中加-fleading-underscore即可,第二种方法更省事。

方案2具体解决方法

msed -O -O\ -fleading-underscore

请记得在改完后,make clean,后再make。

问题2:

main.c:(.text+0x6c): undefined reference to `_printf'
main.c:(.text+0x87): undefined reference to `_printf'
main.c:(.text+0x142): undefined reference to `_puts'
main.c:(.text+0x1e9): undefined reference to `_printf'

额,之前编译的时候似乎正则没全部匹配到,只好手动改下了,把init/main.c 里的printf 全改成 printw

问题3:

vsprintf.c:(.text+0x18cb): undefined reference to `___stack_chk_fail'
fs/fs.o: In function `_do_execve':
(.text+0x3554): undefined reference to `___stack_chk_fail'
kernel/chr_drv/chr_drv.a(tty_ioctl.o): In function `_tty_ioctl':
tty_ioctl.c:(.text+0x51d): undefined reference to `___stack_chk_fail'

直接google到的答案,这是由于ubuntu的GCC默认是加-fstack-protector的,这里在CFLAGS中去掉这个option,加入-fno-stack-protector,至于这个option到底有什么作用,请有兴趣的自行google

msed -O -O\ -fno-stack-protector

问题4:

build.c:(.text+0x1c): undefined reference to `_stderr'
build.c:(.text+0x24): undefined reference to `___fprintf_chk'
/tmp/cctqTbXN.o: In function `_main':
build.c:(.text+0x7d): undefined reference to `_strcmp'
build.c:(.text+0x99): undefined reference to `___xstat'
build.c:(.text+0xab): undefined reference to `_perror'

这个问题是由问题1的解决方案引入的,build.c链接时用的是glibc,而glibc在是没-fleading-underscore这个option的,所以在编译build.c时我们 把这个option去掉。。。,目前没找到什么好方法,我只好手动把CFLAGS展开,然后去掉-fleading-underscore了

修改linux0.12根目录下的Makefile第50行

tools/build: tools/build.c
     $(CC) $(CFLAGS) \
     -o tools/build tools/build.c

上面是原来的,下面是展开后的

tools/build: tools/build.c
    $(CC) -w -O -fno-stack-protecto -m32 -fstrength-reduce -fomit-frame-pointer \
    -o tools/build tools/build.c

问题5:

build.c:(.text+0xcb): undefined reference to `MAJOR'
build.c:(.text+0xe3): undefined reference to `MINOR'
build.c:(.text+0x16c): undefined reference to `MAJOR'
build.c:(.text+0x184): undefined reference to `MINOR'

缺少两个宏定义,将以下两个定义加入到build.c中即可

#define MAJOR(x) (((unsigned)(x))>>8)
#define MINOR(x) ((x)&0xff)

问题6:

/dev/hd6: No such file or directory
Couldn't stat root device.

这个是在linux0.12根目录下的Makefile中定义的

ROOT_DEV=/dev/hd6
SWAP_DEV=/dev/hd2

但我们没这东西,阅读build.c 代码,了解到这里可以写成FLOPPY代替/dev/hd6

) {
        ], "FLOPPY")) {
            ], &sb)) {
                perror(argv[]);
                die("Couldn't stat root device.");
            }
            major_root = MAJOR(sb.st_rdev);
            minor_root = MINOR(sb.st_rdev);
        } else {
            major_root = ;
            minor_root = ;
        }
    } else {
        major_root = DEFAULT_MAJOR_ROOT;
        minor_root = DEFAULT_MINOR_ROOT;
    }

问题6:

/dev/hd2: No such file or directory
Couldn't stat root device.

与上个问题类似,相同的地方,阅读build.c,可以用NONE代替/dev/hd2

) {
        ], "NONE")) {
            ], &sb)) {
                perror(argv[]);
                die("Couldn't stat root device.");
            }
            major_swap = MAJOR(sb.st_rdev);
            minor_swap = MINOR(sb.st_rdev);
        } else {
            major_swap = ;
            minor_swap = ;
        }
    } else {
        major_swap = DEFAULT_MAJOR_SWAP;
        minor_swap = DEFAULT_MINOR_SWAP;
    }

问题7:

Non-GCC header of 'system'

我们先看代码

],O_RDONLY,))<)
    die("Unable to open 'system'");
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
    die("Unable to read header of 'system'");
] != )
    die("Non-GCC header of 'system'");
 ; (c=read(id,buf, ; i+=c )
     ,buf,c)!=c)
         die("Write call failed");
    

大致分4步,1. 打开第4个参数的文件,即system,2. 读system的头1024个字节;3. 判断程序入口地址是不是0x0;4. 读取剩下的部分写入Image中。错在第三步。我们用readelf -h system来看下

~/workspace/blog/linux-0.12/tools$ readelf -h system
ELF Header:
  Magic:   7f  4c
  Class:                             ELF32
  Data:                              's complement, little endian
  Version:                            (current)
  OS/ABI:                            UNIX - System V
  ABI Version:
  Type:                              EXEC (Executable file)
  Machine:                           Intel
  Version:                           0x1
  Entry point address:               0x80480a0
  Start of program headers:           (bytes into file)
  Start of section headers:           (bytes into file)
  Flags:                             0x0
  Size of  (bytes)
  Size of program headers:            (bytes)
  Number of program headers:
  Size of section headers:            (bytes)
  Number of section headers:
  Section header 

这里可以看到程序的入口是0x80480a0,不是0x0,所以要告诉链接器,把text段放到0x0上,在linux0.12根目录下面的Makefile,修改ld命令,在其后面加上-Ttext 0x0 -e startup_32, 同时在head.s 的.global中加入startup_32以便外部访问。除此而外,GCC头的第24个字节是version,第26个字节开始才是程序入口。。。额,索性直接把判断GCC头那段给干掉。。。

然后链接也OK了,生成了Image 进入调试阶段。。

linux0.12 链接过程的更多相关文章

  1. linux0.12 编译过程

    感谢这篇文章的作者:    http://www.cnblogs.com/strugglesometimes/p/4231359.html 编译是个很蛋疼的事情,本想把linux0.12在bochs上 ...

  2. linux0.12 学习总序(不断更新状态中)

    最近有空闲时间,想静下心来学点东西.一直对kernel有兴趣,又苦于无从下手,就拿linux0.12练手.尝试了解并熟悉kernel各模块工作原理. 接下来的博客主要用来记录自己所遇到的问题和解决的方 ...

  3. 第一次作业:基于Linux-0.12的进程分析

    这次作业主要基于Linux-0.12的源代码,分析Linux是如何组织进程,进程的状态之间是如何转换,以及进程是如何调度的. 一. 进程的概念: 1.进程就是:程序在数据集合上的一次运行过程,是系统进 ...

  4. GCC编译链接过程

    编译链接过程 代码 #cat main.c #include <stdio.h> int add(int x, int y); int sub(int x, int y); int mul ...

  5. 鸿蒙内核源码分析(静态链接篇) | 完整小项目看透静态链接过程 | 百篇博客分析OpenHarmony源码 | v54.01

    百篇博客系列篇.本篇为: v54.xx 鸿蒙内核源码分析(静态链接篇) | 完整小项目看透静态链接过程 | 51.c.h.o 下图是一个可执行文件编译,链接的过程. 本篇将通过一个完整的小工程来阐述E ...

  6. 【图片+代码】:GCC 链接过程中的【重定位】过程分析

    作 者:道哥,10+年嵌入式开发老兵,专注于:C/C++.嵌入式.Linux. 关注下方公众号,回复[书籍],获取 Linux.嵌入式领域经典书籍:回复[PDF],获取所有原创文章( PDF 格式). ...

  7. [转]C++编译链接过程详解

    C语言的编译链接过程要把我们编写的一个c程序(源代码)转换成可以在硬件上运行的程序(可执行代码),需要进行编译和链接.编译就是把文本形式源代码翻译为机器语言形式的目标文件的过程.链接是把目标文件.操作 ...

  8. mysql学习(2)-Navicat Premium 12 链接MySQL8.0.11数据库报2059错误

    Navicat Premium 12 链接MySQL8.0.11数据库报2059错误 1,问题现象 安装完MySQL8.0.11和Navicat Premium12后,我们会用Navicat去测试连接 ...

  9. C-从源文件到可执行文件的详细编译链接过程

    一直用windows一键搞定, 没有去了解详细的编译链接过程, 今天看了一篇文章, 顺便实验和记录在Linux下逐步生成的步骤. 预处理: 执行#include, #define, #if, #ifd ...

随机推荐

  1. Android使用GridView实现日历功能(详细代码)

    代码有点多,发个图先: 如果懒得往下看的,可以直接下载源码吧(0分的),最近一直有人要,由于时间太久了,懒得找出来整理,今天又看到有人要,正好没事就整理了一下 http://download.csdn ...

  2. 线段树---HDU1166敌兵布阵

    这个是线段树中最入门的题目,但是由于不了解线段树的概念,当然更不知道怎么样,所以觉得挺费劲,整了一会发现还是基本的思想,就是还是将一个线段继续分割,一直分割到不能分割,这道题目是知道多少个军营,也就是 ...

  3. C#_DBHelper_SQL数据库操作类.

    using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data; ...

  4. ASP.NET-FineUI开发实践-8

    上回模拟的是下拉grid,这回我把下拉grid和表格自动补全放一起了,实在是好做,但是也有很多要注意的,现在分享下,大家学习. 接上回 传送门  1. 有个tbxMyBox1_TriggerClick ...

  5. CI框架深入篇(2)一些基础的我之不知道的标准格式

    1,一些命名规则:类文件名必大写,其他配置文件,视图文件或着脚本都要小写,类文件名和类名要一致!! 2,类名要大写开头,若是多个单词,那就下划线不要驼封法: 3,变量名要小写全,多个单词下划线分割,后 ...

  6. 启用DHCP中继代理,实现跨子网服务 - Win 2003 Server

    伴随着局域网规模的逐步扩大,一个网络常常会被划分成多个不同的子网,以便根据不同子网的工作要求来实现个性化的管理要求.考虑到规模较大的局域网一般会使用DHCP服务器来为各个工作站分配IP地址,不过一旦局 ...

  7. expr的简单应用

    expr命令 是一个手工命令行计数器,用于在UNIX/LINUX下求表达式变量的值,一般用于整数值,也可用于字符串. –格式为: expr expression_r(命令读入Expression 参数 ...

  8. goldengate单向复制文档

    1:实验环境 2:实验步骤 --下面的2.1-2.2步骤,都需要在源端和目标端分别执行. 2.1:准备工作 2.1.1 建表空间 create tablespace ogg datafile '/u0 ...

  9. AFNetworking3.0出现Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable

    在发送请求后一直报错, 浏览器解析却没有问题, 所以基本可以确定是AFNetworking的问题 下面是解决方法: AFHTTPSessionManager *manager = [AFHTTPSes ...

  10. securecrt简介

    SecureCRT是最常用的终端仿真程序,简单的说就是Windows下登录UNIX或Liunx服务器主机的软件,本文主要介绍SecureCRT的使用方法和技巧 VanDyke CRT 和 VanDyk ...