大小端,内对齐及函数跳转在嵌入式中的应用

嵌入式知识点 嵌入式知识点复习一 1、 嵌入式系统的一般组成结构 2、嵌入式硬件系统的结构 (1)嵌入式处理器+外围硬件 (2)常见的外围硬件:电源、时钟、内存、I/O、通信、调试; 3、嵌入式处理器 (1)ARM、S3C6410、STM32单片机、华为海思、高通骁龙等 (2)Intel /AMD 都不是嵌入式处理器 4、嵌入式操作系统 功能: 种类:嵌入式linux;WinCE;Vxworks;μC/OS-... 阅读详情

1)大小端的问题(只是针对多字节,对于单字节,是不存在大小端问题的): 

我们将一个4字节的数据0x7654321放入内存,然后将其读出也是0x7654321,在这个过程中一般是不会出问题的,这是因为对于一种处理器,如果读写指令针对的数据长度和类型是一致的,无论数据在内存中存放的形式如何,处理器整体读写都没有问题。

问题在于,将0x7654321整体写入内存,然后在内存的首地址用单字节读取的命令的读出,这个时候可能就有问题了,就涉及到大小端的问题:

小端处理器:

写内存:将内存低地址放入源数据的低字节,内存高地址放入源数据的高字节
读内存:将内存低地址视为目的数据的低字节,内存高地址视为目的数据的高字节

大端处理器:

写内存:将内存低地址放入源数据的高字节,内存高地址放入源数据的低字节
读内存:将内存低地址视为目的数据的高字节,内存高地址视为目的数据的低字节

存放如下对比(源数据为:0x1234567):


下面给出一个例子:

typedef struct _Byte4{
    unsigned char Byte0;
    unsigned char Byte1;
    unsigned char Byte2;
    unsigned char Byte3;
}Byte4 ;

typedef union _Data32{
    unsigned long data;
    Byte4 dataByte;
}Data32;
 
int main()
{
    Data32 a;
    a.data = 0x11223344;
    printf("Databyte(0, 1, 2 ,3 ):(%x, %x, %x, %x)\n",
        a.dataByte.Byte0, a.dataByte.Byte1,
        a.dataByte.Byte2, a.dataBtye.Byte3);
}
对于这个问题,如果是小端系统,结果是:
Databyte(0, 1, 2, 3):(44, 33, 22, 11)
如果是大端系统,结果是
Databyte(0, 1, 2, 3):(11, 22, 33 ,44)
这里顺便给出测试处理器大小端的简单程序:

int testendian()
{
    unsigned int x=1;
    if(1 == *(unsigned char *)&x)
          printf("Little Endia\n");
    else
          printf("Big Endia\n");
    return (1 == *(unsigned char *)&x);
}
2)内存对齐问题(这里默认是小端系统)
   内存对齐的含义是:对于一个4字节的数据,要求其内存是4字节对齐的(即存储起始地址为4字节的整数倍)。这就是说,32位对齐的含义是其内存的地址的最低位为:0x0, 0x4, 0x8, 0xc;16位对齐(即2字节对齐,存储起始地址为2字节的整数倍)的含义是内存的地址的最低位为:0x0, 0x2, 0x4, 0x6, 0x8, 0xA, 0xC, 0xE.而对于单字节数据是不存在内存对齐问题。一般情况下,编译器在变量的栈上进行内存分配的时候,都能保证根据其自己的数据类型做到内存对齐,不懂,看下边的例子:
char v1;    short v2;    short v3;    long v4;
假设:v1的地址为0xbffff7f7
那么上述四个变量的地址分别如下:0xbffff7f7    0xbffff7f4    0xbffff7f2    0xbffff7ec结果是怎么来的呢,看下边(在这里只考虑最后变化的两位):
注意:计算机中的内存是以字节为单位的连续的存储空间,每个字节都有一个唯一的编号,这个编号就称为内存地址;因为内存的存储空间是连续的,所以,内存字节的地址编号也是连续的:


