AT&T x86_32 汇编_003_数据段

Posted neooelric

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AT&T x86_32 汇编_003_数据段相关的知识,希望对你有一定的参考价值。

以上两节讲解了两个简单的示例程序, 从这一节开始, 就要接触到枯燥的细节了.

1. 在数据段中定义"全局变量"

在前面两讲中, 我们分别以.ascii.asciz, 在数据段定义过字符串数据. 如下这样:

.section .data
output1:
    .ascii "The processor Vendor ID is ‘xxxxxxxxxxxx‘
"

output2:
    .asciz "The processor Vendor ID is ‘%s‘
"

我们可以把output1output2理解为全局变量.

在数据段中定义数据元素需要用到两个语句:

  1. 标签语句. 用以给"变量"起名字, 即是output1:output2:
  2. 命令语句. 用以给"变量"赋值.

数据的本质, 就是内存中的一段连续单元, 那么标签的本质是什么呢?

  1. 标签对cpu是没有意义的, 标签像极了高级语言中的变量名(单指值类型语言), 它本质上是内存区域的一个别名.
  2. 在汇编语言中, 标签是写给程序员看的. 而汇编代码经过编译链接后, 标签就会转换为内存中的地址.

除了标签之外, 还必须定义为数据元素保留多少字节. 保存内存的数量取决于数据的类型, 以及如果是多个重复数据的话, 还有数据的数量.

下面是数据声明命令:

命令 意义
.ascii 文本字符串
.asciz 以结尾的文本字符串
.byte 一个字节
.double 一个双精度浮点数
.float 一个单精度浮点数
.int 32位整数
.long 32位整数
.octa 16(128位)字节整数
.quad 8(64位)字节整数
.short 16位整数
.single 单精度浮点数, 同.float

下面是正确示例:

.section .data
pi:
    .float 3.1415926        # 定义了一个单精度浮点数

sizes:
    .long 100, 150, 200, 250, 300   # 定义了一个数组, 数组中的元素均为32位整数, 数组共有5个元素

按数据段中, 各个标签数据定义的顺序, 各个数据元素将被按顺序存放在内存中. 带有多个值的元素(数组)也按顺序存放.

数据段中除了能够定义"变量"之外, 还能定义"静态符号". 所谓的"静态符号", 可以理解为类似于C语言中"宏值"的概念, 或者C++中"constexpr"的概念. 它不指代内存空间, 只是一个值的别名. 如下:

.section .data

.equ factor, 3
.equ LINUX_SYS_CALL, 0x80

.section .text
.globl _start
_start:
    movl $LINUX_SYS_CALL, %eax      # 实际上等价于 movl $0x80, %eax

2. 在bss段中声明缓冲区变量

C编程中很重要的一个基础技法就是, 做数据操作前先声明一个字符数组做缓冲区, 在读写过程中, 以缓冲区为中介, 暂存数据.

缓冲区的特点主要是:

  1. 一般情况下是一段有限长度的连续内存空间.
  2. 使用前不需要进行初始化

由于缓冲区使用前不需要进行初始化, 也无必要, 所以将缓冲区声明为全局变量或局部静态变量是一个很好的主意: 这种变量默认值为0, 且正因为C的机制使这种变量的初始化值为0, 这种变量在编译链接后的可执行文件中, 位于bss段, 不占用文件空间. bss段的size是为0字节!

我们在上一讲, 使用printf输出cpu厂商信息的示例程序中, 就使用了一个声明了bss段中的缓冲区, 声明尺寸为12字节, 用于暂存厂商的12个字符, 代码片段如下:

.section .bss
    .lcomm buffer 12

需要注意的是, bss段不占空间, 仅是指在程序编译链接后生成的二进制可执行文件中, bss段的长度为0. 但这个bss段依然在文件段表中有自己的段描述符. 并且在文件被操作系统装载, 成为进程后, bss段中声明的所有数据, 都会按照声明的长度在进程内存中占用对应的空间.

"未初始化的全局或局部静态变量"的声明, 和数据段中的"全局变量"声明, 写法不太一样. 变量名不是通过"标签语句"给出的, 而是在lcommcomm命令中给出的. 命令后紧跟变量名, 再跟数据宽度

在bss段中声明变量有两个命令可以使用, 如下:

命令 意义
.comm 声明未初始化的数据的通用内存区域
.lcomm 声明未初始化的数据的本地通用内存区域

语法为: .comm symbol, length, 其中length的单位是字节

.lcomm中的l的含义是local, 即为本地的, 即通过.lcomm声明的变量, 无法被外部文件引用.

以上是关于AT&T x86_32 汇编_003_数据段的主要内容,如果未能解决你的问题,请参考以下文章

AT&T x86_32 汇编_001_一个示例程序.md

AT&T x86_32 汇编_002_使用C库函数

在 x86_64 AT&T 中调用 scanf 时出现分段错误

使用 GNU 汇编器在 x86_64 中调用 printf

x86-64 汇编中的数组元素比较(AT&T 语法)

x86 - 使用内联汇编设置位