15 ABI规范 栈帧结构,帧栈的形成过程

ABI是什么,由谁提供,写在什么规范里 这些规范确保了不同组件之间的二进制接口的一致性,使得在不同的编译器和操作系统上生成的二进制代码能够正确地交互和执行。促进不同编译器、操作系统和硬件平台之间的二进制兼容性。通过遵循统一的ABI规范,不同的软件模块(如库、驱动程序和应用程序)可以在相同的操作系统和硬件平台上无缝地协同工作,即使它们是由不同的开发者、使用不同编程语言或编译器生成的。开发者在编写、编译和链接应用程序时,需要遵循相应的ABI规范,以确保生成的二进制代码能够与目标平台的ABI兼容,从而实现正确的函数调用、内存访问和数据传递。 阅读详情

EIP 指令寄存器,其指向处理器下一条要执行的指令在内存的位置
ESP 栈指针寄存器
EBP 栈帧基地址寄存器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
也就是说每一个函数所需要的栈帧,即每一个函数所对应活动记录的大小是固定的,由编译器在编译的时候指定。编译器在编译的时候就确定了当前函数所需要的栈空间的大小了。 最终表现为汇编代码中第一个字面常量。

函数结束的时候:
move ebp, esp
1 先将 ebp寄存器的值 赋值给 esp寄存器

pop ebp
2 此时pop 弹出来的值是 上一个栈帧的基准地址,pop到EBP寄存器中,此时 EBP寄存器保存了上一个栈帧的基准地址,即调用者栈帧的基准地址。即此时已经恢复了上一个栈帧的基准地址

函数返回的时候
pop eip
前面pop ebp 将 当时ESP栈指针寄存器指向的 内容(上一个栈帧基准地址) pop 到 EBP栈帧寄存器中。
此时 pop eip 将返回地址 弹出来到 EIP 指令寄存器,即函数返回,那么函数返回后,此时ESP 栈指针指向了 参数1的位置,即上一个栈帧的栈顶。被调函数的栈帧也被摧毁了。

pop 弹栈 弹的是ESP 栈顶指针指向的内存

在这里插入图片描述在这里插入图片描述当前栈帧起始地址:当前栈帧栈底

实验1 查看栈帧结构

#include <stdio.h>

/*            
	// EBP指针指向的内存空间 地址,当前栈帧基准地址 
	printf("ebp = %p\n", ebp);

	// EBP指针指向的内存空间中 存储上一个栈帧的基准地址  
   printf("previous ebp = 0x%x\n", *((int*)ebp)); 

	// EBP指针移位 +4 ---> 当前栈帧的返回地址
   printf("return address = 0x%x\n", *((int*)(ebp + 4)));  
   
   // EBP指针移位 +8 ---> 上一个栈帧的 esp指针指向的内存地址 
   printf("previous esp = %p\n", ebp + 8);                 
                         
*/
#define PRINT_STACK_FRAME_INFO() do                        \
{                                                          \
    char* ebp = NULL;                                      \
    char* esp = NULL;                                      \
                                                           \
                                                           \
    asm volatile (                                         \
        "movl %%ebp, %0\n"                                 \
        "movl %%esp, %1\n"                                 \
        : "=r"(ebp), "=r"(esp)                             \
        );                                                 \
                                                           \
   printf("ebp = %p\n", ebp);                              \
   printf("previous ebp = 0x%x\n", *((int*)ebp));          \
   printf("return address = 0x%x\n", *((int*)(ebp + 4)));  \
   printf("previous esp = %p\n", ebp + 8);                 \
   printf("esp = %p\n", esp);                              \
   printf("&ebp = %p\n", &ebp);                            \
   printf("&esp = %p\n", &esp);                            \
} while(0)

void test(int a, int b)
{
    int c = 3;
    
    printf("test() : \n");
    
    PRINT_STACK_FRAME_INFO();
    
    printf("&a = %p\n", &a);
    printf("&b = %p\n", &b);
    printf("&c = %p\n", &c);
}