解释如下:我们已经知道,v1的地址是0xf7。如果常规理解,v2是short,占两个字节,那么应该从0xf5开始,占据0xf5和0xf6两个字节,即地址是0xf5。但由于0xf5不是两字节对齐(见上边),所以要继续向低地址移动到0xf4(它是两字节对齐的),所以v2的地址是0xf4,占据0xf4,0xf5两个字节,v3同理地址是0xf2。对于v4而言,从0xf1开始左移4个字节到0xee,但它不是4字节对齐的,所以继续左移到0xec,占据0xec,0xed,0xee,0xef四个字节,完成存储。
既然说到字节对齐,常常让人忘不了,sizeof对结构体的操作,一般而言,需要满足3个准则:
A.结构体变量的首地址能够被最宽的基本类型成员的大小所整除
B.结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节。
C.结构体的总大小为结构体最宽的基本类型成员的整数倍,如有需要编译器会在最后一个成员后加上一个填充字节。
如:
struct S{
    char c1;
    int i;
    char c2;
};
c1的偏移量为0,i的偏移量为4,c1与i之间便需要填充3个字节,c2偏移量为8,加起来就是1+3+4+1等于9个字节,由于这里最宽的基本类型是int,大小为4字节,再补3字节凑成4的倍数,一共是12字节。
   其实上面的关键在于,在编译器处理结构体的时候,默认将使结构体内部各个变量的内存都是对齐的,由此在结构体的内部可能出现一些位的空字节。
3)函数调整在嵌入式的应用
C语言中程序的一种最基本的跳转方式就是函数调用。经过编译后,在处理器的角度来看就是跳转到了函数的起始地址处,开始执行那个相应位置的代码。这就是告诉我们,在嵌入式系统中,可以使用绝对地址的跳转。这时程序跳转不是去调用一个函数,而是将程序运行的地址(即程序计数器PC)置为绝对地址。然而在各种处理器的汇编语言中,有绝对跳转的指令,但C语言是高级语言,要完成这种绝对地址的跳转,需要通过函数指针这种特殊的形式来实现。
利用函数指针来实现绝对地址跳转。如下:

typedef void (* FUN_T)(void);
void display(void)
{
    ....
}
int main(void)
{
    FUN_T pf=display;
    pf();     
    return 0;
}
运行到pf()时,调用函数指针,将实现跳转到display函数处(地址处)。
通过上面我们易想到把display换成绝对地址,不是就跳到了绝对地址那里吗?不错,如下:

int main(void)
{
    FUN_T pf=(FUN_T)0x400000000;  //这里将函数指针设置为绝对地址。
    pf();   //调用函数指针,实现跳转到  0x400000000
    return 0;
}
上面的代码可以不用类型定义,等价于如下代码:
void (*des)(void);
des = (void (*)(void))0x40000000;
des();
上面的跳转中,没有参数,也没有返回值,其实实际上是可以传递到跳转处参数,以及获取返回值:

typedef int (* FUN_T)(int, int);
int main()
{
    int ret;
    FUN_T pf = (FUN_T)0x40000000;
  ret = (*pf)(0x10, 0x12);
  return 0;
}
这里的返回值一般表示程序出错。

CTF逆向中那些‘坑’:从一道题看IDA反编译、大小端与数据隐藏 本文深入剖析CTF逆向工程中的常见陷阱,通过一道典型题目详解IDA反编译、大小端问题与数据隐藏技巧。文章重点解析`__m128i`类型处理、全局变量定位及字节序转换等关键技术,提供Python工具链和IDA进阶技巧,帮助选手提升逆向分析能力与模式识别敏感度。 阅读详情

相关推荐

【嵌入式面试】嵌入式开发工程师面试通关指南(超详细)

