\ 跳到主要內容

A brief introduction to Object file

這篇可以看到在vim中開啟main.o,而上圖充斥著1&0,看似截然不同的兩個東西。
  • main.o in vim
^?ELF^B^A^A^@^@^@^@^@^@^@^@^@^A^@>^@^A^@^@
^@^@^@^@^@^@^@^@^@^@X^B^@^@^@^@^@^@^@^@^@^
@@^@^@^@^@^@@^@^L^@^K^@ó^O^^úUH<89>å¸^@^@^
@^@]Ã^@GCC: (Ubuntu 9.4.0-1ubuntu1~20.04.1)
9.4.0^@^@^@^@^@^@^D^@^......

理解兩者差異的原因,可以從兩個面向去釐清:
1. 所有的檔案都是由0&1組成的
電腦中的檔案皆是藉由0&1組成的,包括source file, object file(.o), binary file等等,但vim會將所有的binary藉由ASCII轉換成為我們所看到的plain text,這裡以一main.cpp作為例子:
  • main.cpp in vim
#define N 81
int main(){
        return 0;//this is the end
}
  • main.cpp, configured with :%! xxd -b

00000000: 00100011 01100100 01100101 01100110 01101001 01101110  #defin
00000006: 01100101 00100000 01001110 00100000 00111000 00110001  e N 81
0000000c: 00001010 01101001 01101110 01110100 00100000 01101101  .int m
00000012: 01100001 01101001 01101110 00101000 00101001 01111011  ain(){
00000018: 00001010 00001001 01110010 01100101 01110100 01110101  ..retu
0000001e: 01110010 01101110 00100000 00110000 00111011 00101111  rn 0;/
00000024: 00101111 01110100 01101000 01101001 01110011 00100000  /this 
0000002a: 01101001 01110011 00100000 01110100 01101000 01100101  is the
00000030: 00100000 01100101 01101110 01100100 00001010 01111101   end.}
00000036: 00001010 
而透過:%! xxd -b configure vim,則可以查看binary格式的原始資料,可以看到左側的binary與右側的plain text以ASCII CODE一對一的相對應(e.g, 00100011->#, 01100100->d)。
main.o 在透過vim開啟時,透過ASCII CODE decode並且呈現在vim中。而"^@"是在vim中則是對應到了"00000000","^@"是vim用以表示null character的格式。

2. ELF 的 binary decoding
不同的檔案有不同的layout,不是所有的檔案都能經過ASCII CODE decode成plain text,如main.o ,可以看到vim中的main.o 無法被閱讀;順帶一提,也並非所有檔案形式都能被decode成plain text,e.g. binary file。

.o 檔的檔案形式為ELF,這種檔案可以藉由objdump -dh main.o來decode成plain text:
  • main.o configured with objdump -dh main.o
main.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000000f  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000000  0000000000000000  0000000000000000  0000004f  2**0
......

Disassembly of section .text:

0000000000000000 
: 0: f3 0f 1e fa endbr64 4: 55 push %rbp 5: 48 89 e5 mov %rsp,%rbp 8: b8 00 00 00 00 mov $0x0,%eax d: 5d pop %rbp e: c3 retq

ELF包含了很多資訊 ,而程式的邏輯放在 .text 裡面,如果回過頭去看main.s,會發現兩者的內容大同小異。

ELF是公定好,能夠被電腦所執行的資料格式。而因為電腦執行皆的資訊皆是0&1,所以上圖才藉由0&1去表達ELF檔,並非表面上純文字即0&1。此外,實際上被執行的machine code還包括排列記憶體等其餘的工作,assembly code所轉換的machine code並不是實際上被執行的machine code的全貌。


留言

這個網誌中的熱門文章

Command Line 與 Makefile

在認識到Linux以前,我鮮少接觸到CLI(Command Line Interface),也花了些許時間去熟悉。一開始看它也許會感到有些震懾,但並沒有想像中的複雜,單純是將我們習慣使用的GUI(Graphical User Interface)改成CLI,滑鼠改成鍵盤,簡單做了轉換。 sudo apt-get install qt6-default //以superuser身份安裝qt6-default mkdir build/install -p //新增資料夾 cd build/install //切換目錄到build/install rm –rf build //remove文件, recursively. makefile make 以及 makefile讓我們得以自動化我們想執行的command line。比如說modmesh裡面中clean這個target,若是藉由一行一行的command line我們會需要輸入以下的指令, rm -f $(MODMESH_ROOT)/modmesh/_modmesh$(pyextsuffix) make -C $(BUILD_PATH) clean 但如果已經在Makefile中寫好了clean這個target,將一行行的command line寫成了shell script。 .PHONY: clean clean: rm -f $(MODMESH_ROOT)/modmesh/_modmesh$(pyextsuffix) make -C $(BUILD_PATH) clean 我們就可以去藉由make,直接輸入 make clean 去執行我們想要去執行的內容,不用逐步命令。 make clean

Write a module in C++ and use it in python

 做這個小實驗的當天看到這個梗圖,相當呼應這個主題: 「其它的程式語言對你作力學是沒用的,作計算就三本柱 Python、C++、Fortran 足矣,連 C 都沒什麼用處。」Python在計算的速度上相較於C++非常的緩慢,這個 demo 很清楚地呈現了這件事。 以計算力學為題,python在tool的開發,input的整合上具有優勢,但是在計算效能上的表現不佳,於是就有了許多與python互相支援的foreign function interface(FFI),如 swig, cython, pybind11。 截python所長,補C++所短 (or vice versa) ,似乎是做出更好的力學程式不可或缺的元素,pybind扮演的角色於是顯現。接下來就簡單用C++寫一個python的module: 1. 寫 .cpp/.h file。 #include <pybind11/pybind11.h> double square(double i){ return i*i; } PYBIND11_MODULE(test, handle){ //Module 的attributes 會在這裡做定義 handle.doc()="This is my doc"; handle.def("sqrt", &square); } 2. 寫 CMakeList.txt。 cmake_minimum_required(VERSION 3.4) PROJECT(pybind_vid) add_subdirectory(pybind11) pybind11_add_module(test test.cpp) //test為建構的module的名稱 test.cpp是它所依據的檔案 3. Build the module。 mkdir build cd build/ cmake .. make 4. 在python中使用前面所建立的module。 ~/git-repo/importation/test$ python3 >>> import test >>> dir(test) ['doc', 'file...