Showing posts with label C Language. Show all posts
Showing posts with label C Language. Show all posts

Tuesday, December 24, 2013

類似hexdump工具的source code

As title, the hexdump command is

$ hexdump -C -v files.bin

Write a simple tool is helpfull for the binary dump in the program...

  1 #include 
  2 #include 
  3
  4 #define BUF_SIZE    1024
  5
  6 int main(void)
  7 {
  8     int r;
  9     unsigned char buf[BUF_SIZE];
 10
 11     int seed = 0;
 12
 13     while (1)
 14     {
 15         int i, j;
 16
 17         r = fread(buf, 1, BUF_SIZE, stdin);
 18         if (0 == r)
 19         {
 20             break;
 21         }
 22
 23         i = 0;
 24
 25         for (i = 0; i < r; i += 0x10, seed += 0x10)
 26         {
 27
 28             printf("%08x ", seed);
 29
 30             j = i;
 31             for (j = i; j < i + 0x10;  j++)
 32             {
 33                 if (0 == (j % 8))
 34                 {
 35                     printf(" ");
 36                 }
 37                 printf("%02x ", buf[j]);
 38             }
 39
 40             j = i;
 41             for (j = i; j < i + 0x10;  j++)
 42             {
 43                 if (0 == (j % 8))
 44                 {
 45                     printf(" ");
 46                 }
 47                 if ((buf[j] >= ' ') && (buf[j] <= '~'))
 48                 {
 49                     printf("%c", buf[j]);
 50                 }
 51                 else
 52                 {
 53                     printf(".");
 54                 }
 55             }
 56             printf("\n");
 57         }
 58     }
 59
 60     return 0;
 61 }
 62

The result is...


$ gcc -Wall ddc.c -o ddc

$
$ ./ddc < s.jpg
00000000  ff d8 ff e0 00 10 4a 46  49 46 00 01 01 00 00 01  ......JF IF......
00000010  00 01 00 00 ff db 00 43  00 08 06 06 07 06 05 08  .......C ........
00000020  07 07 07 09 09 08 0a 0c  14 0d 0c 0b 0b 0c 19 12  ........ ........
00000030  13 0f 14 1d 1a 1f 1e 1d  1a 1c 1c 20 24 2e 27 20  ........ ... $.'
00000040  22 2c 23 1c 1c 28 37 29  2c 30 31 34 34 34 1f 27  ",#..(7) ,01444.'
00000050  39 3d 38 32 3c 2e 33 34  32 ff c0 00 0b 08 00 08  9=82<.34 2.......
00000060  00 08 01 01 11 00 ff c4  00 1f 00 00 01 05 01 01  ........ ........
00000070  01 01 01 01 00 00 00 00  00 00 00 00 01 02 03 04  ........ ........
00000080  05 06 07 08 09 0a 0b ff  c4 00 b5 10 00 02 01 03  ........ ........
00000090  03 02 04 03 05 05 04 04  00 00 01 7d 01 02 03 00  ........ ...}....
000000a0  04 11 05 12 21 31 41 06  13 51 61 07 22 71 14 32  ....!1A. .Qa."q.2
000000b0  81 91 a1 08 23 42 b1 c1  15 52 d1 f0 24 33 62 72  ....#B.. .R..$3br
000000c0  82 09 0a 16 17 18 19 1a  25 26 27 28 29 2a 34 35  ........ %&'()*45
000000d0  36 37 38 39 3a 43 44 45  46 47 48 49 4a 53 54 55  6789:CDE FGHIJSTU
000000e0  56 57 58 59 5a 63 64 65  66 67 68 69 6a 73 74 75  VWXYZcde fghijstu
000000f0  76 77 78 79 7a 83 84 85  86 87 88 89 8a 92 93 94  vwxyz... ........
00000100  95 96 97 98 99 9a a2 a3  a4 a5 a6 a7 a8 a9 aa b2  ........ ........
00000110  b3 b4 b5 b6 b7 b8 b9 ba  c2 c3 c4 c5 c6 c7 c8 c9  ........ ........
00000120  ca d2 d3 d4 d5 d6 d7 d8  d9 da e1 e2 e3 e4 e5 e6  ........ ........
00000130  e7 e8 e9 ea f1 f2 f3 f4  f5 f6 f7 f8 f9 fa ff da  ........ ........
00000140  00 08 01 01 00 00 3f 00  f0 ba ff d9 18 07 24 00  ......?. ......$.