【嵌入式面试全攻略】 本文系统梳理嵌入式开发工程师面试核心考点,涵盖C语言基础(volatile、大小端、宏定义)、单片机硬件(GPIO、通信协议)、RTOS任务调度、网络协议(LwIP/SMTP)及项目经验讲解技巧。特别整理高频面试题解析(附代码示例)和STAR法则项目表述模板,并提供调试工具使用指南。文章强调嵌入式岗位"软硬结合"的特点,建议通过夯实基础+项目实践+模拟面试提升通过率,适合准备中高级嵌入式岗位的开发者参考。

欢迎来到兰舟比特的博客! 1832

单片机C语言任何位置跳转到任何指定地址 -转

用C语言写的程序为求模块化,一般函数数量较多,函数调用的嵌套层数也多,要从一个较深的嵌套立刻跳出到主函数,是非常困难的。用break或者return是跳不出来的,一般的解决方法或是使用C51的库函数setjmp()和longjmp()实现长跳转,但是这两个函数在中断函数内部是无能为力的;再或是在C函数中嵌入汇编。虽然用汇编指令可以实现程序的长距离跳转,但是这种方法的调试过程十分烦琐,而且程序的可移

xp5xp6的博客 7332

嵌入式linux面试必问35题

软中断是执行中断指令产生的,无面外部施加中断请求信号,因此中断的发生不是随机的而是由程序安排好的。②硬中断的中断响应周期,CPU需要发中断回合信号;软中断的中断响应周期,CPU不需发中断回合信号。③硬中断的中断号是由中断控制器提供的;软中断的中断号由指令直接给出,无需使用中断控制器。函数调用和软中断调用的区别是,软中断多了修改特权级和查找中断向量表的功能,其他部分完全一样。软中断调用时将返回地址和CPU状态寄存器内容压栈,修改特权级,根据中断号查找中断向量表,找到ISR中断服务例程地址,跳转执行。

coldmood77的博客 450

位域对齐问题

在编写一个小程序时,发现原来定义的位域结构

fugc2005的专栏 1174

部署资源管理系统chemx

资源管理系统的部署教程

weixin_40784215的博客 822

Minitab实战:用Weibull分布预测产品寿命的5个关键参数(附真实案例)

本文通过一个真实的电容器老化测试案例,详细介绍了如何运用Minitab软件进行Weibull分布分析,以预测产品寿命。文章深入解读了形状参数β、尺度参数η等五个关键参数的工程意义与商业价值,指导工程师从失效数据中提取洞察,并将其应用于可靠性评估、保修策略制定及成本预估等实际业务决策。

weixin_29231263的博客 520

关于大小端序和字节对齐的总结

在使用变量的时候,直接对变量进行操作,无需管是大端还是小端序,但是以字节为单位进行操作时就需要考虑; 比如:     int numPorts;     numPorts |= 1;     这样子numPorts的值就是1了     如果这样:    unsigned char *s = (unsigned char *)&numPorts,然后

linux Qt C++ 嵌入式 2877

深入解析Android Qcom Camera HAL3架构与Camx线程模块

本文深入解析了Android Qcom Camera HAL3架构与Camx线程模块的核心原理。文章以高通芯片平台为例,剖析了从按下快门到生成照片的完整Camera流程分析,重点阐述了Camx框架中线程池、消息队列及Fence同步机制如何协同工作,以实现高效、稳定的多线程并发图像处理,为相机性能优化提供理论基础。

weixin_29184075的博客 221

大小端序转换

  在嵌入式开发中,经常碰到因端序使用不当导致的错误,故决定决定将工作中常见的转序函数进行梳理,一是为了避免犯同样的错误,二是为了以后方便查询。本文分为四个部分:1、什么是大小端序;2、大小端序数据相互转换函数;3、应用场景;4、使用总结。   1、什么是大小端序   大端模式:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中。   小端模式:是指数据的高字节保存在内...

weixin_34162401的博客 670

手把手教你学Simulink——基于Simulink的变换器老化预测与数字孪生(Digital Twin)

