小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

匯編和c只有一步之近

 ShangShujie 2012-06-12

作者:陳曦

日期:2012-6-8 10:50:13

環(huán)境:[Ubuntu 11.04  Intel-based x64 gcc4.5.2  CodeBlocks10.05  AT&T匯編  Intel匯編] 

轉(zhuǎn)載請(qǐng)注明出處


Q: 舉個(gè)例子吧。

A: 下面的代碼的目標(biāo)是計(jì)算1+2的值,最后放到變量temp中,并輸出:

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)       printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)              printf(#str" is %s\n", (str));  
  6.   
  7.   
  8. static void assemble_func()  
  9. {  
  10.     int temp;  
  11.     __asm__("mov $1, %eax");  
  12.     __asm__("mov $2, %ebx");  
  13.     __asm__("add %ebx, %eax");  // 1 + 2  
  14.     __asm__("mov %%eax, %0":"=r"(temp));    // mov the value of register eax to the var "temp"   
  15.     PRINT_D(temp)               // print temp   
  16. }  
  17.   
  18. int main()  
  19. {  
  20.     assemble_func();  
  21.     return 0;  
  22. }  

運(yùn)行結(jié)果:
  1. temp is 3  

Q: assemble_func函數(shù)的匯編代碼形式是什么?

A: 

  1.   0x08048404 <+0>:    push   ebp  
  2.    0x08048405 <+1>:   mov    ebp,esp  
  3.    0x08048407 <+3>:   push   ebx  
  4.    0x08048408 <+4>:   sub    esp,0x24  
  5. => 0x0804840b <+7>:    mov    eax,0x1  
  6.    0x08048410 <+12>:  mov    ebx,0x2  
  7.    0x08048415 <+17>:  add    eax,ebx  
  8.    0x08048417 <+19>:  mov    ebx,eax  
  9.    0x08048419 <+21>:  mov    DWORD PTR [ebp-0xc],ebx  
  10.    0x0804841c <+24>:  mov    eax,0x8048510  
  11.    0x08048421 <+29>:  mov    edx,DWORD PTR [ebp-0xc]  
  12.    0x08048424 <+32>:  mov    DWORD PTR [esp+0x4],edx  
  13.    0x08048428 <+36>:  mov    DWORD PTR [esp],eax  
  14.    0x0804842b <+39>:  call   0x8048340 <printf@plt>  
  15.    0x08048430 <+44>:  add    esp,0x24  
  16.    0x08048433 <+47>:  pop    ebx  
  17.    0x08048434 <+48>:  pop    ebp  
  18.    0x08048435 <+49>:  ret      

上面的匯編是在調(diào)試運(yùn)行到assemble_func函數(shù)的開(kāi)始時(shí),使用disassemble命令得到的數(shù)據(jù)。注意第五行左側(cè)的箭頭符號(hào)是調(diào)試狀態(tài)顯示正在運(yùn)行的行數(shù)。


Q: 上面的匯編是內(nèi)嵌到c代碼中的,單獨(dú)完全的匯編代碼,如何實(shí)現(xiàn)hello world的功能?

A: 從本質(zhì)上說(shuō),只用匯編的形式需要對(duì)于底層更了解,c代碼從編譯的角度來(lái)說(shuō)和匯編沒(méi)什么區(qū)別,只是寫(xiě)的格式以及調(diào)用的東西看起來(lái)不一致罷了。

如下,是實(shí)現(xiàn)標(biāo)準(zhǔn)控制臺(tái)輸出功能的代碼:

  1. .section .rodata  
  2. str:  
  3. .ascii "Hello,world.\n"  
  4.   
  5. .section .text  
  6. .globl _main  
  7. _main:  
  8. movl  $4,    %eax    # the number of system call   
  9. movl  $1,    %ebx    # file descriptor, 1 means stdout  
  10. movl  $str,  %ecx    # string address  
  11. movl  $13,   %edx    # string length  
  12. int   $0x80  

保存為hello.s.


Q: 如何編譯它,使用gcc嗎?

A: 當(dāng)然可以,不過(guò)這個(gè)文件顯然不需要預(yù)處理了,它已經(jīng)是匯編格式了,不需要單純狹義的編譯過(guò)程了,只需要從匯編過(guò)程開(kāi)始了。

它可以直接生成目標(biāo)文件hello.o


Q: 接下來(lái)做什么?可以直接執(zhí)行它嗎?

A: 試試。


此時(shí),給hello.o添加可執(zhí)行權(quán)限再執(zhí)行:


Q: 這是為什么?

A: 繼續(xù)觀察hello.o文件的屬性。

可以看出,它還不是可執(zhí)行文件。其實(shí)很簡(jiǎn)單,hello.o只是目標(biāo)文件,并沒(méi)有鏈接成可執(zhí)行文件。


Q: 這又是為什么?沒(méi)有找到入口符號(hào)_start, ld默認(rèn)的入口符號(hào)是_start?

A: 是的。在代碼中使用的是_main, 所以應(yīng)該讓鏈接器明白,入口符號(hào)是_main.


Q: 現(xiàn)在應(yīng)該可以運(yùn)行了吧。運(yùn)行一下:

Hello,world是輸出了,為什么后面會(huì)出現(xiàn)段錯(cuò)誤呢?

A: 我們首先看看上面的運(yùn)行返回了什么。

返回值為139,它代表什么?


Q: 從系統(tǒng)的errno.h頭文件以及相關(guān)文件中查找,得到所有系統(tǒng)錯(cuò)誤碼:

/usr/include/asm-generic/errno-base.h文件:

  1. #ifndef _ASM_GENERIC_ERRNO_BASE_H  
  2. #define _ASM_GENERIC_ERRNO_BASE_H  
  3.   
  4. #define EPERM        1  /* Operation not permitted */  
  5. #define ENOENT       2  /* No such file or directory */  
  6. #define ESRCH        3  /* No such process */  
  7. #define EINTR        4  /* Interrupted system call */  
  8. #define EIO      5  /* I/O error */  
  9. #define ENXIO        6  /* No such device or address */  
  10. #define E2BIG        7  /* Argument list too long */  
  11. #define ENOEXEC      8  /* Exec format error */  
  12. #define EBADF        9  /* Bad file number */  
  13. #define ECHILD      10  /* No child processes */  
  14. #define EAGAIN      11  /* Try again */  
  15. #define ENOMEM      12  /* Out of memory */  
  16. #define EACCES      13  /* Permission denied */  
  17. #define EFAULT      14  /* Bad address */  
  18. #define ENOTBLK     15  /* Block device required */  
  19. #define EBUSY       16  /* Device or resource busy */  
  20. #define EEXIST      17  /* File exists */  
  21. #define EXDEV       18  /* Cross-device link */  
  22. #define ENODEV      19  /* No such device */  
  23. #define ENOTDIR     20  /* Not a directory */  
  24. #define EISDIR      21  /* Is a directory */  
  25. #define EINVAL      22  /* Invalid argument */  
  26. #define ENFILE      23  /* File table overflow */  
  27. #define EMFILE      24  /* Too many open files */  
  28. #define ENOTTY      25  /* Not a typewriter */  
  29. #define ETXTBSY     26  /* Text file busy */  
  30. #define EFBIG       27  /* File too large */  
  31. #define ENOSPC      28  /* No space left on device */  
  32. #define ESPIPE      29  /* Illegal seek */  
  33. #define EROFS       30  /* Read-only file system */  
  34. #define EMLINK      31  /* Too many links */  
  35. #define EPIPE       32  /* Broken pipe */  
  36. #define EDOM        33  /* Math argument out of domain of func */  
  37. #define ERANGE      34  /* Math result not representable */  
  38.   
  39. #endif  


/usr/include/asm-generic/errno.h文件:

  1. #ifndef _ASM_GENERIC_ERRNO_H  
  2. #define _ASM_GENERIC_ERRNO_H  
  3.   
  4. #include <asm-generic/errno-base.h>  
  5.   
  6. #define EDEADLK     35  /* Resource deadlock would occur */  
  7. #define ENAMETOOLONG    36  /* File name too long */  
  8. #define ENOLCK      37  /* No record locks available */  
  9. #define ENOSYS      38  /* Function not implemented */  
  10. #define ENOTEMPTY   39  /* Directory not empty */  
  11. #define ELOOP       40  /* Too many symbolic links encountered */  
  12. #define EWOULDBLOCK EAGAIN  /* Operation would block */  
  13. #define ENOMSG      42  /* No message of desired type */  
  14. #define EIDRM       43  /* Identifier removed */  
  15. #define ECHRNG      44  /* Channel number out of range */  
  16. #define EL2NSYNC    45  /* Level 2 not synchronized */  
  17. #define EL3HLT      46  /* Level 3 halted */  
  18. #define EL3RST      47  /* Level 3 reset */  
  19. #define ELNRNG      48  /* Link number out of range */  
  20. #define EUNATCH     49  /* Protocol driver not attached */  
  21. #define ENOCSI      50  /* No CSI structure available */  
  22. #define EL2HLT      51  /* Level 2 halted */  
  23. #define EBADE       52  /* Invalid exchange */  
  24. #define EBADR       53  /* Invalid request descriptor */  
  25. #define EXFULL      54  /* Exchange full */  
  26. #define ENOANO      55  /* No anode */  
  27. #define EBADRQC     56  /* Invalid request code */  
  28. #define EBADSLT     57  /* Invalid slot */  
  29.   
  30. #define EDEADLOCK   EDEADLK  
  31.   
  32. #define EBFONT      59  /* Bad font file format */  
  33. #define ENOSTR      60  /* Device not a stream */  
  34. #define ENODATA     61  /* No data available */  
  35. #define ETIME       62  /* Timer expired */  
  36. #define ENOSR       63  /* Out of streams resources */  
  37. #define ENONET      64  /* Machine is not on the network */  
  38. #define ENOPKG      65  /* Package not installed */  
  39. #define EREMOTE     66  /* Object is remote */  
  40. #define ENOLINK     67  /* Link has been severed */  
  41. #define EADV        68  /* Advertise error */  
  42. #define ESRMNT      69  /* Srmount error */  
  43. #define ECOMM       70  /* Communication error on send */  
  44. #define EPROTO      71  /* Protocol error */  
  45. #define EMULTIHOP   72  /* Multihop attempted */  
  46. #define EDOTDOT     73  /* RFS specific error */  
  47. #define EBADMSG     74  /* Not a data message */  
  48. #define EOVERFLOW   75  /* Value too large for defined data type */  
  49. #define ENOTUNIQ    76  /* Name not unique on network */  
  50. #define EBADFD      77  /* File descriptor in bad state */  
  51. #define EREMCHG     78  /* Remote address changed */  
  52. #define ELIBACC     79  /* Can not access a needed shared library */  
  53. #define ELIBBAD     80  /* Accessing a corrupted shared library */  
  54. #define ELIBSCN     81  /* .lib section in a.out corrupted */  
  55. #define ELIBMAX     82  /* Attempting to link in too many shared libraries */  
  56. #define ELIBEXEC    83  /* Cannot exec a shared library directly */  
  57. #define EILSEQ      84  /* Illegal byte sequence */  
  58. #define ERESTART    85  /* Interrupted system call should be restarted */  
  59. #define ESTRPIPE    86  /* Streams pipe error */  
  60. #define EUSERS      87  /* Too many users */  
  61. #define ENOTSOCK    88  /* Socket operation on non-socket */  
  62. #define EDESTADDRREQ    89  /* Destination address required */  
  63. #define EMSGSIZE    90  /* Message too long */  
  64. #define EPROTOTYPE  91  /* Protocol wrong type for socket */  
  65. #define ENOPROTOOPT 92  /* Protocol not available */  
  66. #define EPROTONOSUPPORT 93  /* Protocol not supported */  
  67. #define ESOCKTNOSUPPORT 94  /* Socket type not supported */  
  68. #define EOPNOTSUPP  95  /* Operation not supported on transport endpoint */  
  69. #define EPFNOSUPPORT    96  /* Protocol family not supported */  
  70. #define EAFNOSUPPORT    97  /* Address family not supported by protocol */  
  71. #define EADDRINUSE  98  /* Address already in use */  
  72. #define EADDRNOTAVAIL   99  /* Cannot assign requested address */  
  73. #define ENETDOWN    100 /* Network is down */  
  74. #define ENETUNREACH 101 /* Network is unreachable */  
  75. #define ENETRESET   102 /* Network dropped connection because of reset */  
  76. #define ECONNABORTED    103 /* Software caused connection abort */  
  77. #define ECONNRESET  104 /* Connection reset by peer */  
  78. #define ENOBUFS     105 /* No buffer space available */  
  79. #define EISCONN     106 /* Transport endpoint is already connected */  
  80. #define ENOTCONN    107 /* Transport endpoint is not connected */  
  81. #define ESHUTDOWN   108 /* Cannot send after transport endpoint shutdown */  
  82. #define ETOOMANYREFS    109 /* Too many references: cannot splice */  
  83. #define ETIMEDOUT   110 /* Connection timed out */  
  84. #define ECONNREFUSED    111 /* Connection refused */  
  85. #define EHOSTDOWN   112 /* Host is down */  
  86. #define EHOSTUNREACH    113 /* No route to host */  
  87. #define EALREADY    114 /* Operation already in progress */  
  88. #define EINPROGRESS 115 /* Operation now in progress */  
  89. #define ESTALE      116 /* Stale NFS file handle */  
  90. #define EUCLEAN     117 /* Structure needs cleaning */  
  91. #define ENOTNAM     118 /* Not a XENIX named type file */  
  92. #define ENAVAIL     119 /* No XENIX semaphores available */  
  93. #define EISNAM      120 /* Is a named type file */  
  94. #define EREMOTEIO   121 /* Remote I/O error */  
  95. #define EDQUOT      122 /* Quota exceeded */  
  96.   
  97. #define ENOMEDIUM   123 /* No medium found */  
  98. #define EMEDIUMTYPE 124 /* Wrong medium type */  
  99. #define ECANCELED   125 /* Operation Canceled */  
  100. #define ENOKEY      126 /* Required key not available */  
  101. #define EKEYEXPIRED 127 /* Key has expired */  
  102. #define EKEYREVOKED 128 /* Key has been revoked */  
  103. #define EKEYREJECTED    129 /* Key was rejected by service */  
  104.   
  105. /* for robust mutexes */  
  106. #define EOWNERDEAD  130 /* Owner died */  
  107. #define ENOTRECOVERABLE 131 /* State not recoverable */  
  108.   
  109. #define ERFKILL     132 /* Operation not possible due to RF-kill */  
  110.   
  111. #endif  

就是沒(méi)有找到139.

A: 看來(lái),系統(tǒng)已經(jīng)發(fā)生一些詭異的情況,錯(cuò)誤碼已經(jīng)不正確了。為了確定139錯(cuò)誤碼確實(shí)不存在,我們?cè)?usr/include目錄下遞歸搜索139這個(gè)字符。

  1. grep -R '139' *  

