标签:
.section .data < initialized data here > .section .bss < uninitialized data here > .section .text .global _start _start: < instruction code >
如上述代码所示,汇编程序通常包含3个段(section):
GNU assembler使用.section语句来声明section。.section语句只带一个参数。
除定义section之外,还需要定义一个起始点。当程序转换成可执行代码时,linker必须知道执行代码的起始点。GNU assembler定义了一个默认的符号(label、identifier): _start。可以不使用_start作为起始点,但是需要在linker中加入-e参数。此外,还需要让该起始点在其他代码中可能看到,这就需要.global指令。
.global指令声明一个符号可以从其他程序中访问,如果你正在些一组需要被其他程序或者C程序访问的工具,那就需要在函数符号前添加.global指令。
1 # cpuid.s Print process Vendor ID, AT&T syntax 2 .section .data 3 output: 4 .ascii "The processor Vendor ID is ‘xxxxxxxxxxxx‘\n" 5 6 .section .text 7 .global _start 8 _start: 9 movl $0, %eax 10 cpuid 11 movl $output, %edi 12 movl %ebx, 28(%edi) 13 movl %edx, 32(%edi) 14 movl %ecx, 36(%edi) 15 movl $4, %eax 16 movl $1, %ebx 17 movl $output, %ecx 18 movl $42, %edx 19 int $0x80 20 movl $1, %eax 21 movl $0, %ebx 22 int $0x80
as -o cpuid.o cpuid.s ld -o cpuid cpuid.o ./cpuid
输出:
The processor Vendor ID is ‘GenuineIntel‘
注意:这里其实可以使用gcc, 但有个问题是GNU linker以_start作为起始点,而gcc会查找main符号。所以其实把代码中的_start改为main,就可以用gcc语句来编译:
.section .text .global main main:
gcc -o cpuid cpuid.s
CPUID 指令一般用于处理器信息,把结果返回到寄存器中。具体如下:
EAX中存放查询码:
EAX值 | CPUID输出 |
0 | Vendor ID string, and maximum CPUID option value suppted |
1 | Processor type, family, model, and stepping information |
2 | Processor cache configuration |
3 | Processor serial number |
4 | Cache configuration(number of threads, cores, and physical properties |
5 | Monitor information |
80000000h | Extended vendor ID string and supported levels |
80000001h | Extended processor type, famlily, model, and stepping information |
80000002h-80000004h | Extended processor name string |
根据EAX的查询码,CPUID会在EBX,ECX,EDX中存放不同的值,以上例中的0为例,即查询vendor string,CPUID会分别在EBX中返回最低的4字节,EDX总返回中间4字节,ECX中返回最高4字节。
linux kernel提供了一组系统调用,要使用这些系统需要使用int指令带一个0x80值来生成一个软中断,具体触发使用什么系统调用,取决于EAX中的值。
以write系统调用为例,EAX存放系统调用码4,EBX包含fd,ECX包含输出字符串起始地址,EDX包含输出字符串长度。
.ascii "The processor Vendor ID is ‘xxxxxxxxxxxx‘\n"
.ascii 用于声明一段ASCII字符串。该字符串会在内存中以output符号标识的内存位置开始存放好。语句中众多‘x‘,只是些placeholder,用于被返回的值替换。
6 .section .text
7 .global _start
8 _start:
这段代码不在赘述,在引言中已经说明过了。
9 movl $0, %eax
10 cpuid
CPUID指令,参见上文。
11 movl $output, %edi
12 movl %ebx, 28(%edi)
13 movl %edx, 32(%edi)
14 movl %ecx, 36(%edi)
edi中存放output的值(指针),把CPUID返回的值依次写到字符串相应的偏移位置中(‘xxxxxxxxxxxx‘)。
15 movl $4, %eax
16 movl $1, %ebx
17 movl $output, %ecx
18 movl $42, %edx
19 int $0x80
write系统调用,向fd 1(stdoutput)写出output。
20 movl $1, %eax
21 movl $0, %ebx
22 int $0x80
系统调用码1(exit),ebx存放程序的退出码。
这段简单程序的结构和语句的含义到此就结束了。这里再记一笔工具链相关的内容,以备来时查用。
as的调试参数: -gstabs
设置断点:可以通过label,源代码行数,变量达到某个具体值,函数执行次数到达某个具体值来设置断点。 用label设置断点的形式为: break *label+offset, 比如, break *_start
查看数据:
info registers | Display the values of registers | |
Display the values of a spefic register or variable form the program |
print/d, print/t, print/x |
|
x | Display the contents of a specific memory location |
x/nyz, (注,符号需要加&, 以表明是内存地址) n is the numberof fields to display, y is the format of the output: c for character, d for decimal, x for hexadecimal z is the size of the field : b for byte, h for 16-bit word(half-word), w for 32-bit world |
Q.E.D.
标签:
原文地址:http://www.cnblogs.com/cudbuc/p/4591118.html