这不仅是技术的演进,更是从“事后救火”到“事前预言”的降维打击。:通过本文的实战演练,你不仅掌握了功率变换器“电气-热-老化”多物理场耦合的建模哲学,更深刻领悟了如何将高深的随机过程(粒子滤波)降维成可落地、可量产的工程工具;:起初,由于数据量少,粒子滤波器预测的剩余寿命(RUL)置信区间(95%)非常宽泛(如 1000~2000小时)。在工业4.0与智能制造的浪潮下,功率变换器(如光伏逆变器、车载OBC、服务器电源)不再是孤立的硬件,而是具备“自我感知”与“寿命预知”的智能节点。

MHD0815的博客 298

COSMO-RS理论:流体相热力学预测的核心模型与技术突破

摘要:COSMO-RS模型通过量子化学计算分子表面电荷分布,实现了从微观量子尺度到宏观化工过程的热力学预测。该模型基于介电连续介质理论,将分子表面片段化处理,通过σ-剖面描述电荷分布,并计算片段间的静电失配能和氢键能。其核心算法通过自洽化学势方程求解活度系数,克服了传统模型依赖实验参数的局限。随着技术进步,模型引入了高阶描述符和色散力修正,提升了预测精度。在药物研发、化工分离等领域广泛应用,但仍存在对长程有序结构预测不足等局限性。该模型为复杂体系的热力学性质预测提供了重要理论工具。

ASKCOS博客 973

保证函数调用时stack的起始地址是十六字节对齐的方法

    在某些应用到SSE指令的代码中,都会要求所参与运算的内存地址必须是16字节对齐,否则程序将会crash. 在默认情况下如果一个(静态/动态)库是用gcc编译的,并且调用该(静态/动态)库的程序也是用gcc编译的,则该程序将运行正常,因为这样可以保证所有代码中都用相同的stack初始化逻辑,如果代码出错,则必定是真实的错误,而不是由于函数调用过程中stack初始化错误而造成的。 

我的奋斗@2011之移动互联网 5487

【硬件的单元测试 UT 3】PCIe 3.0及信号完整性测试方法

PCIe标准自从推出以来,1代和2代标准已经在PC和Server上逐渐普及,用于满足高速显卡、高速存储设备对于高速数据传输的要求。出于支持更高总线数据吞吐率的目的,PCI-SIG组织在2010年制定了PCIe 3.0,即PCIe 3代的规范,数据速率达到8Gbps。

qq_43416206的博客 1414

嵌入式学习笔记——大小端及跳转到绝对地址

大小端以及跳转到绝对地址 0x100000

zxjiaya的博客 1368

【数据集】全球预报系统GFS概述:数据下载及处理

【数据集】全球预报系统GFS概述:数据下载及处理

WW、forever的博客 5751

修改yolov8使支持单通道图像输入

默认支持BGR三通道图像输入,但是在很多工业场景下,存在很多灰度图像的场景,因此对yolov8代码做一些修改以支持单通道图像输入,满足项目实际需求。训练时,只需要在 data 的 yaml 文件中,添加 ch=1 即可。

mingo_敏 5779

【Cortex-M】MCU代码段跳转、运行多段代码,Flash程序更新的实现方式之一

摘要:本文介绍了在Cortex-M系列MCU上实现代码段跳转和运行多段代码的方法,用于实现Flash程序更新。主要内容包括:1)通过软件跳转到BootLoader或其他Flash地址的执行流程,需关闭外设时钟、中断等;2)以STM32为例的跳转代码实现,包括系统初始化、中断处理和地址跳转;3)多段代码运行方案设计,通过引导程序判断条件跳转到不同应用程序区域,并需调整目标代码的起始地址和中断向量表位置。该方法为MCU固件更新提供了一种灵活的软件实现方案。

Mike Zhou的博客 1868

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

小端模式和大端模式_嵌入式C语言——大小端模式初探

