2019-2020-1 20209313《Linux內核原理與分析》第二周作業

  • 2020 年 10 月 18 日
  • 筆記

2019-2020-1 20209313《Linux內核原理與分析》第二周作業

零、總結

闡明自己對「計算機是如何工作的」理解。

一、myod

步驟

  1. 複習c文件處理內容
  2. 編寫myod.c 用myod XXX實現Linux下od -tx -tc XXX的功能
  3. main與其他分開,製作靜態庫和動態庫
  4. 編寫Makefile
  5. 提交測試代碼和運行結果截圖, 提交調試過程截圖,要全屏,包含自己的學號信息
  6. 在博客園發表一篇博客,重點寫遇到的問題和解決過程

總結

  1. 問題:命名修改導致不停輸錯命令
    解決:進行命名管理;使用批量替換修改

  2. 問題:ld: attempted static link of dynamic object

解決:

  • 因為指定了鏈接參數-static,它的存在,要求鏈接的必須是靜態庫,而不能是共享庫
  • 鏈接的應該為其他函數,誤寫成main函數的目標文件了
  1. 問題:undefined reference to異常
    解決:因為makefile寫錯了,把鏈接庫的名字寫成要調用它的文件名了,導致找不到文件

  2. 問題:使用文件時,找不到動態庫
    解決:gcc編譯時指明路徑 ./

其他方法:來源於//www.cnblogs.com/x_wukong/p/4722903.html
分析原因:ld提示找不到庫文件,而庫文件就在當前目錄中。
鏈接器ld默認的目錄是/lib和/usr/lib,如果放在其他路徑也可以,需要讓ld知道庫文件在哪裡。

  • 方法1:
    編輯/etc/ld.so.conf文件,在新的一行中加入庫文件所在目錄;
    運行ldconfig,以更新/etc/ld.so.cache文件;
  • 方法2:
    在/etc/ld.so.conf.d/目錄下新建任何以.conf為後綴的文件,在該文件中加入庫文件所在的目錄;
    運行ldconfig,以更新/etc/ld.so.cache文件;