void func()
{
    int a = 1;
    int b = 2;
    
    printf("func() : \n");
    
    PRINT_STACK_FRAME_INFO();
    
    printf("&a = %p\n", &a);
    printf("&b = %p\n", &b);
    
    test(a, b);
}

int main()
{
    printf("main() : \n");
    
    PRINT_STACK_FRAME_INFO();
    
    func();

    return 0;
}

gdb 调试

栈帧结构 分析

mhr@ubuntu:~/Desktop/system/qianzhuan/15$ gdb
GNU gdb (Ubuntu 7.11-0ubuntu1) 7.11
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
Type "apropos word" to search for commands related to "word".
(gdb) 
(gdb) shell gcc -g frame.c -o frame.out
frame.c: Assembler messages:
frame.c:30: Error: unsupported instruction `mov'
frame.c:31: Error: unsupported instruction `mov'
frame.c:44: Error: unsupported instruction `mov'
frame.c:45: Error: unsupported instruction `mov'
frame.c:56: Error: unsupported instruction `mov'
frame.c:57: Error: unsupported instruction `mov'

/*
在64位系统下去编译32位的目标文件,这样是非法的。
解决方案:
用”-m32”强制用32位ABI去编译,即可编译通过。

64位的Ubuntu如果执行X86平台32位编译,gcc -m32 -o x  x.c会报错:fatal error: sys/cdefs.h: No such file or directory
sudo apt-get install libc6-dev-i386 安装32位库文件
*/
(gdb) shell gcc -g -m32 frame.c -o frame.out   // 用”-m32”强制用32位ABI去编译
(gdb) file frame.out  //载入可执行程序
Reading symbols from frame.out...done.
(gdb) 
(gdb) start  //执行可执行程序
Temporary breakpoint 1 at 0x80486fe: file frame.c, line 53.
Starting program: /home/mhr/Desktop/system/qianzhuan/15/frame.out 

Temporary breakpoint 1, main () at frame.c:53
53	{
(gdb) break frame.c:35  //在 frame.c 第35行打上断点
Breakpoint 2 at 0x80485ad: file frame.c, line 35.
(gdb) (gdb) info breakpoints //查看断点信息 已经打上了
Num     Type           Disp Enb Address    What
2       breakpoint     keep y   0x080485ad in test at frame.c:35
(gdb) continue  //执行到断点位置
Continuing.
main() : 
ebp = 0xffffcf68
previous ebp = 0x0
return address = 0xf7e21647
previous esp = 0xffffcf70
esp = 0xffffcf50
&ebp = 0xffffcf54
&esp = 0xffffcf58
func() : 
ebp = 0xffffcf48
previous ebp = 0xffffcf68
return address = 0x80487cc
previous esp = 0xffffcf50
esp = 0xffffcf20
&ebp = 0xffffcf34
&esp = 0xffffcf38
&a = 0xffffcf2c
&b = 0xffffcf30
test() : 
//当前栈帧基准地址
ebp = 0xffffcf08
//上一个栈帧基准地址,可以看 func()函数的栈帧信息中的 栈帧基准地址,两者一致 
previous ebp = 0xffffcf48
//当前栈帧的返回地址
return address = 0x80486d6
//上一个栈帧的esp指针指向的位置  即上一个栈帧的栈顶地址
previous esp = 0xffffcf10
esp = 0xffffcef0
&ebp = 0xffffcef4
&esp = 0xffffcef8
&a = 0xffffcf10 // test(a, b); 函数参数a地址
&b = 0xffffcf14//  test(a, b); 函数参数b地址
&c = 0xffffcef0 //函数局部变量地址, 所以可以看出来 一个函数的栈帧空间中 参数数据 与 局部变量的存储 空间并不是连续的

Breakpoint 2, test (a=1, b=2) at frame.c:35
35	}
(gdb) info frame  //查看当前栈帧信息
Stack level 0, frame at 0xffffcf10: //当前栈帧的起始地址(栈底地址) = 当前栈帧基准地址(0xffffcf08 ) + 8 = 上一个栈帧的栈顶位置
 eip = 0x80485ad in test (frame.c:35); saved eip = 0x80486d6  //当前栈帧返回地址 所在空间的地址(0xffffcf0c ) =  当前栈帧基准地址(0xffffcf08 ) + 4
 called by frame at 0xffffcf50
 source language c.
 Arglist at 0xffffcf08, args: a=1, b=2
 Locals at 0xffffcf08, Previous frame's sp is 0xffffcf10 //函数调用前的栈顶指针指向的位置 ,即上一个栈帧(函数)的栈顶位置 = 当前栈帧基准地址(0xffffcf08 ) + 4
 Saved registers:
  ebp at 0xffffcf08, eip at 0xffffcf0c // eip 指针指向的空间  存储 当前函数(栈帧)的返回地址 
