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 把eax和edx合成一个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
学习时间 125分钟
操作时间 15分钟
按键次数 333次
实验次数 4次
报告字数 10090字
是否完成 完成