覺得第二種辦法更為方便,對於原系統的改動最小。因為/etc/ld.so.conf文件的內容是include /etc/ld.so.conf.d/*.conf
所以,在/etc/ld.so.conf.d/目錄下加入的任何以.conf為後綴的文件都能被識別到。

二、C程序反彙編

  1. 目的:分析彙編代碼的工作過程中堆棧的變化
  2. 基本知識:

X86t體系結構棧地址向下增長(地址減小)

彙編指令:

mov尋址

1. 寄存器尋址
      movl %eax, %edx
2. 立即尋址
      movl $0x123, %edx
3. 直接尋址
      movl 0x123, %edx
4. 變址尋址
      movl 4(%ebx), %edx
### 進出棧
1. 進棧
  pushl %eax`
  等價偽指令
  sub $4 ,%esp
  mov %eax,%esp

2.出棧
popl %eax
等價偽指令
mov %esp,%eap
add $4 ,%esp
3.函數命令

  • 函數調用
    call 0x12345
    等價偽指令
    push %eip
    mov $OX???? ,%eip

  • 函數返回
    ret
    等價偽指令
    pop %eip

  • 建立函數堆棧enter
    等價偽指令

    push1 %ebp
    
    movl %esp, %ebp
    
  • 撤銷函數堆棧leave
    等價偽指令
    movl %ebp, %esp
    popl %ebp

3. 步驟一 反彙編

// main.c
int g(int x)
{
return x + 5555;
}

int f(int x)
{
return g(x);
}

int main(void)
{
return f(6) + 6666;
}

![](//img2020.cnblogs.com/blog/2175053/202010/2175053-20201018232126107-1250148043.png)
![](//img2020.cnblogs.com/blog/2175053/202010/2175053-20201018232042662-

4. 步驟二 分析彙編代碼

g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $5555, %eax
popl %ebp
ret
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $6, (%esp)
call f
addl $6666, %eax
leave
ret


(二)下面分析過程

首先進行main函數調用g:
main:
// 1、建立main的空棧 等價於enter
pushl %ebp
movl %esp, %ebp
// 2、等價於push $6
subl $4, %esp //棧頂地址-4,左移增加棧空間一個單元
movl $6, (%esp) //棧頂值設為6(設在內存中對應塊號為0)

//(設該立即數的存儲位置在內存中對應塊號為0)

// 3、進入f函數調用
call  f //eip跳轉到函數f的第一條命令
f:
// 1、壓棧f所需參數(上一步的棧頂值即為參數,放在f的棧底)
    // 建立f的空棧 等價於enter
    pushl %ebp //基地址右移一個單元(在內存中對應塊號為1),獲取塊號0的值,放在eax。
    movl  %esp, %ebp //棧頂、棧底指向(在內存中對應塊號為1),建立f的空棧
    // push f棧的-2單元
    subl  $4, %esp //左移,增加棧空間一個單元(esp在內存中對應塊號為2)
    movl  8(%ebp), %eax//獲取(基地址塊號1右移兩個單元,在內存中對應塊號為-1)即上級函數存儲的立即數6,放到eax
    // 將值存入f的棧頂
    movl  %eax, (%esp)//塊號2存儲塊號0的存儲值)
// 2、 進入g函數調用
    call  g //eip跳轉到函數g的第一條命令
    g:
    //
        // 建立g的空棧 等價於enter
        pushl %ebp //(ebp存儲的地址對應在內存中對應塊號為2)
        movl  %esp, %ebp//(esp存儲的地址對應在內存中對應塊號為2)
        // 上級函數所給的參數6 +5555存儲到eax(存着main所給的參數值6)
        movl  8(%ebp), %eax//獲取(在內存中對應塊號為0)存儲值.即上級函數存儲的立即數6,放到eax
        addl  $5555, %eax // eax寄存器值加5555
        popl  %ebp //ebp指向塊號為1,塊號2的地址
        // 返回上級函數f,返回值為eax的值
        ret
    //撤銷g的空堆棧
    leave
    // 返回上級函數main,返回值為eax的值
    ret
addl  $6666, %eax // eax寄存器值加56666
leave //撤銷空堆棧

// main函數結束,返回值為eax的值
ret


# 三、其他
## 調試
* b 設斷點(要會設4種斷點:行斷點、函數斷點、條件斷點、臨時斷點)
* run 開始運行程序
* bt 打印函數調用堆棧
* p 查看變量值
* c 從當前斷點繼續運行到下一個斷點
* n 單步運行
* s 單步運行
* quit 退出CGDB
## 四種斷點的設法
1.條件斷點:b fxx(函數名)
2.條件斷點:b 12 if i=5000
3.行斷點:b 行號
4.臨時斷點:tb 行號


# gcc編譯
### 預處理
`gcc -E hello.c -o hello.i`
### 編譯
`gcc –S hello.i –o hello.s`
### 彙編
`gcc –c hello.s –o hello.o`
### 鏈接
`gcc hello.o –o hello.exe`

# gcc打包
1.把代碼編譯為目標文件形式(形如):
`gcc -c liberr.c -o liberr.o`

## 靜態庫
2.使用工具ar創建一個存檔文件:
`ar rcs mymath9313.a otherfunc.o`

3.編譯程序時把程序和myod9313.a鏈接起來:
`gcc -static -o myod XXX myod9313.o mymath.a`
## 動態庫

1.創建一個共享目標文件
gcc -shared -fpic -o mymath.so add5320.c sub5320.c mul.c div.c
gcc -shared -fpic -o myod9313.so myod9313.c
2.創建可執行目標文件
gcc -o myod XXX myod9313.c ./mymath.so

運行+測試

makefile

myod XXX:main.o otherfunc.o s
gcc main.o otherfunc.o s -o testmyod
main.o:main.c
gcc -c main.c -o main.o
otherfunc.o:otherfunc.c
gcc -c otherfunc.c -o otherfunc.o
clean:
rm -f *.o testmymath