$

Saturday, December 21, 2013

Bit operation

於system driver中,時常遇到bit的操作...
比方說要將某bit設成1或0
或這要看看某些bit有無on/off
可以以以下方式操作
#define BIT0 0x00000001
#define BIT1 0x00000002
#define BIT2 0x00000004
#define BIT3 0x00000008
#define BIT4 0x00000010
#define BIT5 0x00000020
#define BIT6 0x00000040
#define BIT7 0x00000080

#define REG_BASE 0x80000000

typedef unsigned int u32;

#define REG_BIT_SET(reg, bit) \
   (*(volatile u32 *)(REG_BASE + reg) |= (bit))

#define REG_BIT_GET(reg, bit) \
   (*(volatile u32 *)(REG_BASE + reg) & (bit))

#define REG_BIT_CLR(reg, bit) \
   (*(volatile u32 *)(REG_BASE + reg) &= ~(bit))

Thursday, August 27, 2009

Hello World入門(4)

這是Hello World程式的註解。

1 /*
2 引入header file,目的是讓
3 compiler找到printf的宣告
4 */
5 #include <stdio.h>
6
7 /*
8 定義main為不需要參數,傳回
9 值為整屬的函數。main函數為
10 C語言程式中默認的進入點
11 */
12 int main(void)
13 {
14
15 /*
16 使用printf函數,輸出
17 Hello World字串至標準輸出
18 */
19 printf("Hello World\n");
20
21 /*
22 使函數結束,並傳回值0
23 */
24 return 0;
25 }

Hello World的入門,宅爸爸就暫時學習到這邊。
最後,以Hello World跟Makefile結合,做到編譯HelldWorld.c使用兩階段(編譯、連結)

1 # Copyright (C) 2009 Lung.S.Wu
2
3 #ARCH=
4 #TARGET=$(ARCH)-elf-
5
6 HEADER=head.h
7 SRC=HelloWorld.c
8 OBJ=$(SRC:%.c=%.o)
9 EXE=HelloWorld
10
11 CC=$(TARGET)gcc
12 LD=$(TARGET)ld
13
14 CFLAGS=-O3 -g -Wall
15
16 #.SILENT:
17
18 all:$(EXE)
19
20 $(EXE): $(OBJ)
21 $(CC) $(CFLAGS) $^ -o $@
22
23 %.o: %.c $(HEADER)
24 $(CC) -c $(CFLAGS) $< -o $@
25
26 clean:
27 rm -rf $(OBJ) $(EXE)

goto怎麼用?

宅爸爸學到goto這東西...
教科書上寫到儘量不用它,以免增加程式的複雜度,
以下就是一個很標準因為goto使用不當的鬼打牆的程式...

1 /******************************
2 * goto program 1
3 ******************************/
4 void function(void)
5 {
6 int i = 0;
7
8 label1:
9 printf("Hello World\n");
10 if (i != 0)
11 {
12 return;
13 }
14 goto label3;
15
16 label2:
17 printf("What is it?\n");
18 i = 1;
19 goto label1;
20
21 label3:
22 printf("Here is it\n");
23 goto label2;
24 }
25

但有些狀況宅爸爸沒用goto這東西會讓程式變的很容易出錯,這是一個很矛盾的狀況...

