make bzImage
cp arch/x86/root/bzImage /boot/bzImage3
reboot
echo 8 > /proc/sys/kernel/printk
arch/x86/kernel/syscall_table_32.S
xxd -g1 myfd > x # 각 바이트가 분리되어 보이도록 함
ls -a # 숨겨진 파일(., ..)도 모두 출력됨
ls -ai # inode number 함께 출력
dd bs=1024 count=1440 if=/dev/zero of=myfd
0으로 채워진 1024*1440 바이트 크기의 데이터를 myfd에 write하겠다
mkfs -t ext2 myfd
mkdir temp
mount -o loop myfd temp # myfd와 temp를 연결
umount temp # 연결을 끊음
m_inodes_count
- 디스크 내 inode의 개수m_blocks_count
- 디스크 내 block의 개수m_magic
- 파일 시스템 형식 (ext2, ext3, ext4)m_log_block_size
- 블록 사이즈m_first_data_block
- 첫번째 데이터 블록 number, super blockm_block_bitmap
- DBM 블록의 위치m_inode_bitmap
- IBM 블록의 위치m_inode_table
- inode table의 위치block location
- 00 00 00 21byte size
- 00 00 04 00 = 1024block size
- 00 00 00 02owner
- 00 00 (= root 사용자)4byte - inode number / 2byte - record length / 1byte - name length / 1byte - file type / 나머지 - file name
여기서도 리틀 인디언으로 읽기 !!
block location 구하는 방법: 0x2800 + 0x80 * (c-1)
c-1
을 16진수로 변환한 뒤 16진수 곱셈을 해주어야 함.
와 ..
dms inode가 2인 root directory file로 위에서 한 것과 동일.
- 02 00 00 00 / 0c 00 / 01 / 02 / 2e 00 00 00
..
- 02 00 00 00 / 0c 00 / 02 / 02 / 2e 2e 00 00
lost+found
- 0b 00 00 00 / 14 00 / 0a / 02 / 6c 6f 73 74 2b 66 6f 75 6e 64 00 00
f1
- 0c 00 00 00 00 / 0c 00 / 02 / 01 / 66 31 00 00
f2
- 0d 00 00 00 / c8 03 / 02 / 01 / 66 32 00 00
기존에는 f1, f2만 있던 상황
0e ~~~
부분이 추가된 것을 알 수 있음m_ctime
이 5c 4b 60 63으로 변경됨 (최종 변경 시간)m_dtime
이 5c 4b 60 63으로 변경됨 (삭제한 시간)m_links_count
- 00으로 변경됨 (해당 inode를 참조하는 링크 수)block location
- 31 00 00 00을 그대로 유지inode number
- 14에서 0으로 바뀜inode number
- 14week10 16번
보기: super block과 root inode 등의 파일 시스템을 캐싱
start_kernel
> rest_init
> kernel_init
> prepare_namespace
> mount_root
순으로 호출
init/main.c
init/do_mounts.c
include/linux/fs.h
include/linux/buffer_head.h
include/linux/dcache.h
init/do_mounts.c
에 함수 만들기void display_superblocks() {
struct super_block *sb;
list_for_each_entry(sb, &super_blocks, s_list) {
printk("dev name: %s, dev maj num: %d, dev minor num: %d, root ino: %d\n",
sb->s_id, MAJOR(sb->s_dev), MINOR(sb->s_dev), sb->s_root->d_inode->i_ino);
}
}
// mount_root() 전 후에 함수 호출
void __init prepare_namespace() {
...
printk("before mount_root():\n");
display_superblocks();
mount_root();
printk("after mount_root():\n");
display_superblocks();
...
}
init/do_mounts.c
에 함수 만들기void display_all_inodes() {
struct inode *in;
list_for_each_entry(in, &inode_in_use, i_list) {
printk("dev maj num: %d, dev minor num: %d, inode num: %d, sb dev: %s\n",
MAJOR(in->i_rdev), MINOR(in->i_rdev), in->i_ino, in->i_sb->s_id);
}
}
// mount_root() 전 후에 함수 호출
void __init prepare_namespace() {
...
printk("before mount_root():\n");
display_all_inodes();
mount_root();
printk("after mount_root():\n");
display_all_inodes();
...
}
void display_all_inodes() {
struct inode *in;
list_for_each_entry(in, &inode_in_use, i_list) {
printk("dev maj num: %d, dev minor num: %d, inode num: %d, sb dev: %s\n",
MAJOR(in->i_rdev), MINOR(in->i_rdev), in->i_ino, in->i_sb->s_id);
// 코드 추가한 부분 !!!
struct dentry *den;
list_for_each_entry(den, &in->i_dentry, d_alias) {
printk("file name: %s, ", den->d_name.name);
}
printk("file byte size: %x\n", in->i_size);
}
}
fs/read_write.c
에 구현했는데 모범 답안은 init/do_mounts.c
에 구현함#include <stdio.h>
int main() {
syscall(44);
return 0;
}
extern struct list_head inode_in_use;
asmlinakge void my_sys_display_inodes() {
struct inode *in;
int count = 0;
list_for_each_entry(in, &inode_in_use, i_list) {
if(count==100) break;
struct dentry *den;
list_for_each_entry(den, &in->i_dentry, d_alias) {
printk("file name: %s, ", den->d_name.name);
printk("mounting point: %d, ", den->d_mounted);
count++;
}
printk("file byte size: %x\n", in->i_size);
}
}
g++ -o ex1 ex1.cpp
./ex1 & # ex1의 pid가 나옴
cat /proc/(ex1의 pid)/maps > x1
vi x1
#include <stdio.h>
int x; // 전역 변수 - Data 영역
int y[100000]; // 전역변수지만 커서 Heap 영역
int main() { // Code 영역
int k; // 지역 변수 - Stack 영역
int *pk; // 동적할당 메모리 - Heap 영역
pk = new int;
printf("ex1. &main: %p, &x: %p, &y: %p, &y[9999]: %p,
&k: %p, &pk: %p, pk: %p\n", main, &x, &y, &y[9999], &pk, pk);
for(;;); // memory map을 보기 위해
return 0;
}
Segment | Address | Identifier |
---|---|---|
Code | 08048000 - 08049000 | &main |
Read-only Data | 08049000 - 0804a000 | - |
Data | 0804a000 - 0804b000 | &x, &y |
Heap | 0804b000 - 08075000 | &y[9999], pk |
Stack | bfa77000 - bfa8c000 | &k, &pk |
프로세스 상의 주소는 logical 주소이기 때문
각 프로세스 구조의 같은 부분에 메모리를 할당
physical 메모리 주소는 서로 다를 것
#include <stdio.h>
int A[5][1024];
int main() { // Code 영역
int i, j; // 지역 변수 - Stack 영역
for(i=0; i<5; i++) {
for(j=0; j<5; j++) {
A[i][j] = 3;
}
printf("&main: %p, &A: %p, &A[%d]: %p, &i: %p, &j: %p"
, main, &A, i, &A[i], &i, &j);
}
for(;;);
return 0;
}
Segment | Page | Identifier |
---|---|---|
Code | 8048 - 8049 | &main |
Data | 804a - 804b | &A[0] |
Heap | 804b - 8050 | &A[1], &A[2], &A[3], &A[4] |
Stack | bfa7f - bfa94 | &i, &j |
1) Code 영역에서 페이지를 불러옴 - 1 page
2) Data, Heap 영역에서 804a ~ 8050 불러옴 - 6 page
3) Stack 영역에서 bfa92 불러옴 - 1 page
시스템콜 56번 할당 - my_sys_show_pfcnt
mm/mmap.c
에 함수 구현
extern int pfcnt;
asmlinkage void my_sys_show_pfcnt() {
printk("page fault count so far: %d\n", pfcnt);
}
arch/x85/mm/fault.c
의 do_page_fault()
- page fault가 발생하면 pfcnt가 1 증가하도록 코드 추가void __kprobes do_page_faults(struct pt_regs *regs, unsinged long error_code) {
pfcnt += 1; // 맨 위에 코드 한 줄 추가
...
}
#include <stdio.h>
#include <unistd.h>
int A[5][1024];
int main() { // Code 영역
int i, j; // 지역 변수 - Stack 영역
syscall(56);
for(i=0; i<5; i++) {
for(j=0; j<5; j++) {
A[i][j] = 3;
}
// printf("&main: %p, &A: %p, &A[%d]: %p, &i: %p, &j: %p"
// , main, &A, i, &A[i], &i, &j);
// printf문이 page fault에 영향을 주는 것 같아 주석 처리 후 실행
}
syscall(56);
for(;;);
return 0;
}
arch/x85/mm/fault.c
의 do_page_fault()
- 프로그램 이름이 ex3면 page fault 주소를 출력하도록 커널 코드를 변경void __kprobes do_page_faults(struct pt_regs *regs, unsinged long error_code) {
...
address = read_cr2();
if(strcmp(tsk->comm, "ex3")==0) {
printk("pg fault for ex3 at: %p\n", address);
}
...
}
#include <stdio.h>
int x;
int main() {
x = 3;
return 0;
}
x
- 804a014main
- 8048034read only data
- 8049f20, 8049f6clibrary code, data
- b7~~#include <stdio.h>
#include <unistd.h>
int A[5][1024];
int main() { // Code 영역
int i, j; // 지역 변수 - Stack 영역
syscall(56);
for(i=0; i<5; i++) {
for(j=0; j<5; j++) {
A[i][j] = 3;
}
printf("&main: %p, &A: %p, &A[%d]: %p, &i: %p, &j: %p"
, main, &A, i, &A[i], &i, &j);
}
syscall(56);
for(;;);
return 0;
}
my_sys_get_phyloc
mm/mmap.c
에 시스템 콜 함수 구현#include <stdio.h>
#include <unistd.h>
int main() {
printf(&main: %p\n", main);
syscall(98);
return 0;
}
asmlinkage void sys_get_phyloc(unsigned int addr) {
// step 0. PGDIR_SHIFT, PTRS_PER_PGD, PAGE_SHIFT, PTRS_PER_PTE 확인
printk("PGDIR_SHIFT: %d, PTRS_PER_PGD: %d, PAGE_SHIFT: %d, PTRS_PER_PTE: %d\n",
PGDIR_SHIFT, PTRS_PER_PGD, PAGE_SHIFT, PTRS_PER_PTE);
// step 1. directory number, page number, offset 추출
unsigned int dir = addr >> PGDIR_SHIFT;
unsigned int pg = (addr >> PAGE_SHIFT) & 0x3ff;
unsigned int off = addr & 0xfff;
printk("directory number: %d, page number: %d, offset from address: %d\n",
dir, pg, off);
// step 2. 현재 프로세스의 디렉토리 테이블
unsigned int *x = current->mm->pgd;
printk("location of directory table of the current process: %p\n", x);
// step 3. 디렉토리 테이블의 위치
unsigned int *y = &x[dir];
printk("location of directory table entry: %p\n", y);
// step 4. 디렉토리의 물리적 주소
unsigned int pdir = *y & 0xfffff000;
printk("physical location of the directory: %x\n", pdir);
// step 5. 가상 주소에 접근 (앞에 c 붙이기)
unsigned int *vdir = pdir + 0xc0000000;
printk("virtual location of the directory: %p\n", vdir);
// step 6. k를 이용하여 물리 주소에 접근하자
// 물리 주소에 직접 접근 불가 > 가상 주소를 이용해야 함
unsigned int *k = &vdir[pg];
printk("location of the frame entry: %p\n", k);
// step 7. frame의 물리 주소
unsigned int pfr = *k & 0xfffff000;
printk("physical location of frame: %x\n", pfr);
// step 8. main 함수의 물리 주소
unsigned int pmain = pfr + off;
printk("physical address of main: %x\n", pmain);
// step 9. 가상 주소에 접근 (앞에 c 붙이기)
unsigned int *vmain = pmain + 0xc0000000
printk("virtual address of main: %x\n", vmain);
printk("first 4 bytes: %x\n", vmain[0]);
}
8d 4c 24 04
objdump -d ./ex~~
의 결과8d 4c 24 04
올바르게 main 함수의 물리 주소를 찾았다 !!!