汇编语句中定义变量

  • GAS(GNU Assembler)

    • 设计目标:GAS 是 GNU 工具链的一部分,设计用于与 GNU 编译器集合(GCC)紧密集成。它支持多种平台和处理器架构,包括 x86、ARM、MIPS 等。
    • 使用场景:主要用于与 GCC 一起使用,编写嵌入式系统、操作系统内核、以及其他需要与 GCC 集成的低级编程任务。它的设计使得它适合与 GNU 工具链中的其他工具(如 ld 链接器)一起使用。
  • NASM(Netwide Assembler)

    • 设计目标:NASM 是一个专注于 x86 和 x86-64 架构的汇编器,设计简单,语法直观。它强调与现代汇编语言语法的一致性,并提供了丰富的宏功能。
    • 使用场景:适用于需要对 x86 架构进行细粒度控制的任务,如编写操作系统、引导程序、以及其他需要直接控制硬件的低级编程。它可以单独使用,也可以与不同的工具链一起使用(如使用 ld 链接器或其他链接器)。

GNU 汇编器(GAS)和 NASM 汇编器在定义变量和数据的方式上有一些重要的区别。以下是这两种汇编器在定义变量时的一些主要区别:

1. 数据段(Section)

  • GNU 汇编器(GAS) 使用 .data, .bss, 和 .rodata 段来定义数据。
  • NASM 汇编器 使用 section .data, section .bss, 和 section .rodata 来定义数据。
示例:定义数据段

GAS

.section .data
my_var: .long 0x12345678  ; 定义一个32位整数

.section .bss
uninit_var: .skip 4       ; 预留4字节空间

NASM

section .data
my_var dd 0x12345678      ; 定义一个32位整数

section .bss
uninit_var resb 4         ; 预留4字节空间

2. 数据定义伪指令

  • GNU 汇编器(GAS) 使用 .byte, .short, .long, .quad, .fill 等伪指令。
  • NASM 汇编器 使用 db, dw, dd, dq, resb, resw, resd, resq 等指令。
示例:定义数据

GAS

.section .data
byte_var: .byte 0x1       ; 定义一个字节
short_var: .short 0x1234  ; 定义一个16位整数
long_var: .long 0x12345678 ; 定义一个32位整数

NASM

section .data
byte_var db 0x1           ; 定义一个字节
short_var dw 0x1234       ; 定义一个16位整数
long_var dd 0x12345678    ; 定义一个32位整数

3. 未初始化数据

  • GNU 汇编器(GAS) 使用 .bss 段来定义未初始化的数据。
  • NASM 汇编器 使用 section .bssresb, resw, resd, resq 来预留空间。
示例:未初始化数据

GAS

.section .bss
buffer: .skip 1024         ; 预留1024字节的空间

NASM

section .bss
buffer resb 1024           ; 预留1024字节的空间

4. 只读数据

  • GNU 汇编器(GAS) 使用 .rodata 段来定义只读数据。
  • NASM 汇编器 也使用 section .rodata 来定义只读数据。
示例:只读数据

GAS

.section .rodata
message: .asciz "Hello, World!"  ; 定义一个以0结尾的字符串

NASM

section .rodata
message db 'Hello, World!', 0    ; 定义一个以0结尾的字符串

5. 符号导出

  • GNU 汇编器(GAS) 使用 .global 指令将符号声明为全局。
  • NASM 汇编器 使用 global 指令将符号声明为全局。
示例:定义全局符号

GAS

.section .data
.global my_var
my_var: .long 0x12345678

NASM

section .data
global my_var
my_var dd 0x12345678

总结

  • 数据段声明:GAS 使用 .section,NASM 使用 section
  • 数据定义伪指令:GAS 使用 .byte, .short, .long, .fill,NASM 使用 db, dw, dd, resb 等。
  • 未初始化数据:GAS 使用 .bss,NASM 使用 section .bssresb, resw, resd, resq
  • 只读数据:GAS 使用 .rodata,NASM 使用 section .rodata
  • 全局符号:GAS 使用 .global,NASM 使用 global

GAS示例代码:

linkage.h

#ifndef _LINUX_LINKAGE_H
#define _LINUX_LINKAGE_H

#define ENTRY(name) \
  .globl name; \
  ALIGN; \
  name:

#endif

start.S

.text
#include "linkage.h"

.section ".data.pg_dir","w"
ENTRY(swapper_pg_dir)
    .long 100
    .fill 1023,4,0

main.c

#include <stdio.h>

// 声明swapper_pg_dir符号,它在外部定义
extern unsigned int swapper_pg_dir[];

int main() {
    // 输出swapper_pg_dir的地址
    printf("Address of swapper_pg_dir: %p\n", swapper_pg_dir);
    // 访问swapper_pg_dir中的第一个值(应该是0)
    printf("First value in swapper_pg_dir: %u\n", swapper_pg_dir[0]);
    return 0;
}

gcc -c start.S -o start.o
gcc -c main.c -o main.o
gcc start.o main.o -o test

 执行结果:

./test
Address of swapper_pg_dir: 0x55e20ee01010
First value in swapper_pg_dir: 100

代码解释

.section ".data.pg_dir","w"
.globl swapper_pg_dir
swapper_pg_dir:
    .long 100
    .fill 1023,4,0
1. .section ".data.pg_dir","w"
  • .section:这条伪指令指定当前段的名称为 .data.pg_dir,并且该段是可写的("w")。如果你使用 ".data" 作为段名,它将是 .data 段的一个变体,但在此示例中,.data.pg_dir 是一个自定义段名。
  • .data 段通常用于已初始化的数据,但自定义名称可以用于组织不同类型的数据。
2. .globl swapper_pg_dir
  • .globl:这条伪指令将 swapper_pg_dir 符号声明为全局符号,使其可以在其他文件或模块中引用。
3. swapper_pg_dir:
  • swapper_pg_dir::定义了一个标签 swapper_pg_dir,用于在内存中标识数据的开始位置。
4. .long 100
  • .long:将一个32位的整数 100 存储在 swapper_pg_dir 标签所在的内存位置。
5. .fill 1023,4,0
  • .fill:用于在内存中填充数据。
    • 1023:填充的数量,即填充 1023 个 4 字节(总共 4092 字节)的数据。
    • 4:每个填充项的大小,以字节为单位,这里是 4 字节。
    • 0:填充的值,这里是 0。
  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值