cpuid.s代码如下:
.section .data output: .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n" .section .text .global _start _start: movl $0, %eax cpuid movl $output, %edi movl %ebx, 28(%edi) movl %edx, 32(%edi) movl %ecx, 36(%edi) movl $4, %eax movl $1, %ebx movl $output, %ecx movl $42,%edx int $0x80 movl $1,%eax movl $0,%ebx int $0x80首先在数据段,添加了一个string字符串。
.section .data output: .ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n".ascii说明字符串是ascii码 其中的xx是符号用于后面的字符替换
接下来这三行可以看作是汇编程序的一个模板
.section .text .global _start _start:声明了代码段以及程序的入口
接下来
movl $0, %eax cpuid将0存入了eax寄存器中,这个0代表获取CPUID的参数
EAX值CPUID 输出0显示卖家ID的字符串1处理器的类型 家族等等信息2处理起的缓存信息3处理器的序列号4缓存配置5监控信息80000000h显示 额外的卖家ID字符串80000001h显示额外的处理器的类型 家族等等信息80000002h-80000004h显示额外的处理器名字的字符串接下来运行完CPUID之后,需要收集返回值,返回值存在了3个寄存器中
movl $output, %edi movl %ebx, 28(%edi) movl %edx, 32(%edi) movl %ecx, 36(%edi) movl $4, %eax movl $1, %ebx movl $output, %ecx movl $42,%edx int $0x80EAX 包含了系统调用的值 EBX 包含了要写入的文件描述符 ECX 包含了字符串的起始位置 EDX 包含了字符串的长度
如果你需要对汇编程序进行调试的话,就需要在编译的时候增加调试的选项,即增加-gstabs选项。
as -gstabs -o cpuid.o cpuid.s ld -o cpuid cpuid.o接着使用gdb 进行调试
$ gdb cpuid GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-119.el7 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-redhat-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from /home/code/at/cpuid...done. (gdb)在gdb中使用run命令
(gdb) run Starting program: /home/code/at/cpuid The processor Vendor ID is 'GenuineIntel' [Inferior 1 (process 17829) exited normally] (gdb)可以看到,当输入run命令后,程序立即执行完毕了,为了让程序停止在某一个过程,就需要设置断点。
打断点可以参考下面的格式
break *label+offset例如我们让程序停在第一行
(gdb) break *_start Note: breakpoint 1 also set at pc 0x4000b0. Breakpoint 2 at 0x4000b0: file cpuid.s, line 7. (gdb) r Starting program: /home/code/at/cpuid Breakpoint 1, _start () at cpuid.s:7 7 movl $0, %eax (gdb)通过打上断点,我们发现程序没有继续往下执行,停留在了第7行中 可以使用next或者step命令进行单步执行
(gdb) next 8 cpuid (gdb) next 9 movl $output, %edi (gdb) step 10 movl %ebx, 28(%edi) (gdb) step 11 movl %edx, 32(%edi) (gdb)使用cont命令使得程序继续执行
(gdb) cont Continuing. The processor Vendor ID is 'GenuineIntel' [Inferior 1 (process 17889) exited normally]程序刚刚运行时,EBX,ECX和EDX寄存器存储的值都是0。当运行cpuid指令之后,它们就存储了CPU卖家的ID 字符串。
如果使用print命令进行打印那么: print/d 可以以数字的形式显示 print/t 可以以二进制的形式显示 print/x 可以以十六进制的形式显示
如果使用x命令查看内存,可以使用如下的格式
格式: x /nfu <addr>说明: x 是 examine 的缩写
n表示要显示的内存单元的个数
f表示显示方式, 可取如下值 x 按十六进制格式显示变量。 d 按十进制格式显示变量。 u 按十进制格式显示无符号整型。 o 按八进制格式显示变量。 t 按二进制格式显示变量。 a 按十六进制格式显示变量。 i 指令地址格式 c 按字符格式显示变量。 f 按浮点数格式显示变量。
u表示一个地址单元的长度 b表示单字节, h表示双字节, w表示四字节, g表示八字节
(gdb) break *_start Breakpoint 1 at 0x4000b0: file cpuid.s, line 7. (gdb) run Starting program: /home/code/at/cpuid Breakpoint 1, _start () at cpuid.s:7 7 movl $0, %eax (gdb) next 8 cpuid (gdb) next 9 movl $output, %edi (gdb) next 10 movl %ebx, 28(%edi) (gdb) next 11 movl %edx, 32(%edi) (gdb) next 12 movl %ecx, 36(%edi) (gdb) next 13 movl $4, %eax (gdb) x/42cb &output 0x6000ea: 84 'T' 104 'h' 101 'e' 32 ' ' 112 'p' 114 'r' 111 'o' 99 'c' 0x6000f2: 101 'e' 115 's' 115 's' 111 'o' 114 'r' 32 ' ' 86 'V' 101 'e' 0x6000fa: 110 'n' 100 'd' 111 'o' 114 'r' 32 ' ' 73 'I' 68 'D' 32 ' ' 0x600102: 105 'i' 115 's' 32 ' ' 39 '\'' 71 'G' 101 'e' 110 'n' 117 'u' 0x60010a: 105 'i' 110 'n' 101 'e' 73 'I' 110 'n' 116 't' 101 'e' 108 'l' 0x600112: 39 '\'' 10 '\n'