Browsed by
Category: gcc

[科普向?] Re: 从零开始的操作系统开发 第一集

[科普向?] Re: 从零开始的操作系统开发 第一集

Hmm, 果然还是开坑了~! 在学校智障的操作系统课设的发起下, 再加上每个程序员都有一个写一个自己的操作系统的公主梦(雾), 我们愉(作)快(死)地开坑啦~ 以前曾经跟着 “30天自制操作系统” 玩过DIY操作系统, 不过那个书更像面向小白, 讲的东西也不够系统, 而且使用的是自己改过的nas汇编器, 因而不能算写过, 这一次则是真正的开坑啦~ (虽然课设时间很短写出一个完整的根本不可能不过慢慢写总会写完的你说对不喵~) 我们的开发过程在Bearychat上直播 neugeek.bearychat.com 的Toy-OS频道, 我们的git-repo 为 https://github.com/VOID001/toy-os 菊苣们不要喷, 既然挖了坑窝就不会不填(….你都已经挖了多少个坑了啊喂! (逃)) 这个系列的文章将会记录在开发操作系统的整个过程中的一些经验&心得&吐槽 不知道会有多少集(   参考资料们: MIT 的 XV6 源代码 & handbook University of Birmingham 的 Writing an simple operating system from scratch Quora, StackOverflow Jiong Zhao Linux 0.11内核完全注释   我们使用的工具链: GNU Assembler & GNU C Compiler Qemu Gdb objcopy, objdump, binutils, elfutils GNU Makefile   操作系统编写总览 什么是BIOS 参考阅读: http://whatis.techtarget.com/definition/BIOS-basic-input-output-system 我们的定位是写一个操作系统,那么首先我们应该了解,整个操作系统都应该由哪些模块构成, 那么就让我们从操作系统的启动说起, 说到这里就不得不说一下BIOS, BIOS是Basic Input and Output System, 是你的计算机加电运行后加载的第一个程序, 它是固化在你的EPROM内的一个程序片段…

Read More Read More

[C Linux内核] 文件与I/O

[C Linux内核] 文件与I/O

系统调用 Hello world 先看一个例子,利用系统调用sys_write用汇编实现的向stdout输出hello world .data msg: .ascii “Hello, world!\n” len = . – msg .text .global _start _start: movl $len, %edx # third argument: message length movl $msg, %ecx # second argument: pointer to message to write movl $1, %ebx # frist argument: file handle(here stdout) movl $4, %eax int $0x80 movl $0, %ebx movl $1, %eax int $0x80 将_start作为 ELF linker or loader的 外部可以使用的符号(通过 .global) 并且在.data段内定义一个标号msg,代表字符串Hello world 的首地址,  定义len的时候用到的 . 是一个用来代替当前段内地址(在每一个段开头, “.” 的值都会初始化回0)因而, len的值就是当前地址减去msg的首地址, 换句话说,就是 字符串常量”Hello world\n”长度, 上面的代码进行了两次系统调用,…

Read More Read More

C语言可变参数函数实现 & 分析

C语言可变参数函数实现 & 分析

先给出一个样例程序, 实现一个打印每一个传给它的元素并且换行 /************************************************************************* > File Name: va_args_1.c > Author: VOID_133 > ################### > Mail: ################### > Created Time: Sun 17 Apr 2016 09:34:22 PM CST ************************************************************************/ #include<stdio.h> #include<stdarg.h> void print_list(char *begin, …) { va_list ap; char *p = NULL; va_start(ap, begin); p = va_arg(ap, char *); while(p != NULL) { fputs(p, stdout); putchar(‘\n’); p = va_arg(ap, char *); } va_end(ap); } int main(void) { print_list(0, “This”, “is”, “Multi”, “Line”, NULL); return 0; } 上面的代码已经很清晰了, 下面简单说明一下如何编写一个可变参数函数 1.定义函数, 注意参数列表的第一个参数一定要有,就算没有用到也不能为空, 而且必须有名字, 这个是提供给va_start作为参数的 void…

Read More Read More

ELF 文件格式初步探索

ELF 文件格式初步探索

在Linux下编译一个汇编程序需要的工具为 as(汇编器) ld(链接器) e.g: 一个非常简单的AT&T汇编程序 .section .data .section .text .globl _start _start: movl $1, %eax movl $4, %ebx int $0x80 .section .globl 这种叫做 伪操作, .section将代码分为若干段 _start 是 symbol(符号)  符号在汇编程序中代表一个地址 .globl 表示一个符号会被链接器使用 as –32 将 汇编代码编译为 relocatable object file elf32_i386   解读ELF 文件格式 对于汇编 , 链接器来看 , elf文件是由 Section Header Table 描述的一系列Section 集合, 而执行一个ELF文件的时候, 在loader看来 它是由 Programer Header Table 描述的一系列Segment的集合 对于程序运行的时候 Program Header Table 是必须 程序链接的时候 Section Header Table 是必须的 对于一个在运行的时候动态链接的程序, Program Header Table 和 Section Header Table 都是需要的, 因为程序既要加载 也要动态链接…

Read More Read More

Calling Conventions 调用惯例

Calling Conventions 调用惯例

摘自维基, 暂时先搬运, 以后会加入自己的理解(又挖坑了 QWQ) 调用惯例涉及以下几点: 1. 函数参数的空间分配顺序 2. 这些参数存储在什么地方(是全部放在栈上,还是部分放在栈上,部分放在寄存器里,还是全部放在寄存器里) 3.被调用的函数需要保留哪些寄存器给调用他的函数 4.调用函数的时候, 保护现场, 恢复现场的顺序.  __cdecl: 1> 参数按从右到左的顺序传递,放于栈中 2> 栈的清空由主调函数完成  __stdcall:     1> 参数按从右到左的顺序传递,放于栈中 2> 栈的清空由被调函数完成  __fastcall: 1> 前两个参数要求不超过32bits,分别放入ECX和EDX,其余参数按从右到左的顺序传递,放于栈中 2> 参数由被调函数弹出栈 Thiscall,仅用于C++中类的成员函数: 1> 参数按从右到左的顺序传递,放于栈中。this放于ECX中 2> 栈的清空有被调函数完成 下面通过对cdecl 和 stdcall Calling convention 的区别的研究, 学习calling convention的相关知识 cdecl 是 C语言默认的调用惯例 , 也就是说, 如果你什么不加, default为cdecl ,这个调用惯例 , 要求caller清理堆栈, callee不用清理堆栈 , 用cdecl可以实现可变参数的函数, 另一种方式 stdcall, 是由 callee清理堆栈 , caller不负责堆栈的清理 ,下面是两个不同的调用的C代码及汇编   (注意, 在gcc中 想指定Calling Convention 需要用这样的形式 , 以 stdcall为例: __attribute__((__stdcall__)) , 另外注意, 想要看到Calling Convention的效果要将代码编译为 32位的程序而不是64位 , 提供一个编译指令 gcc -m32 -g…

Read More Read More