Gil L5 2020-09-18 12:34:06 Coding!
987 0

“操作系统实验:基于 uCore OS”实验报告

Coding!

1: 了解汇编

Try below command

$cd related_info/lab0
$gcc -S -m32 lab0_ex1.c
copy

Then you will get lab_ex1.S. Try to understand the content & relation of C file and S file.

shiyanlou:~/ $ cd ucore_lab/related_info/lab0                         [2:27:44]
shiyanlou:lab0/ (master) $ gcc -S -m32 lab0_ex1.c                     [2:28:01]
shiyanlou:lab0/ (master*) $ ls                                        [2:28:26]
defs.h      lab0_ex1.md  lab0_ex2.c   lab0_ex3.c   lab0_ex4.c   list.h
lab0_ex1.c  lab0_ex1.s   lab0_ex2.md  lab0_ex3.md  lab0_ex4.md
shiyanlou:lab0/ (master*) $ cat lab0_ex1.s                            [2:28:35]
    .file    "lab0_ex1.c"
    .globl    count
    .data
    .align 4
    .type    count, @object
    .size    count, 4
count:
    .long    1
    .globl    value
    .align 4
    .type    value, @object
    .size    value, 4
value:
    .long    1
    .comm    buf,40,32
    .text
    .globl    main
    .type    main, @function
main:
.LFB0:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl    %edi
    pushl    %ebx
    .cfi_offset 7, -12
    .cfi_offset 3, -16
    movl    count, %edx
    movl    value, %eax
    movl    buf, %ebx
    movl    %edx, %ecx
    movl    %ebx, %edi
#APP
# 6 "lab0_ex1.c" 1
    cld 
    rep 
    stosl
# 0 "" 2
#NO_APP
    popl    %ebx
    .cfi_restore 3
    popl    %edi
    .cfi_restore 7
    popl    %ebp
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size    main, .-main
    .ident    "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits
copy
b ebx
c ecx
d edx
S esi
D edi
I 常数值,(0 - 31)
q,r 动态分配的寄存器
g eax,ebx,ecx,edx或内存变量
A 把eaxedx合成一个64位的寄存器(use long longs)
copy

2: 用gdb调试

Try below command

$cd related_info/lab0
$gcc -g -m32 lab0_ex2.c
copy

Then you will get a.out. Try to use gdb to debug lab0_ex2.

cd related_info/lab0
gcc -g -m32 lab0_ex2.c
# 编译完成之后
# 进入gdb
gdb
# 载入a.out文件
(gdb) file a.out
# 设置断点
(gdb) b main
# 运行
(gdb) r
# 输出当前行

# 继续执行
(gdb) c
# 输出hello,world!

# 退出
(gdb) q
copy
表 gdb 的常用命令

break FILENAME:NUM    在特定源文件特定行上设置断点
clear FILENAME:NUM    删除设置在特定源文件特定行上的断点
run    运行调试程序
step    单步执行调试程序,不会直接执行函数
next    单步执行调试程序,会直接执行函数
backtrace    显示所有的调用栈帧。该命令可用来显示函数的调用顺序
where continue    继续执行正在调试的程序
display EXPR    每次程序停止后显示表达式的值,表达式由程序定义的变量组成
file FILENAME    装载指定的可执行文件进行调试
help CMDNAME    显示指定调试命令的帮助信息
info break    显示当前断点列表,包括到达断点处的次数等
info files    显示被调试文件的详细信息
info func    显示被调试程序的所有函数名称
info prog    显示被调试程序的执行状态
info local    显示被调试程序当前函数中的局部变量信息
info var    显示被调试程序的所有全局和静态变量名称
kill    终止正在被调试的程序
list    显示被调试程序的源代码
quit    退出 gdb
copy

3.掌握指针和类型转换相关的C编程

#include <stdio.h>

#define STS_IG32        0xE            // 32-bit Interrupt Gate
#define STS_TG32        0xF            // 32-bit Trap Gate