(gdb) x /1wx 0xffffcf0c  //查看 eip 指针指向的空间存储的数据 : 当前函数(栈帧)的返回地址 
0xffffcf0c:	0x080486d6
(gdb) 
(gdb) x /1wx 0xffffcf10 // 查看 上一个栈帧的栈顶位置(esp 指针指向的位置) 存储的数据
0xffffcf10:	0x00000001 // test(a, b); 函数调用的 最后一个参数b 
(gdb) x /1wx 0xffffcf14
0xffffcf14:	0x00000002 // test(a, b); 函数调用的 倒数第二个参数a
(gdb) 

以上的 栈帧结构分析 可以对应到这张结构图

在这里插入图片描述
参数入栈,前言,后续 分析

(gdb) shell objdump -S frame.out > frame.s  //查看可执行程序的反汇编


...


void test(int a, int b)
{
 804849b:	55                   	push   %ebp
 804849c:	89 e5                	mov    %esp,%ebp
 804849e:	83 ec 18             	sub    $0x18,%esp
 80484a1:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 80484a7:	89 45 f4             	mov    %eax,-0xc(%ebp)
 80484aa:	31 c0                	xor    %eax,%eax
...
}
...
 80485bf:	c9                   	leave  
 80485c0:	c3                   	ret    


080485c1 <func>:

void func()
{
//前言
 80485c1:	55                   	push   %ebp  // ebp 入栈
 80485c2:	89 e5                	mov    %esp,%ebp  // 移动 ebp 指针 指向 esp指向的地址处
 80485c4:	83 ec 28             	sub    $0x28,%esp  // $0x28 常量 即编译器设定的 栈帧空间大小。esp = esp - 0x28 。即移动esp指针到栈顶
 80485c7:	65 a1 14 00 00 00    	mov    %gs:0x14,%eax
 80485cd:	89 45 f4             	mov    %eax,-0xc(%ebp)
 80485d0:	31 c0                	xor    %eax,%eax

    int a = 1;
 80485d2:	c7 45 e4 01 00 00 00 	movl   $0x1,-0x1c(%ebp)
    int b = 2;
 80485d9:	c7 45 e8 02 00 00 00 	movl   $0x2,-0x18(%ebp)  //ebp 向低地址处 偏移24个字节
...

//函数调用  注意 call 指令会将返回地址 入栈
test(a, b);
 80486c6:	8b 55 e8             	mov    -0x18(%ebp),%edx  //将 -0x18(%ebp) 地址存储的数据 b 放到 edx寄存器
 80486c9:	8b 45 e4             	mov    -0x1c(%ebp),%eax  //将 -0x1c(%ebp) 地址存储的数据 a 放到 eax 寄存器
 80486cc:	83 ec 08             	sub    $0x8,%esp  //  
 80486cf:	52                   	push   %edx  // 参数 b 先入栈 
 80486d0:	50                   	push   %eax //参数 a 后入栈
 80486d1:	e8 c5 fd ff ff       	call   804849b <test>  // 跳转到 test()函数所在地 ,将返回地址入栈 继续执行
 80486d6:	83 c4 10             	add    $0x10,%esp
}
...
//后续
 80486eb:	c9                   	leave  
 80486ec:	c3                   	ret    