結(jié)果比較長(zhǎng),這里不列出來(lái)來(lái)。依然沒(méi)有能找到系統(tǒng)對(duì)應(yīng)的139錯(cuò)誤定義。

那么,我們來(lái)看看系統(tǒng)日志吧,到底哪里可能有問(wèn)題。


Q: 使用如下命令得到了錯(cuò)誤信息:

最后的地方確實(shí)看到hello應(yīng)用程序運(yùn)行錯(cuò)誤的系統(tǒng)日志。應(yīng)該是指針訪問(wèn)出錯(cuò)。原因是否是匯編代碼大最后沒(méi)有恰當(dāng)?shù)卦O(shè)置堆棧寄存器等寄存器的值呢?

A: 在這里,很有可能。為了更容易看出問(wèn)題可能在哪里,寫(xiě)一個(gè)類似功能的c代碼,得到它的匯編代碼,和上面的匯編代碼進(jìn)行比較。


Q: 寫(xiě)了如下的hello_1.c代碼如下:

  1. #include <stdio.h>  
  2.   
  3. int main()  
  4. {  
  5.     printf("Hello,world!\n");  
  6.     return 0;  
  7. }  
查看它的匯編代碼:
  1.     .file   "hello_1.c"  
  2.     .section    .rodata  
  3. .LC0:  
  4.     .string "Hello,world!"  
  5.     .text  
  6. .globl main  
  7.     .type   main, @function  
  8. main:  
  9.     pushl   %ebp  
  10.     movl    %esp, %ebp  
  11.     andl    $-16, %esp  
  12.     subl    $16, %esp  
  13.     movl    $.LC0, (%esp)  
  14.     call    puts  
  15.     movl    $0, %eax  
  16.     leave  
  17.     ret  
  18.     .size   main, .-main  
  19.     .ident  "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"  
  20.     .section    .note.GNU-stack,"",@progbits  