typedef unsigned uint32_t;

#define SETGATE(gate, istrap, sel, off, dpl) {            \
    (gate).gd_off_15_0 = (uint32_t)(off) & 0xffff;        \
    (gate).gd_ss = (sel);                                \
    (gate).gd_args = 0;                                    \
    (gate).gd_rsv1 = 0;                                    \
    (gate).gd_type = (istrap) ? STS_TG32 : STS_IG32;    \
    (gate).gd_s = 0;                                    \
    (gate).gd_dpl = (dpl);                                \
    (gate).gd_p = 1;                                    \
    (gate).gd_off_31_16 = (uint32_t)(off) >> 16;        \
}

 /* Gate descriptors for interrupts and traps */
 struct gatedesc {
    unsigned gd_off_15_0 : 16;        // low 16 bits of offset in segment
    unsigned gd_ss : 16;            // segment selector
    unsigned gd_args : 5;            // # args, 0 for interrupt/trap gates
    unsigned gd_rsv1 : 3;            // reserved(should be zero I guess)
    unsigned gd_type : 4;            // type(STS_{TG,IG32,TG32})
    unsigned gd_s : 1;                // must be 0 (system)
    unsigned gd_dpl : 2;            // descriptor(meaning new) privilege level
    unsigned gd_p : 1;                // Present
    unsigned gd_off_31_16 : 16;        // high bits of offset in segment
 };

int
main(void)
{
    unsigned before;
    unsigned intr;
    unsigned after;
    struct gatedesc gintr;

    intr=8;
    before=after=0;

    gintr=*((struct gatedesc *)&intr);
    SETGATE(gintr, 0,1,2,3);
    intr=*(unsigned *)&(gintr);
    printf("intr is 0x%x\n",intr);
    printf("gintr is 0x%llx\n",gintr);

    return 0;
}
copy

结构体gatedesc的定义很规范,成员变量的大小精确到了比特。printf内的参数%llx功能是输出有符号64位16进制整数。

宏定义SETGATE用于设置结构体gatedesc的值。

编译

gcc -g -m32 lab0_ex3.c 2>&1 | tee make.log

代码中的 “2>&1”要拆开来看,对于& 1 更准确的说应该是文件描述符 1,而1标识标准输出,stdout。对于2 ,表示标准错误,stderr。所以2>&1 的意思就是将标准错误重定向到标准输出。tee命令用于读取标准输入的数据,并将其内容输出成文件,将错误日志保存到make.log方便后期查看

输出结果

intr is 0x10002
gd_off_15_0 is ox2
gintr is 0xee0000010002
copy

4: 掌握通用链表结构相关的C编程

用在related_info/lab0/list.h中定义的结构和函数来实现一个小应用程序完成一个基于此链表的数据对象的访问操作。 可参考related_info/lab0/lab0_ex4.c

gcc -g -m32 -I. lab0_ex4.c 2>&1|tee make.log

不加参数-I.会报错defs.h: No such file or directory

通用链接结构的意义在于将对链表数据的操作与对链表指针的操作分开,定义单独的结构体处理链表指针的增、删、插操作,屏蔽了链表数据的类型。

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

struct entry {

    list_entry_t node;
    int num;
};

int main() {
    struct entry head;
    list_entry_t* p = &head.node;
    list_init(p);
    head.num = 0;
    int i;
    for (i = 1; i != 10; i ++) {
        struct entry * e = (struct entry *)malloc(sizeof(struct entry));
        e->num = i;
        list_add(p, &(e->node));
        p = list_next(p);
    }
    //reverse list all node
    while ((p = list_prev(p)) != &head.node)
        printf("%d\n", ((struct entry *)p)->num);
    return 0;
}
copy
#ifndef __LIBS_LIST_H__
#define __LIBS_LIST_H__

#ifndef __ASSEMBLER__

#include <defs.h>