可以由上面的调试过程 总结出 如下函数调用时,栈帧形成的过程:

80486c6: 8b 55 e8 mov -0x18(%ebp),%edx //将 -0x18(%ebp) 地址存储的数据 b 放到 edx寄存器
80486c9: 8b 45 e4 mov -0x1c(%ebp),%eax //将 -0x1c(%ebp) 地址存储的数据 a 放到 eax 寄存器
80486cf: 52 push %edx // 参数 b 先入栈
80486d0: 50 push %eax //参数 a 后入栈
//func() 调用 使用 call 指令调用 test(), 跳转到 test()函数所在地 ,将返回地址入栈
80486d1: e8 c5 fd ff ff call 804849b // 跳转到 test()函数所在地 ,将返回地址入栈 继续执行
时刻1 : func()调用 test():

时刻2 test() 函数开始 ,将 ebp 压入栈中

//将 ebp 压入栈中
804849b: 55 push %ebp

时刻3

80485c2: 89 e5 mov %esp,%ebp // 移动 ebp 指针 指向 esp指向的地址处
80485c4: 83 ec 28 sub $0x28,%esp // $0x28 常量 即编译器设定的 栈帧空间大小。esp = esp - 0x28 。即移动esp指针到栈顶

时刻4 test()帧栈形成

在这里插入图片描述

【读书笔记】关于栈帧结构 依次入栈。4)其他上下文信息:在一些情况下,还会保存一些其他上下文信息,如函数调用前后的寄存器状态等。 阅读详情

相关推荐

ARM64栈帧探秘:从寄存器到函数调用的微观世界

本文深入解析ARM64架构的栈帧机制,从寄存器体系到函数调用的全流程,揭示FP(帧指针)和LR(链接寄存器)在栈帧构建中的关键作用。通过具体示例和调试技巧,帮助开发者掌握ARM64栈帧的底层原理,提升调试和性能优化能力。

weixin_29230649的博客 282

栈帧结构详解

Java虚拟机以方法作为基本的执行单位,“栈帧”是用于支持虚拟机进行方法调用和执行的数据结构,每一个方法从调用开始到执行结束,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程,栈帧也是虚拟机运行时数据区中虚拟机栈的栈元素。位于栈顶的栈帧被称为“当前栈帧”,其对应的方法称为“当前方法”。   栈帧中存储了方法的局部变量表、操作数栈、动态连接、方法返回地址和附加信息(例如,调试、性能收集相关的信息,取决于具体的虚拟机实现,是《Java虚拟机规范》中未描述的信息)。

lizhongchao_的博客 1万+

Linux调试私房菜(七)缔造程序兼容的合约

为什么下面的代码能够以0作为退出码结束程序运行? Linux下对于位域的存储方式是压缩存储。windows下对于位域的存储方式是非压缩存储。 函数调用时,参数如何入栈?函数返回时,返回值在哪里? 13. 问题 当返回值类型为结构体时,如何将值返回到调用函数中?...

Exp.Joker 534

编译工具链 之二 详解 ELF 格式及标准、UNIX 发展、ABI

在计算机及嵌入式系统中,二进制文件也有一定的标准格式,通常会包含在各平台的应用程序二进制接口 (Application Binary Interface,ABI)规范中。它是编译工具链必须要遵守的规范(编译工具链产生符合 ABI 的二进制文件)

技术干货 2548

Android RS-485 Modbus通信实战:填平收发使能与帧粘连两大深坑

RS-485是一种广泛应用于工业现场的半双工串行总线标准,以其抗干扰强、传输距离远(可达1200米)、支持多点通信等特性,成为PLC、电表、温控仪表等设备联网的核心物理层。其通信依赖严格的时序控制与帧边界识别,而Modbus RTU作为最主流的上层协议,以3.5字符间隔界定帧边界,并采用CRC16校验保障完整性。在Android平台实现可靠RS-485 Modbus通信面临双重挑战:一是系统缺乏原生硬件使能(DE/RE)协同机制,导致总线锁死;二是Linux tty驱动字节流无帧语义,引发Modbus帧粘连