1 /******************************
2 * goto program 2
3 * This is a C pseudo code
4 ******************************/
5 int function(void)
6 {
7 int ret = -1;
8 Handle h1, h2, h3;
9
10 h1 = HandleOpen(...);
11 if (error == h1)
12 {
13 goto return_f;
14 }
15
16 h2 = HandleOpen(...);
17 if (error == h2)
18 {
19 goto close_h1;
20 }
21
22 /* Error happened ... */
23 if (error)
24 {
25 goto close_h2;
26 }
27
28 h3 = HandleOpen(...);
29 if (error == h3)
30 {
31 goto close_h2;
32 }
33
34 /* Error happened ... */
35 if (error)
36 {
37 goto close_h3;
38 }
39
40 /* Other code ... */
41
42 ret = 0;
43 close_h3:
44 HandleClose(h3);
45 close_h2:
46 HandleClose(h2);
47 close_h1:
48 HandleClose(h1);
49 return_f:
50 return ret;
51 }
52

尤其是在事後修改、維護這些程式時,program 1我會很容易搞混,而program 2比較有效率。
如果program2沒有用goto,return的處理就很麻煩,情況如下...

1 /******************************
2 * goto program 3
3 * This is a C pseudo code
4 ******************************/
5 int function(void)
6 {
7 int ret = -1;
8 Handle h1, h2, h3;
9
10 h1 = HandleOpen(...);
11 if (error == h1)
12 {
13 return ret;
14 }
15
16 h2 = HandleOpen(...);
17 if (error == h2)
18 {
19 HandleClose(h1);
20 return ret;
21 }
22
23 /* Error happened ... */
24 if (error)
25 {
26 HandleClose(h1);
27 return ret;
28 }
29
30 h3 = HandleOpen(...);
31 if (error == h3)
32 {
33 HandleClose(h1);
34 HandleClose(h2);
35 return ret;
36 }
37
38 /* Error happened ... */
39 if (error)
40 {
41 HandleClose(h1);
42 HandleClose(h2);
43 HandleClose(h3);
44 return ret;
45 }
46
47 /* Other code ... */
48
49 ret = 0;
50 return ret;
51 }
52

program 2若要修改,要增加一個return點,只要goto到合適的地方就行。
program 3的處理情況,要重複的關閉已開啟的handle,再做return,科科...。

goto在C語言中式保留字,不是函數,是無條件的跳躍到指定的程式中,但只限於單一函式範圍內。

Tuesday, August 25, 2009

Hello World入門(3)

於Hello World入門(2)中一個檔案HelloWorld.c,它是一隻C語言程式。
傳統上,C語言程式檔案都以.c或者.h檔為結尾,本程式也不例外。

要使此程式可以執行,需經過C compiler編譯、連結無誤之後產生一可執行檔。

這裡補充說明,C語言語法是一個標準,現在標準官方網站。
而有不同的廠商、團體根據C語言標準製作他們自產的編譯器,比方說Microsoft,GNU,Intel...。

現在以GNU製作的編譯器為例,要將HelloWorld.c編譯成執行檔,
我習慣以底下命令編譯C語言程式...

gcc -Wall HelloWorld.c -o HelloWorld