/* *
 * Simple doubly linked list implementation.
 *
 * Some of the internal functions ("__xxx") are useful when manipulating
 * whole lists rather than single entries, as sometimes we already know
 * the next/prev entries and we can generate better code by using them
 * directly rather than using the generic single-entry routines.
 * */

struct list_entry {
    struct list_entry *prev, *next;
};

typedef struct list_entry list_entry_t;

static inline void list_init(list_entry_t *elm) __attribute__((always_inline));
static inline void list_add(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
static inline void list_add_before(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
static inline void list_add_after(list_entry_t *listelm, list_entry_t *elm) __attribute__((always_inline));
static inline void list_del(list_entry_t *listelm) __attribute__((always_inline));
static inline void list_del_init(list_entry_t *listelm) __attribute__((always_inline));
static inline bool list_empty(list_entry_t *list) __attribute__((always_inline));
static inline list_entry_t *list_next(list_entry_t *listelm) __attribute__((always_inline));
static inline list_entry_t *list_prev(list_entry_t *listelm) __attribute__((always_inline));

static inline void __list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));
static inline void __list_del(list_entry_t *prev, list_entry_t *next) __attribute__((always_inline));

/* *
 * list_init - initialize a new entry
 * @elm:        new entry to be initialized
 * */
static inline void
list_init(list_entry_t *elm) {
    elm->prev = elm->next = elm;
}

/* *
 * list_add - add a new entry
 * @listelm:    list head to add after
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *after* the element @listelm which
 * is already in the list.
 * */
static inline void
list_add(list_entry_t *listelm, list_entry_t *elm) {
    list_add_after(listelm, elm);
}

/* *
 * list_add_before - add a new entry
 * @listelm:    list head to add before
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *before* the element @listelm which
 * is already in the list.
 * */
static inline void
list_add_before(list_entry_t *listelm, list_entry_t *elm) {
    __list_add(elm, listelm->prev, listelm);
}

/* *
 * list_add_after - add a new entry
 * @listelm:    list head to add after
 * @elm:        new entry to be added
 *
 * Insert the new element @elm *after* the element @listelm which
 * is already in the list.
 * */
static inline void
list_add_after(list_entry_t *listelm, list_entry_t *elm) {
    __list_add(elm, listelm, listelm->next);
}

/* *
 * list_del - deletes entry from list
 * @listelm:    the element to delete from the list
 *
 * Note: list_empty() on @listelm does not return true after this, the entry is
 * in an undefined state.
 * */
static inline void
list_del(list_entry_t *listelm) {
    __list_del(listelm->prev, listelm->next);
}

/* *
 * list_del_init - deletes entry from list and reinitialize it.
 * @listelm:    the element to delete from the list.
 *
 * Note: list_empty() on @listelm returns true after this.
 * */
static inline void
list_del_init(list_entry_t *listelm) {
    list_del(listelm);
    list_init(listelm);
}

/* *
 * list_empty - tests whether a list is empty
 * @list:       the list to test.
 * */
static inline bool
list_empty(list_entry_t *list) {
    return list->next == list;
}

/* *
 * list_next - get the next entry
 * @listelm:    the list head
 **/
static inline list_entry_t *
list_next(list_entry_t *listelm) {
    return listelm->next;
}

/* *
 * list_prev - get the previous entry
 * @listelm:    the list head
 **/
static inline list_entry_t *
list_prev(list_entry_t *listelm) {
    return listelm->prev;
}

/* *
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 * */
static inline void
__list_add(list_entry_t *elm, list_entry_t *prev, list_entry_t *next) {
    prev->next = next->prev = elm;
    elm->next = next;
    elm->prev = prev;
}

/* *
 * Delete a list entry by making the prev/next entries point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 * */
static inline void
__list_del(list_entry_t *prev, list_entry_t *next) {
    prev->next = next;
    next->prev = prev;
}

#endif /* !__ASSEMBLER__ */

#endif /* !__LIBS_LIST_H__ */
copy
最新评论
暂无评论~