axfcjwkbi259888707的博客 343

RISC-V编译选项-march与-mabi匹配原理与实战

RISC-V指令集架构没有默认CPU概念,其程序可执行性高度依赖编译时指定的-march(机器架构)和-mabi(应用二进制接口)组合。-march定义硬件支持的指令扩展集合,如rv64imac中的a代表原子扩展,缺失即导致illegal instruction;-mabi则规定寄存器用途、栈对齐、浮点传参等ABI契约,如lp64d要求硬件必须同时支持F和D扩展。二者不匹配将引发静默崩溃、syscall失败或中断异常等深层问题。在嵌入式开发、Linux内核适配及SoC Bring-up中,需结合芯片手册、工

weixin_33798152的博客 310

栈帧结构

栈帧 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表丶操作数栈丶动态连接和方法返回地址等信息。每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧。与当前栈帧相关联的方法,称为当前方法。 局部变量表 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方

amy acker的博客 3041

嵌入式面试内存管理四大考点:堆栈、对齐、大小端一网打尽

C语言内存管理是嵌入式开发的基石,涉及栈、堆、内存对齐与字节序等核心概念。理解栈的向下生长与堆的向上分配,掌握结构体对齐规则与sizeof计算,并能用指针法判断大小端,是定位栈溢出、通信数据错乱等疑难bug的关键。在实际工程中,DMA缓冲区需要对齐,通信协议需统一字节序,RTOS任务栈需要估算余量,这些场景无不考验工程师对底层机制的理解。本文围绕嵌入式面试高频考点,系统梳理堆栈、内存对齐、大小端判断与转换的常见追问,并结合代码示例给出可复用的定位思路与答题话术,适合C语言开发者与嵌入式求职者系统复习。

weixin_34326429的博客 437

栈帧结构差异分析:arm64和x64实战案例解析

深入对比arm64和x64架构下的栈帧布局与调用约定,通过实际案例揭示两者在函数调用、寄存器使用和堆栈管理上的核心区别,帮助开发者更好理解arm64和x64在底层执行模型上的差异。

weixin_42600128的博客 798

Opus编解码器与大语言模型的分层协作原理