這將會產生HelloWorld的執行檔。
  • gcc:GNU C編譯器的命令
  • -Wall:gcc參數,列出所有gcc認為有危險、不妥當程式碼片段
  • HelloWorld.c:程式設計者所編寫程式檔名
  • -o HelloWorld:指定編譯完成的執行檔為名稱,若無此參數預設檔名為a.out


    很多理論的書本中提到,將一的原始程式要編譯成執行檔的過程,需經過以下步驟...
    1.編譯。2.連結。
    或者...
    1.編譯。2.組譯。3.連結。

    GNU C編譯器也不例外,遵循以上三步驟的慣例,我們可以用以下方式編譯
    $gcc -Wall -v HelloWorld.c -o HelloWorld
    得到編譯時的詳細內容、步驟
    Using built-in specs.
    Target: i486-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Debian 4.3.2-1.1' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-mpfr --enable-targets=all --enable-cld --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
    Thread model: posix
    gcc version 4.3.2 (Debian 4.3.2-1.1)
    COLLECT_GCC_OPTIONS='-Wall' '-v' '-o' 'HelloWorld' '-mtune=generic'
    /usr/lib/gcc/i486-linux-gnu/4.3.2/cc1 -quiet -v HelloWorld.c -quiet -dumpbase HelloWorld.c -mtune=generic -auxbase HelloWorld -Wall -version -o /tmp/cc3KesF0.s
    ignoring nonexistent directory "/usr/local/include/i486-linux-gnu"
    ignoring nonexistent directory "/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/include"
    #include "..." search starts here:
    #include <...> search starts here:
    /usr/local/include
    /usr/lib/gcc/i486-linux-gnu/4.3.2/include
    /usr/lib/gcc/i486-linux-gnu/4.3.2/include-fixed
    /usr/include/i486-linux-gnu
    /usr/include
    End of search list.
    GNU C (Debian 4.3.2-1.1) version 4.3.2 (i486-linux-gnu)
    compiled by GNU C version 4.3.2, GMP version 4.2.2, MPFR version 2.3.2.
    warning: MPFR header version 2.3.2 differs from library version 2.3.1.
    GGC heuristics: --param ggc-min-expand=99 --param ggc-min-heapsize=129511
    Compiler executable checksum: c4cd35f2318868df36b839e33a8e2089
    COLLECT_GCC_OPTIONS='-Wall' '-v' '-o' 'HelloWorld' '-mtune=generic'
    as -V -Qy -o /tmp/ccA8J2A1.o /tmp/cc3KesF0.s
    GNU assembler version 2.18.0 (i486-linux-gnu) using BFD version (GNU Binutils for Debian) 2.18.0.20080103
    COMPILER_PATH=/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/
    LIBRARY_PATH=/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/:/lib/../lib/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../:/lib/:/usr/lib/
    COLLECT_GCC_OPTIONS='-Wall' '-v' '-o' 'HelloWorld' '-mtune=generic'
    /usr/lib/gcc/i486-linux-gnu/4.3.2/collect2 --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o HelloWorld /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.3.2/crtbegin.o -L/usr/lib/gcc/i486-linux-gnu/4.3.2 -L/usr/lib/gcc/i486-linux-gnu/4.3.2 -L/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.3.2/../../.. /tmp/ccA8J2A1.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.3.2/crtend.o /usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/crtn.o

    以上囉哩八說這麼多,只要抓住底下的要點
    /usr/lib/gcc/i486-linux-gnu/4.3.2/cc1
    為第一步驟...編譯,產生一個組合語言程式。

    as -V -Qy -o /tmp/ccA8J2A1.o /tmp/cc3KesF0.s
    為第二步驟...將第一步驟產生的組合語言程式做組譯工作,
    產生object code(中文我不會翻譯)。

    /usr/lib/gcc/i486-linux-gnu/4.3.2/collect2
    為第二步驟...將第二步驟產生的object code做聯結(link)工作,
    產稱執行程式。



    做最後補充,連結的步驟可以將一個以上的object聯結(link)成一個執行程式。
    之所以會有聯結(link)的步驟,最主要目的是...
  • 可以將很大一段的程式碼分割成很多的程式檔,個別編譯,方便程式管理。
  • 將程式是分割,若發生編譯錯誤,只需修改、編譯錯誤的程式,不需所有程式重新編譯,以節省編譯時間。
  • 可以將已編譯的object code交給第三者,達到資料隱藏。
  • 連結他人撰寫編譯好的程式庫(動作和上一點相反)
  • 使執行檔於執行時,做好程式碼於記憶體中的佈局規劃。
  • 增加執行檔檔頭,使program loader辨認、讀取相關訊息。
  • 一般狀況而言,也會自動聯結系統預設的程式庫。