果然,和hello.s代碼確實(shí)有不一樣。這里,開(kāi)始執(zhí)行時(shí)對(duì)ebp, esp進(jìn)行了處理,最后使用了leave和ret命令。就是它們引起的嗎?

A: 不過(guò)在實(shí)際中,不管是加入pushl  %ebp之類代碼,還是加入leave, ret指令,最終執(zhí)行依然是段錯(cuò)誤。這個(gè)地方筆者一直沒(méi)明白,如果有誰(shuí)知道的,希望能不吝賜教。不過(guò),可以調(diào)用exit系統(tǒng)調(diào)用實(shí)現(xiàn)結(jié)束應(yīng)用程序,這樣就不會(huì)出現(xiàn)段錯(cuò)誤。如下:

  1. .section .rodata  
  2. str:  
  3. .ascii "Hello,world.\n"  
  4.   
  5. .section .text  
  6. .globl _main  
  7. _main:  
  8.   
  9. movl  $4,    %eax    # the number of system call   
  10. movl  $1,    %ebx    # file descriptor, 1 means stdout  
  11. movl  $str,  %ecx    # string address  
  12. movl  $13,   %edx    # string length  
  13. int   $0x80  
  14.   
  15. movl  $1,    %eax  
  16. movl  $0,    %ebx  
  17. int   $0x80  