音频编解码器(如Opus)是实时语音传输的底层基础设施,核心解决低延迟、抗丢包、带宽自适应等确定性工程问题;大语言模型(如GPT-4o)则位于语义理解层,依赖前序模块完成语音转文本后的意图解析与生成。二者不属于同一技术层级,不存在性能替代关系,而是通过L1信号层(Opus)、L2特征层(VAD)、L3感知层(ASR)、L4语义层(LLM)构成协同链路。真实系统中,Opus持续承担音频‘快递员’角色——所有主流AI语音产品(含GPT-4o Audio)均默认采用Opus压缩传输,其参数配置(如VBR、FEC、

dbp5156的博客 335

编译原理:目标程序运行时的活动

活动(Activation)是程序执行的基本单位。活动定义:过程(函数)的一次执行从调用开始到返回结束有自己的执行环境和生命周期有明确的开始和结束有自己的局部数据可以嵌套调用其他活动遵循后进先出的顺序C程序:int x = 1;foo(x);return 0;bar(b);main活动开始main调用foo,main活动暂停foo活动开始foo调用bar,foo活动暂停bar活动开始bar返回,bar活动结束。

梁辰兴的博客 93

STM32 HardFault 调试实战:基于 GCC 编译的栈回溯与函数调用链定位 3 步法

本文详细介绍了STM32 HardFault调试的3步实战方法,基于GCC编译环境,通过栈回溯与函数调用链定位技术快速解决问题。重点解析Cortex-M3异常栈帧结构、AAPCS调用规范及自动化栈回溯脚本,帮助开发者高效诊断内存越界、栈溢出等常见问题,提升嵌入式系统调试效率。

wangqiaowqo的专栏 385

【信息科学与工程学】【运营科学】第二篇 C4信息与通信网络运营 (C4) ——数据中心网络运营04

典型值:λ1​∈[−0.02,−0.01], λ2​∈[−0.01,0], η1​,η3​∈[0.1,0.3], η2​,η4​∈[0.05,0.15]参数:δ1​∈[−0.8,−0.3], δ2​∈[−0.5,−0.2], δ3​∈[−0.4,−0.1], δ4​∈[−0.6,−0.2]参数:φ1​∈[0.1,0.3], φ2​∈[−0.2,−0.05], φ3​∈[−0.1,0.1], φ4​∈[−0.3,−0.1]参数:α∈[0.3,0.6], β∈[0.2,0.4], γ∈[0.01,0.03]

weixin_49199313的博客 1207

智能家居开源硬件的四层认知体系与资源决策树

智能家居开源硬件并非简单可复用的代码包,而是一套涵盖协议标准、芯片驱动、场景实践与代码实现的分层技术体系。理解Zigbee、Matter等通信协议的强制性规范,掌握Nordic、Silicon Labs等原厂SDK的芯片级行为约束,借鉴OpenHAB、Thread Group等垂直社区的真实环境数据,并审慎评估GitHub项目的认证兼容性与射频设计完备性,是构建可靠硬件系统的基础。这类资源选择直接决定设备互操作性、量产良率与云平台对接成功率,尤其在Home Assistant集成、电池续航优化及EMC合规等

weixin_30235225的博客 326

ROS2 -Jazzy 一步一步(第一步_工作空间以及编译)

文件夹作用特点是否需要手动创建/维护src存放自己写的 ROS 2 包一个 workspace 可以有多个包需要手动创建build保存编译过程中的中间文件每个包生成对应子目录自动生成,可删除install保存编译完成后的功能包每个包有独立子目录,含可执行文件自动生成,可删除log保存编译日志用于查看错误原因、调试自动生成,不需修改colcon是 ROS 2 推荐使用的构建工具自动处理功能包的依赖和编译顺序一条命令就能编译整个工作空间。

jerrykorea的博客 1380

【Matlab 六自由度机器人】基于改进型D-H参数的运动学建模与蒙特卡洛工作空间分析

本文详细介绍了如何使用改进型D-H参数法为六自由度机器人建立运动学模型,并利用Matlab Robotics Toolbox实现正运动学计算与可视化。通过蒙特卡洛法对机器人工作空间进行分析,生成三维点云图以直观展示其可达范围,为机器人选型与任务规划提供关键依据。

weixin_29040367的博客 438

嵌入式工程师成长路径:从STM32裸机到FreeRTOS+Modbus+CAN实战

嵌入式系统开发是以微控制器为核心、软硬协同的工程实践,其本质是通过寄存器配置、中断响应、实时调度与工业协议交互来实现物理世界控制。掌握STM32底层驱动能力是基础,理解FreeRTOS任务调度与上下文切换机制是进阶关键,而Modbus和CAN总线则代表工业现场最广泛部署的通信范式——前者解决设备数据上行标准化,后者保障多节点高可靠实时交互。这些技术共同构成智能硬件、边缘网关、工控终端等岗位的核心能力图谱。本文聚焦真实调试场景,以问题驱动方式串联硬件电路、协议栈实现与系统级调优,覆盖从Keil环境搭建、GPI

weixin_34034261的博客 491

STM32F407用FSMC+DMA驱动LVGL,3.5寸屏流畅度翻倍实战(附CubeMX配置避坑)

本文详细介绍了如何在STM32F407上通过FSMC+DMA驱动LVGL,显著提升3.5寸屏的显示流畅度。从FSMC与DMA的配置原理到LVGL驱动层适配,提供了完整的优化方案和实测数据,帮助开发者解决界面卡顿问题,实现流畅度翻倍的效果。

weixin_30872499的博客 559

ISO15693国产替代:协议栈深度决定远距离读取成败

ISO15693是一种面向远距离、多标签场景的13.56MHz RFID通信协议,其核心在于精密的物理层定时控制与链路层防冲突机制,而非简单的射频收发。它依赖严格的帧结构、副载波相位解调、128μs级响应窗口(FDT/RWT)及二进制树遍历算法,对芯片数字基带处理能力提出极高要求。技术价值体现在工业级稳定识别(≥25cm)、高密度并发(10+标签)与宽温域可靠性(-20℃~70℃),广泛应用于智能门禁、医疗耗材管理、物流资产盘点等国产化关键领域。实践中,仅标称‘兼容ISO15693’的国产芯片往往在协议栈深

weixin_34245082的博客 298

Debezium报错处理系列之二十一:Unable to connect: Communications link failure.The driver has not received any

Debezium报错系列之二十一:Unable to connect: Communications link failure.The driver has not received any。

zhengzaifeidelushang的博客 547

ABAP Cloud:面向云时代的 ABAP 开发范式与实践指南

摘要: 本文系统讲解SAP ABAP Cloud开发模型,涵盖其架构、工具链、规范及实践。ABAP Cloud作为统一开发模型,支持在SAP BTP和S/4HANA上构建云就绪应用,遵循clean core原则,通过RAP(RESTful应用编程模型)实现低耦合扩展。文章详细解析其核心构成(RAP、稳定API、clean core约束)、工具链(ADT、软件物流)及两种典型扩展场景(on-stack与side-by-side),并附可运行RAP示例代码(如销售笔记应用)。重点强调通过规范开发确保系统可升级性

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 393

详解栈帧结构

https://www.1024do.com/?p=367 栈帧结构 含义:C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。栈帧也叫过程活动记录,是编译器用来实现过程函数调用的一种数据结构。 从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里等等。实现上有硬件方式和软件方式(有些体系不支持硬件栈)首先应该明白,...

子曰小玖的博客 9118

Windows服务器环境下 OpenCode Skill 下载与运行全流程实战指南(小白版)

Windows服务器环境下 OpenCode Skill 下载与运行全流程实战指南(小白版),OpenCode技能安装与使用指南,分为四个步骤:1)准备Windows服务器环境并确认OpenCode可用;2)通过Git或直接下载方式获取Skill;3)配置技能路径至.opencode/config.json;4)运行测试技能。关键点包括路径配置必须使用双反斜杠、确保Python环境正确安装、管理员权限运行等。文中提供了文本总结技能的完整案例,从创建skill.yaml和main.py到注册运行的全流程,并针

专注于编程、AI、人工智能等多个领域内容研究和分析 1080

尚硅谷JVM从入门到精通宋红康版|第五章、虚拟机栈

虚拟机栈 虚拟机栈概述 由于跨平台性的设计,Java的指令都是根据栈来设计的。不同平台CPU架构不同,所以不能设计为基于寄存器的。 优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功能需要更多的指令。 有不少Java开发人员一提到Java内存结构,就会非常粗粒度地将JVM中的内存区理解为仅有Java堆(heap)和Java战(stack)?为什么? 首先栈是运行时的单位,而堆是存储的单位 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。 堆解决的是数据存储的问题,即数据怎么放,

weixin_45759791的博客 1484

6.10华为OD机试真题 新系统 - 查找温度记录统计信息 (Java/Py/C/C++/Js/Go)

6.10华为OD机试真题 新系统 - 查找温度记录统计信息 (Java/Py/C/C++/Js/Go)

算法大师! 436

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

上一篇: 10 链接器--定制链接脚本 配合使用系统服务 设计体积受限的可执行程序
下一篇: 关于BIOS 和 主引导程序 的一点随笔
Ma浩然
博客等级 码龄9年 1万+粉丝 462原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ma浩然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值