首页 > 解决方案 > 在程序集中初始化变量

问题描述

我正在 i386 Assembly 中编写 Forth 解释器。一些数据需要在开始时初始化,然后作为错误恢复过程的一部分在稍后重新初始化。

我遵循了https://sourceware.org/binutils/docs/ld/Scripts.html中的链接器脚本指南,但它似乎不像描述的那样工作。具体来说,第 3.6.8.2 节讨论了使用 AT 功能以及需要一些初始化代码来复制初始化数据。但是,当我运行我的程序时,数据似乎已经初始化(没有副本),所以我不知道如何重新初始化它。

我已经用以下内容重现了这个问题......

我有一个汇编程序my.S

    .text
_start: 
    cld
    mov     $_etext,%esi
    mov     $_data,%edi
    mov     $_edata,%ecx
    sub     %edi,%ecx
    rep     movsb
    mov     (the_answer),%eax
    mov     $1,%ebx
    int     $0x80

    .data
the_answer: 
    .long   42

my.x我有我的链接器脚本:

SECTIONS
  {
  .text 0x08048000 : { *(.text) _etext = . ; }
  .mdata 0x80000000 : 
    AT ( ADDR (.text) + SIZEOF (.text) )
    { _data = . ; *(.data); _edata = . ;  }
  .bss :
    { _bstart = . ;  *(.bss) *(COMMON) ; _bend = . ;}
}

构建镜像的命令是:

gcc -g -o my.o my.S -c -m32 -Wa,-agnlsc > my.lst
ld -m elf_i386 -T my.x -Map=my.map my.o -o my

my.map 文件显示

.mdata          0x0000000080000000        0x4 load address 0x0000000008048020

也就是说,正如预期的那样,“运行时”VMA 地址是 0x80000000,而“加载时间”LMA 是 0x08048020。根据其他地方的描述,我希望在程序开始时执行一些代码来将数据从 LMA 地址复制到 VMA 地址(如 中所示my.S)。

然后我运行gdb my并执行:

(gdb) break _start
...
(gdb) run
...
(gdb) x/w 0x8048020
0x8048020:      0
(gdb) x/w 0x80000000
0x80000000:     42

所以在不执行复制代码的情况下,初始化数据出现在VMA地址,而不是手册中描述的LMA地址。这无关紧要,只是我需要能够在以后重新初始化数据。

标签: assemblylinker-scriptsi386

解决方案


推荐阅读