運(yùn)行結(jié)果:


Q: 進(jìn)行0x80軟中斷進(jìn)行系統(tǒng)調(diào)用,參數(shù)在哪里保存,就在上面寫(xiě)的寄存器里面嗎?

A: 是的。linux下,功能號(hào)和返回值在eax中保存,參數(shù)一般在5個(gè)以下,就按照ebx, ecx, edx, esi, edi來(lái)傳遞,如果參數(shù)過(guò)多,就會(huì)使用堆棧??梢钥吹缴厦鎯纱蜗到y(tǒng)調(diào)用,均是在使用ebx, ecx, edx這些寄存器。


Q: 4號(hào)系統(tǒng)調(diào)用是什么?在哪里能知道?

A: 可以在/usr/include/asm/unistd_32.h或者/usr/include/asm/unistd_64.h中看到平臺(tái)所有系統(tǒng)調(diào)用,下面為unistd_32.h文件中開(kāi)始一部分:

  1. #define __NR_restart_syscall      0  
  2. #define __NR_exit         1  
  3. #define __NR_fork         2  
  4. #define __NR_read         3  
  5. #define __NR_write        4  
  6. #define __NR_open         5  
  7. #define __NR_close        6  
  8. #define __NR_waitpid          7  
  9. #define __NR_creat        8  
  10. #define __NR_link         9  
  11. #define __NR_unlink      10  
  12. #define __NR_execve      11  
  13. #define __NR_chdir       12  
  14. #define __NR_time        13  
  15. #define __NR_mknod       14  
  16. #define __NR_chmod       15  
  17. #define __NR_lchown      16  
  18. #define __NR_break       17  

