首页 > 解决方案 > 如何在 ARM64 汇编代码中分配可写内存?

问题描述

我正在尝试学习ARM64。我在 Apple M1 上组装。

我正在尝试分配我可以写入的内存。我不断收到以下错误:

ld: Absolute addressing not allowed in arm64 code but used in '_main' referencing 'foo'

我的程序很简单:

// foo.s
.global _main
.align 2

_main:
  ldr x0, =foo

.data
foo: .zero 8

我正在使用这个脚本来编译它:

#!/bin/bash

as foo.s -o foo.o &&                               \
                                                   \
ld foo.o -o foo                                    \
   -arch arm64                                     \
   -syslibroot `xcrun -sdk macosx --show-sdk-path` \
   -lSystem

经过一番谷歌搜索后,我尝试设置-no_pield 但这会导致:

ld: warning: -no_pie ignored for arm64

我不确定发生了什么。

谢谢

更新:这里有一个问题可以解释这个问题。

我应用了该修复程序并编写了这个快速程序来测试它是否有效:

.global _main
.align 2

_main:
  // Set x0 to the memory address of foo.
  adrp x0, foo@PAGE
  add x0, x0, foo@PAGEOFF

  // Store 123 in foo.
  mov x1, 123
  str x1, [x0]

  // Load the contents of foo into x2.
  ldr x2, [x0]

  // Exit with a status code set to foo.
  mov x0, x2
  mov x16, 1
  svc 0

.data
foo: .zero 8

正如我所料,它以 123 的退出状态返回。

标签: assemblyarmldarm64

解决方案


.zero您在该.data部分中分配了内存。现在您只需要加载其地址即可访问它。

编写与位置无关的代码比尝试禁用它要好。因此,不要尝试加载绝对地址,而是相对于程序计数器访问它们。

在一个中等大小的程序中(不到一兆字节左右的代码加上静态数据),你可以foox0

adr x0, foo

adr指令将立即数加到程序计数器的值上pc,并将结果留在目标寄存器中。汇编器和链接器可以确定adr指令地址与 的地址之间的差异foo,并将该差异编码为adr指令的立即数。

对于较大的程序,地址差异可能高达 4 GB 左右,您可以使用组合adrp来获取高位,add或者使用带有偏移量的加载/存储。请参阅ARM 汇编中 ADRP 和 ADRL 指令的语义是什么?


推荐阅读