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 & relationg of C file and S file.
输入命令
cd ~/ucore_lab/related_info/lab0
gcc -S -m32 lab0_ex1.c
copy
(注:题目所示未给出完整路径,应填补完整路径,根据提示缺省目录为/home/shiyanlou/ucore_lab )
同时注意到实验楼的源码位置是/home/shiyanlou/ucore_lab,但是在虚拟机里源码位置在/home/moocos/下。又已知/home/username/ 表示用户目录,实验楼平台上的默认用户目录是shiyanlou,虚拟机上的默认用户目录是moocos。 所以在虚拟机的输入命令为 cd ~/ucore_lab/related_info/lab0 再输入gcc -S -m32 lab0_ex1.c ,此时在文件系统中 ~/ucore_lab/related_info/lab0目录下得到lab0_ex1.s文件。
(注:注意命令的大小字母区分 gcc -s -m32 lab0_ex1.c 得到的是a.out文件)
gcc表示使用了GCC扩展内联汇编。
-S表示只激活预处理和编译,把文件编译为汇编代码。
-m32指生成32位机器的汇编代码。
lab0_ex1.c文件:
int count=1;
int value=1;
int buf[10];
void main()
{
asm(
"cld \n\t"
"rep \n\t"
"stosl"
:
: "c" (count), "a" (value) , "D" (buf[0])
:
);
}
copy
asm关键字用于调用内联汇编程序,可在C或C++语句合法出现。如果有多行汇编,则每一行都要加上“\n\t”。其中“\n”是换行符,“\t”是tab符,在每条指令的结束加这两个符号,是为了让gcc把内联汇编代码翻译成一般的汇编代码时能够保证换行和留有一定的空格。
cld:将标志寄存器flag的方向标志位df清零,在字符串操作中使变址寄存器si或di的地址指针自动增加,字符串处理由前往后。
rep:在cx不等于0的情况下,对字符串执行重复操作。
stosl:相当于将EAX中的值保存到ES:EDI指向的地址中。 冒号后的语句指明输入,输出和被改变的寄存器。其中"c"(count)表明把count的值放入cx寄存器中,"a"(value)表明把value的值放入EAX寄存器中,"D"(buf[0])表明把buf[0]的值放进edi寄存器中。
所以该代码段功能是向buf中写上count个value值。
lab0_ex1.s文件:
.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
.s文件是根据命令由.c文件按照32位机器汇编而成。
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.
输入命令
gcc -g -m32 lab0_ex2.c
copy
-g为编译选项,编译源文件,生成a.out.文件。
输入运行程序的命令
$ gcc -o lab0_ex2 -g lab0_ex2.c
$ ./lab0_ex2
copy
程序运行结果为显示“Hello ,world!”
输入命令加载lab0_ex2可执行文件,执行装入的lab_ex2
gdb lab0_ex2
run
copy
输入命令查看程序出错的地方
where
copy
错误为没有堆栈 no stack
输入命令查看调用gets函数附近的代码。
list
copy
输入命令第7行处设置断点并执行单步命令next
break 7
next
copy
发现程序无法运行
输入print命令查看int的值,发现问题在于试图使用类型名作为一个表达式。
print int
copy
对于如下的代码段
...
#define STS_CG32 0xC // 32-bit Call Gate
#define STS_IG32 0xE // 32-bit Interrupt Gate
#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
};
...
copy
如果在其他代码段中有如下语句,
unsigned intr;
intr=8;
SETGATE(intr, 0,1,2,3);
copy
请问执行上述指令后,intr的值是多少?
具体方法:Try below command
$cd related_info/lab0
gcc -g -m32 lab0_ex3.c 2>&1|tee make.log
copy
If you get gcc's error, try to read make.log and fix the bugs. If gcc successed, then you will get a.out. Try to answer below question.
输入命令
gcc -g -m32 lab0_ex3.c 2>&1|tee make.log
copy
2>&1是把错误输出和正常输出导到一起,然后通过tee写入log文件,同时在屏幕上继续输出
发现错误在第48行,
printf("gintr is 0x%llx\n",gintr);
copy
%llx表示long long unsigned int (注:文件存放的路径是/home/ucore_lab/related_info/lab0) 打开lab0_ex3.c,发现在第39行中,gintr的类型为struct gatedesc,很明显类型不一致。
struct gatedesc gintr;
copy
按照错误提示,把输出语句删除。
输入命令重新编译(在虚拟机里的文件似乎不太对,我直接在实验楼的在线环境尝试了)
$gcc -g -m32 lab0_ex3.c 2>&1|tee make.log
copy
生成a.out文件
运行a.out,得到结果 intr is 0x10002
$./a.out
copy
用在related_info/lab0/list.h
中定义的结构和函数来实现一个小应用程序完成一个基于此链表的数据对象的访问操作。可参考related_info/lab0/lab0_ex4.c
list.h文件
#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
该文件中包含的链表的初始化,节点的插入,删除等操作。
lab0_ex4.c文件:
#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
运行lab0_ex4.c
$ gcc -g -m32 lab0_ex4.c
copy
发现代码中出现错误
在list.h文件中将<defs.h>改为“defs.h"
重新运行,生成a.out文件,运行a.out文件
学习时间 355分钟
操作时间 63分钟
按键次数 483次
实验次数 46次
报告字数 11479字
是否完成 完成