引言:什么是大小端模式在计算机通信过程中,经常会遇到一个问题,是先发送数据的高字节还是先发送低字节呢?比如我们经常可以在网络通讯协议中,都能听到”大端(big endian)模式”这一词,与之对应的是"小端模式(little endian)",发送方和接收方必须按照相同的字节顺序来处理数据,否则就会出现错误。而今天我们主要讲的是计算机存储系统的大小端,在计算机内存/硬盘中,数据是以字节为单位存储的...

weixin_39872872的博客 504

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【嵌入式入门篇】嵌入式0基础沉浸式刷题篇1

【嵌入式入门篇】嵌入式0基础沉浸式刷题篇1

努力才是唯一的入场券。 4万+

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

「面试/笔试」嵌入式八股文—P1 关键字篇

这篇嵌入式技术文章系统性地总结了C/C++编程中的关键语法点,分为四大类:循环控制(continue/break/return/goto)、数据类型(struct/union/enum等)、存储类别(volatile/extern/static等)和运算符特性(++a/a++、sizeof等)。文章采用"核心规则+对比分析+典型示例"的三段式结构,重点突出了struct与class的内存对齐差异、指针与数组的存储特性、前置/后置自增的效率区别等嵌入式开发中的高频考点

嵌入式阿齐Archie 1万+

几道嵌入式的面试题

1. 用C语言跳到绝对地址0xFFF0处。    typedef void (*lpFunction)(void);    lpFunction lpReset = (lpFunction)0xFFF0;    // ((void)(*)(void))(0xFFF0)    lpReset();2. 用宏写出大小端判定,大端返回0,小端返回1    不会...3. sizeof()操作符    char* ss = "0123456789";    sizeof(ss) 结果 4 ===》ss是指向字符串常

finewind的专栏 945

嵌入式常见面试题二

嵌入式常见面试题

weixin_46580481的博客 1873

嵌入式软件笔试基础

前言:面试中,有些公司会先有笔试,有些同学没温习,很容易忘记写不出了。下面总结一下(个人笔试经验) 重中之重:熟悉自己所做过的项目。 笔试基础: 1、(void (*)( )) ,是一个返回值为void,参数为空的函数指针原型。 题目:C语言跳转到指定地址执行?如跳转到0x100000这个地址执行。 Uint32 addr = 0x100000; static void (*p)(void); //定义一个函数指针 //将制定地址强制转换为不带参数不带返回值的值函数指针。 p= (void (*)(void

qq_42837982的博客 740

嵌入式八股文总结(C语言篇)

最近正在准备秋招,在此每天记录一些面试常问的八股文,希望可以和大家一起进步。(持续更新中……)

小海螺的博客 3万+

嵌入式面试八股文整理(持续更新)

计算机系统中以字节(8bit)为存储单元,也就是每个地址单元对应一个字节,C语言中的int、short等类型数据大小大于一字节,所以就要考虑到多字节类型数据在内存中的字节排序问题,也就是大端模式和小端模式,介绍如下:小端模式:数据的低位存放在低地址中,数据的高位存放在高地址中。如存储0x12 34 56 78,小端存储时情况如下:低地址 --------------------> 高地址大端模式:数据的高位存放在低地址中,数据的低位存放在高地址中。

bastarddd的博客 1502

嵌入式操作系统复习

文章目录: 一:选择题 二:填空题 三:简单题 1 嵌入式系统基础:含义、应用、组成、特点、与单片机的关系 1.1 含义 1.2应用 1.3 组成 1.4 特点 1.5 嵌入式系统与单片机的关系 2 嵌入式系统的硬件、软件、处理器分类 2.1嵌入式系统硬件 2.2嵌入式系统软件 2.3处理器分类 3 ARM处理器 3.1 特点 3.2 两种工作状态 3.3 七种运行模式 3.4 寻址方式 3.5 体系结构 3.6 指令结构 3.7 ARM体系结构的存储器格式...

刘鑫磊 5904
上一篇: linux内核及驱动开发中有关__init,__exit和__initdata的用法
下一篇: C语言程序的内存布局
wustdatamining
博客等级 码龄15年 12粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值