返回顶部
首页 > 资讯 > 精选 >ARMv8汇编指令adrp和adr怎么使用
  • 654
分享到

ARMv8汇编指令adrp和adr怎么使用

2023-06-22 02:06:13 654人浏览 安东尼
摘要

这篇文章主要介绍“ARMv8汇编指令adrp和adr怎么使用”,在日常操作中,相信很多人在ARMv8汇编指令adrp和adr怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ARMv8汇编指令adrp和a

这篇文章主要介绍“ARMv8汇编指令adrp和adr怎么使用”,在日常操作中,相信很多人在ARMv8汇编指令adrp和adr怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ARMv8汇编指令adrp和adr怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    1.概述

    在阅读linux内核代码时,经常能碰到汇编代码,网上能查的资料千篇一律,大多都描述的很模糊。俗话说,实践是检验真理的唯一标准,我们就参考官方文档,自己写汇编代码并反汇编,探寻其中的奥妙。

    2.adrp

    在Linux内核启动代码primary_entry中,使用adrp指令获取Linux内核在内存中的起始页地址,页大小为4KB,由于内核启动的时候MMU还未打开,此时获取的Linux内核在内存中的起始页地址为物理地址。adrp通过当前PC地址的偏移地址计算目标地址,和实际的物理无关,因此属于位置无关码。对于具体的计算过程,下面慢慢分析。

    [arch/arm64/kernel/head.S]SYM_CODE_START(primary_entry)    ......adrpx23, __PHYS_OFFSETandx23, x23, MIN_KIMG_ALIGN - 1  // KASLR offset, defaults to 0    ......SYM_CODE_END(primary_entry)[arch/arm64/kernel/head.S]#define __PHYS_OFFSETKERNEL_START  // 内核的物理地址[arch/arm64/include/asm/memory.h]// 内核的起始地址和结束地址在vmlinux.lds链接脚本中定义#define KERNEL_START    _text         // 内核代码段的起始地址,也即内核的起始地址#define KERNEL_END_end          // 内核的结束地址

    2.1.定义

    adrp指令根据PC的偏移地址计算目标页地址。首先adrp将一个21位有符号立即数左移12位,得到一个33位的有符号数(最高位为符号位),接着将PC地址的低12位清零,这样就得到了当前PC地址所在页的地址,然后将当前PC地址所在页的地址加上33位的有符号数,就得到了目标页地址,最后将目标页地址写入通用寄存器。此处页大小为4KB,只是为了得到更大的地址范围,和虚拟内存的页大小没有关系。通过adrp指令,可以获取当前PC地址±4GB范围内的地址。通常的使用场景是先通过adrp获取一个基地址,然后再通过基地址的偏移地址获取具体变量的地址。
    下面是adrp指令的编码格式。立即数占用21位,在运行的时候,会将21位立即数扩展为33位有符号数。最高位为1,表示这是一个aarch74指令。

    ARMv8汇编指令adrp和adr怎么使用

    2.2.测试

    Linux内核启动代码不好测试,需要写一个简单的测试代码。下面是本次adrp的测试代码,使用adrp指令获取g_val1g_val2数组所在页的基地址,同时会打印数组的地址和调用函数的地址,由于是应用层的程序,这些地址都是虚拟地址,但是计算过程都是一样的。

    #define PAGE_4KB    (4096) #define __stringify_1(x...)#x#define __stringify(x...)__stringify_1(x)uint64_t g_val1[PAGE_4KB / sizeof(uint64_t)];uint64_t g_val2[PAGE_4KB / sizeof(uint64_t)];#define ADRP(label)   ({          \    uint64_t __adrp_val__ = 0;    \    asm volatile("adrp %0," __stringify(label) :"=r"(__adrp_val__)); \    __adrp_val__;                 \})static void adrp_test(){    printf("g_val1 addr 0x%lx, adrp_val1 0x%lx, adrp_test addr 0x%lx\n",        (uint64_t)g_val1, ADRP(g_val1), (uint64_t)adrp_test);    printf("g_val2 addr 0x%lx, adrp_val2 0x%lx, adrp_test addr 0x%lx\n",        (uint64_t)g_val2, ADRP(g_val2), (uint64_t)adrp_test);}

    上面程序运行的输出结果如下,g_val1g_val2的地址分别为0x5583e250280x5583e26028g_val1的页基地址为0x5583e25000g_val2页的基地址为0x5583e26000adrp_test函数的地址为0x5583e1479c

    g_val1 addr 0x5583e25028, adrp_val1 0x5583e25000, adrp_test addr 0x5583e1479cg_val2 addr 0x5583e26028, adrp_val2 0x5583e26000, adrp_test addr 0x5583e1479c

    反汇编代码如下所示。下面分析一下g_val1页基地址的计算过程,包括编译时和运行时,g_val2页基地址的计算过程类似,这里不再赘述。

    • g_val1址低低12位清零,得到0x1100,将当前adrp指令所在地址的低12清零,得到0x0(编译时完成)

    • 0x1100减去0x0得到偏移地址0x11000,偏移地址右移12位得到偏移页数量0x11,将立即数0x11保存到指令编码中(编译时完成)

    • 取出立即数0x11,左移12位转换成偏移的字节数,即0x11000(运行时完成)

    • 将PC地址的低12位清零得到0x5583e14000(运行时完成)

    • 将0x5583e14000加上0x1100得到g_val1运行时页基地址0x5583e25000(运行时完成)

    000000000000079c <adrp_test>:  // 运行时的地址为0x5583e1479c...... 7b0:b0000080 adrpx0, 11000 <__data_start>    // 获取g_val1页基地址...... 7e0:d0000080 adrpx0, 12000 <g_val1+0xfd8>    // 获取g_val2页基地址Disassembly of section .data:       // 数据段定义0000000000011000 <__data_start>:    // 运行时的地址为0x5583e25000.........Disassembly of section .bss:        // bss段定义0000000000011028 <g_val1>:    // 运行时地址为0x5583e25028...0000000000012028 <g_val2>:    // 运行时地址为0x5583e26028...

    从上面可以看出,编译时和运行时的地址不一样,但通过adrp指令都能正确获取g_val1页基地址和g_val2页基地址。说明adrp获取的地址是位置无关的,不管运行时的地址怎么变,都可以正确获取对应变量页基地址。当然我们也可以使用专业的反汇编工具,直接将机器码转换为汇编代码。上面两条adrp指令转换的汇编代码如下,和上面一样,这里的偏移地址都已经做了左移12位的处理。

    ARMv8汇编指令adrp和adr怎么使用

    3.adr

    3.1.定义

    adr指令根据PC的偏移地址计算目标地址。偏移地址是一个21位的有符号数,加上当前的PC地址得到目标地址。adr可以获取当前PC地址±1MB范围内的地址。下面是adr指令的编码格式。立即数占用21位。

    ARMv8汇编指令adrp和adr怎么使用

    3.2.测试

    下面是测试代码,使用adr指令获取变量g_val3g_val4的地址,并与通过&获取的地址进行对比。

    uint64_t g_val3 = 0;uint64_t g_val4 = 0;#define ADR(label)   ({          \    uint64_t __adr_val__ = 0;    \    asm volatile("adr %0," __stringify(label) :"=r"(__adr_val__)); \    __adr_val__;                 \})static void adr_test(){    printf("g_val3 addr 0x%lx, adr_val1 0x%lx, adr_test addr 0x%lx\n",        (uint64_t)&g_val3, ADR(g_val3), (uint64_t)adr_test);    printf("g_val4 addr 0x%lx, adr_val2 0x%lx, adr_test addr 0x%lx\n",        (uint64_t)&g_val4, ADR(g_val4), (uint64_t)adr_test);}

    下面是测试结果,使用&获取的地址和通过adr获取的地址相同。

    g_val3 addr 0x5583e25018, adr_val1 0x5583e25018, adr_test addr 0x5583e14810g_val4 addr 0x5583e25020, adr_val2 0x5583e25020, adr_test addr 0x5583e14810

    下面是反汇编的代码。可以看出,adr汇编代码中的偏移地址被objdump使用符号地址代替了,没有使用真正的偏移地址。g_val3真正的偏移地址为0x107f4,g_val4真正的偏移地址为0x107cc。执行第一条adr指令的PC地址为0x5583e14824,则0x5583e14824+0x107f4=0x5583e25018为g_val3的地址。g_val4的计算过程类似,不再赘述。

    0000000000000810 <adr_test>:    // 运行地址为0x5583e14810...... 824:10083fa0 adrx0, 11018 <g_val3>  // 偏移地址为0x11018-0x824=0x107f4...... 854:10083e60 adrx0, 11020 <g_val4>  // 偏移地址为0x11020-0x854=0x107cc......isassembly of section .data:0000000000011000 <__data_start>:.........Disassembly of section .bss:......0000000000011018 <g_val3>:      // 运行地址为0x5583e25018...0000000000011020 <g_val4>:      // 运行地址为0x5583e25020    ...

    ARMv8汇编指令adrp和adr怎么使用

    到此,关于“ARMv8汇编指令adrp和adr怎么使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: ARMv8汇编指令adrp和adr怎么使用

    本文链接: https://lsjlt.com/news/301963.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    猜你喜欢
    • ARMv8汇编指令adrp和adr怎么使用
      这篇文章主要介绍“ARMv8汇编指令adrp和adr怎么使用”,在日常操作中,相信很多人在ARMv8汇编指令adrp和adr怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”ARMv8汇编指令adrp和a...
      99+
      2023-06-22
    • 浅析ARMv8汇编指令adrp和adr
      目录1.概述2.adrp2.1.定义2.2.测试3.adr3.1.定义3.2.测试参考资料1.概述 在阅读Linux内核代码时,经常能碰到汇编代码,网上能查的资料千篇一律,大多都描述...
      99+
      2024-04-02
    • 怎么从0学ARM汇编伪指令LDS
      本篇内容介绍了“怎么从0学ARM汇编伪指令LDS”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! ...
      99+
      2024-04-02
    • Verilog编译指令怎么使用
      这篇“Verilog编译指令怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Verilog编译指令怎么使用”文章吧。V...
      99+
      2023-07-06
    • C++的using声明和using编译指令怎么使用
      这篇文章主要介绍“C++的using声明和using编译指令怎么使用”,在日常操作中,相信很多人在C++的using声明和using编译指令怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++的usi...
      99+
      2023-06-22
    • 汇编语言的指令采用什么来取代二进制
      本篇内容介绍了“汇编语言的指令采用什么来取代二进制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!汇编语言的指令采用“助记符”来取代二进制。助...
      99+
      2023-06-25
    • Vue指令v-show和v-if怎么使用
      本文小编为大家详细介绍“Vue指令v-show和v-if怎么使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Vue指令v-show和v-if怎么使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。一、v-sho...
      99+
      2023-06-29
    • vue中的指令和插值怎么使用
      这篇文章主要介绍“vue中的指令和插值怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“vue中的指令和插值怎么使用”文章能帮助大家解决问题。一、安装vue直接使用script标签引入<s...
      99+
      2023-07-04
    • Apache RewriteBase指令怎么使用
      在Apache配置文件中使用RewriteBase指令可以设置重写规则中的基本路径。该指令用于指定相对于网站根目录的基本路径,以便在...
      99+
      2024-03-08
      Apache
    • 汇编语言80x86系统通用数据传送指令是什么
      这期内容当中小编将会给大家带来有关汇编语言80x86系统通用数据传送指令是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。通用数据传送指令MOVmove传送MOVSXmove with sig...
      99+
      2023-06-25
    • oracle中怎么使用adrci命令来管理ADR下相关日志
      本篇内容主要讲解“oracle中怎么使用adrci命令来管理ADR下相关日志”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“oracle中怎么使用adrci命令来...
      99+
      2024-04-02
    • angular指令和管道怎么用
      本篇内容主要讲解“angular指令和管道怎么用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“angular指令和管道怎么用”吧!指令 Directive指令是...
      99+
      2024-04-02
    • 怎么使用Vue中v-指令
      这篇文章主要介绍“怎么使用Vue中v-指令”,在日常操作中,相信很多人在怎么使用Vue中v-指令问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么使用Vue中v-指令”的疑惑有所帮助!接下来,请跟着小编一起来...
      99+
      2023-06-25
    • Angular的Directive指令怎么使用
      这篇文章主要介绍“Angular的Directive指令怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Angular的Directive指令怎么使用”文章能帮助大家解决问题。Directiv...
      99+
      2023-07-04
    • Dockerfile的CMD指令怎么使用
      这篇文章主要介绍“Dockerfile的CMD指令怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Dockerfile的CMD指令怎么使用”文章能帮助大家解决问题。一 Docker的CMD指令...
      99+
      2023-07-05
    • Vue中的调试工具和指令怎么使用
      这篇文章主要讲解了“Vue中的调试工具和指令怎么使用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Vue中的调试工具和指令怎么使用”吧!vue 的调试工具(1)安装 vue-devtools...
      99+
      2023-06-30
    • Vue3中的模板语法和vue指令怎么使用
      1 模板插值语法在script 声明一个变量可以直接在template 使用用法为{{变量名称}}模板语法是可以编写条件运算的运算也是支持的操作API 也是支持的<template> {{ message }} {{...
      99+
      2023-05-18
      VUE Vue3
    • vim指令怎么在linux 中使用
      这篇文章给大家介绍vim指令怎么在linux 中使用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Vim 是 Linux 系统上的最著名的文本/代码编辑器,也是早年的 Vi 编辑器的加强版,而 gVim 则是其 Win...
      99+
      2023-06-09
    • Vue的指令v-for怎么使用
      这篇文章主要介绍了Vue的指令v-for怎么使用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Vue的指令v-for怎么使用文章都会有所收获,下面我们一起来看看吧。Vue v-for的使用1.迭代普通数组在da...
      99+
      2023-06-29
    • MySQL Delete From指令怎么使用
      MySQL的DELETE FROM指令用于从表中删除记录。其语法如下:```DELETE FROM table_na...
      99+
      2023-10-12
      MySQL
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作