可以看到,1號(hào)系統(tǒng)調(diào)用為exit, 4號(hào)為write, 正是上面代碼使用的。


Q: 匯編如何調(diào)用c庫(kù)函數(shù)?

A: 使用call指令,不過(guò)調(diào)用前要傳好參數(shù)。如下代碼,調(diào)用c庫(kù)printf函數(shù):

  1. .section .rodata  
  2. str:  
  3. .ascii "Hello,world.\n"  
  4.   
  5. .section .text  
  6. .globl main  
  7. main:  
  8.   
  9. pushl   $str  
  10. call    printf  
  11.   
  12. pushl   $0  
  13. call    exit  

保存為printf.s, 編譯:

運(yùn)行:


Q: 可以使用as, ld來(lái)匯編以及鏈接嗎?

A: 可以的。不過(guò)需要注意,因?yàn)樗褂胏庫(kù),需要指定鏈接c庫(kù):  -lc;


Q:  乘法運(yùn)算mul后面只跟著一個(gè)數(shù),另一個(gè)數(shù)存哪里?

A: 另一個(gè)數(shù)存儲(chǔ)在al, ax或者eax寄存器中,這取決于使用的是mulb, mulw還是mull指令。結(jié)果將按照高位到地位的順序保存在dx和ax中。

同理,除法運(yùn)算div后面也只跟一個(gè)除數(shù),被除數(shù)保存在ax, dx:ax或者edx:eax中。除數(shù)的最大長(zhǎng)度只能是被除數(shù)的一半。商和余數(shù)將根據(jù)被除數(shù)占用大小來(lái)確定:

如果被除數(shù)在ax中,商在al, 余數(shù)在ah; 如果被除數(shù)在eax中,商在ax, 余數(shù)在dx; 如果被除數(shù)在edx:eax中,商在eax, 余數(shù)在edx.

如下是測(cè)試代碼:

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)       printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)              printf(#str" is %s\n", (str));  
  6.   
  7.   
  8. static void assemble_func()  
  9. {  
  10.     int result_high, result_low;  
  11.     short result, remainder;  
  12.   
  13.    // mul  
  14.     __asm__("mov $10, %eax");  
  15.     __asm__("mov $10, %ebx");  
  16.     __asm__("mull %ebx");  
  17.     __asm__("mov %%edx, %0":"=r"(result_high));  
  18.     __asm__("mov %%eax, %0":"=r"(result_low));  
  19.     PRINT_D(result_high)  
  20.     PRINT_D(result_low)  
  21.   
  22.     // div  
  23.     __asm__("mov $0,   %dx");  
  24.     __asm__("mov $100, %ax");   // the divident is dx:ax  
  25.     __asm__("mov $9,  %bx");  
  26.     __asm__("div %bx");         // the divisor is bx  
  27.     __asm__("movw %%ax, %0":"=r"(result));  
  28.     __asm__("movw %%dx, %0":"=r"(remainder));  
  29.     PRINT_D(result)  
  30.     PRINT_D(remainder)  
  31. }  
  32.   
  33. int main()  
  34. {  
  35.     assemble_func();  
  36.     return 0;  
  37. }  

輸出結(jié)果:

  1. result_high is 0  
  2. result_low is 100  
  3. result is 11  
  4. remainder is 1  


Q:  對(duì)于數(shù)據(jù)比較指令cmp,它是如何配合jmp相關(guān)的指令?

A:  cmp指令將進(jìn)行兩個(gè)數(shù)據(jù)的差計(jì)算,如果得到的是0,jz成立; 如果不是0, jnz成立。如下例子:

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)      printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)          printf(#str" is %s\n", (str));  
  6. #define PRINT(str)              printf(#str"\n");  
  7.   
  8.   
  9. static void assemble_func()  
  10. {  
  11.     __asm__("mov $10, %eax");  
  12.     __asm__("cmp $10, %eax ");  
  13.     __asm__("jz  end");  
  14.     PRINT("below jz")  
  15.     __asm__("end:");  
  16.     PRINT("the end")  
  17.   
  18. }  
  19.   
  20. int main()  
  21. {  
  22.     assemble_func();  
  23.     return 0;  
  24. }  

顯然,jz會(huì)成立,輸出如下:

  1. "the end"  

Q: 對(duì)于某些時(shí)候,加法可能導(dǎo)致溢出,如何判斷出來(lái)?

A: CPU內(nèi)部有一個(gè)寄存器,它內(nèi)部會(huì)保存溢出標(biāo)志位OF, 可以通過(guò)jo或者jno判斷。

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)      printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)          printf(#str" is %s\n", (str));  
  6. #define PRINT(str)              printf(#str"\n");  
  7.   
  8.   
  9. static void assemble_func()  
  10. {  
  11.     __asm__("movw   $0x7FFF,  %ax");  
  12.     __asm__("movw   $0x7FFF,  %bx");  
  13.     __asm__("addw   %bx,      %ax");  
  14.   
  15.     __asm__("jo     overflow_set");  
  16.   
  17.     __asm__("movl   $1,       %eax");  
  18.     __asm__("movl   $0,       %ebx");  
  19.     __asm__("int    $0x80");  
  20.   
  21.     __asm__("overflow_set:");  
  22.     PRINT("overflow flag is set...")  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     assemble_func();  
  28.     return 0;  
  29. }  

運(yùn)行結(jié)果:

  1. "overflow flag is set..."  

Q: 對(duì)于溢出,到底應(yīng)該判斷?

A: 以加法舉例,如果兩個(gè)相同符號(hào)的數(shù)相加得到的結(jié)果符號(hào)相反,那么一定溢出了。


Q: OF和CF標(biāo)志位有什么區(qū)別?

A: CF代表進(jìn)位標(biāo)志。進(jìn)位不一定是溢出,比如有符號(hào)整形最小值加1,雖然進(jìn)位,但是沒(méi)溢出。因?yàn)橛?jì)算機(jī)補(bǔ)碼的理論允許進(jìn)位,但是結(jié)果卻正確。

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)      printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)          printf(#str" is %s\n", (str));  
  6. #define PRINT(str)              printf(#str"\n");  
  7.   
  8.   
  9. static void assemble_func()  
  10. {  
  11.     __asm__("movw   $0xFFFF,  %ax");  
  12.     __asm__("movw   $0x1,  %bx");  
  13.     __asm__("addw   %bx,      %ax");  
  14.   
  15.     __asm__("je     carry_set");  
  16.   
  17.     __asm__("movl   $1,       %eax");  
  18.     __asm__("movl   $0,       %ebx");  
  19.     __asm__("int    $0x80");  
  20.   
  21.     __asm__("carry_set:");  
  22.     PRINT("carry flag is set...")  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     assemble_func();  
  28.     return 0;  
  29. }  

運(yùn)行結(jié)果:

  1. "carry flag is set..."  

當(dāng)然,我們可以用jo來(lái)測(cè)試上面的加法是否溢出。

  1. #include <stdio.h>  
  2. #include <string.h>  
  3.   
  4. #define PRINT_D(longValue)      printf(#longValue" is %ld\n", ((long)longValue));  
  5. #define PRINT_STR(str)          printf(#str" is %s\n", (str));  
  6. #define PRINT(str)              printf(#str"\n");  
  7.   
  8.   
  9. static void assemble_func()  
  10. {  
  11.     __asm__("movw   $0xFFFF,  %ax");  
  12.     __asm__("movw   $0x1,  %bx");  
  13.     __asm__("addw   %bx,      %ax");  
  14.   
  15.     __asm__("jo     overflow_set");  
  16.   
  17.     __asm__("movl   $1,       %eax");  
  18.     __asm__("movl   $0,       %ebx");  
  19.     __asm__("int    $0x80");  
  20.   
  21.     __asm__("overflow_set:");  
  22.     PRINT("overflow flag is set...")  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.     assemble_func();  
  28.     return 0;  
  29. }  

執(zhí)行結(jié)果:


它什么也沒(méi)輸出,這就意味著OF沒(méi)有被置位。


作者:陳曦

日期:2012-6-8 10:50:13

環(huán)境:[Ubuntu 11.04  Intel-based x64 gcc4.5.2  CodeBlocks10.05  AT&T匯編  Intel匯編] 

轉(zhuǎn)載請(qǐng)注明出處


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多