我正在为ARM Cortex M3编写一个简单的多任务操作系统。我的线程总是使用进程堆栈指针运行。我继承了一个应用程序,它使用全局变量。我试图从线程代码中调用应用程序中的函数,但它没有正确地访问内存。下列陈述是否正确:
。
使用PSP的
时切换回PSP。
**编辑:澄清这是为一个皮质M
发布于 2022-06-27 18:27:45
全局变量与堆栈无关,甚至与静态局部变量无关。
所以你只需要看看编译器的输出,它就会告诉你一切。
你的问题很模糊,你可以问许多不同的问题之一。我会展示一些基本知识,也许我会得到幸运。
请注意,一般来说,这应该与处理器、模式等无关--手臂、拇指、x86等等。与工具链有更多的关系。
如果这是太基本,而你是问一些非常高级的问题,这是不明显的,我将删除或重写,没有问题。
抛出代码总是一个解决问题的好主意。
flash.s
.thumb
.syntax unified
.word 0x20001000
.word reset
.thumb_func
reset:
bl notmain
b .notmain.c
unsigned int x;
unsigned int y=5;
void notmain ( void )
{
unsigned int z=7;
x=++y;
z--;
}flash.ld
MEMORY
{
rom : ORIGIN = 0x00080000, LENGTH = 0x00001000
ram : ORIGIN = 0x20000000, LENGTH = 0x00001000
}
SECTIONS
{
.text : { *(.text) } > rom
.bss : { *(.bss) } > ram
.data : { *(.data) } > ram
}构建
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m0 -c notmain.c -o notmain.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o notmain.o -o flash.elf
arm-none-eabi-objdump -D flash.elf > flash.list
arm-none-eabi-objcopy -O binary flash.elf flash.bin检查
Disassembly of section .text:
00080000 <reset-0x8>:
80000: 20001000 andcs r1, r0, r0
80004: 00080009 andeq r0, r8, r9
00080008 <reset>:
80008: f000 f802 bl 80010 <notmain>
8000c: e7fe b.n 8000c <reset+0x4>
...
00080010 <notmain>:
80010: 4b04 ldr r3, [pc, #16] ; (80024 <notmain+0x14>)
80012: 4905 ldr r1, [pc, #20] ; (80028 <notmain+0x18>)
80014: 681a ldr r2, [r3, #0]
80016: 3201 adds r2, #1
80018: 601a str r2, [r3, #0]
8001a: 600a str r2, [r1, #0]
8001c: 685a ldr r2, [r3, #4]
8001e: 3a01 subs r2, #1
80020: 605a str r2, [r3, #4]
80022: 4770 bx lr
80024: 20000004 andcs r0, r0, r4
80028: 20000000 andcs r0, r0, r0
Disassembly of section .bss:
20000000 <x>:
20000000: 00000000 andeq r0, r0, r0
Disassembly of section .data:
20000004 <y>:
20000004: 00000005 andeq r0, r0, r5
20000008 <z.3645>:
20000008: 00000007 andeq r0, r0, r7这是基本的,不可重定位的,等等。
80010: 4b04 ldr r3, [pc, #16] ; (80024 <notmain+0x14>)
80014: 681a ldr r2, [r3, #0]
80016: 3201 adds r2, #1
80018: 601a str r2, [r3, #0]
80024: 20000004 andcs r0, r0, r4
Disassembly of section .data:
20000004 <y>:
20000004: 00000005 andeq r0, r0, r5我们可以看到y++。r3获取y的地址,r2获取y r2增量的值,然后保存回内存。
你也可以看到x和z是如何处理的。
现在,由于以下几个原因,这对于mcu来说是行不通的。0x20000000地址信息将不存在。只有在非易失性存储器中的东西才会在芯片启动和复位后出现。根据你真正的问题是什么,上面的内容是相关的。
MEMORY
{
rom : ORIGIN = 0x00080000, LENGTH = 0x00001000
ram : ORIGIN = 0x20000000, LENGTH = 0x00001000
}
SECTIONS
{
.text : { *(.text) } > rom
.bss : { *(.bss) } > ram AT > rom
.data : { *(.data) } > ram AT > rom
}程序没有改变,但是二进制文件改变了。
00000000 00 10 00 20 09 00 08 00 00 f0 02 f8 fe e7 00 00 |... ............|
00000010 04 4b 05 49 1a 68 01 32 1a 60 0a 60 5a 68 01 3a |.K.I.h.2.`.`Zh.:|
00000020 5a 60 70 47 04 00 00 20 00 00 00 20 05 00 00 00 |Z`pG... ... ....|
00000030 07 00 00 00 |....|
00000034在0x2C,我们看到y的预加载值和z的0x30。
.bss值不在这里。通常,您要做的是向链接器脚本中添加更多的内容,以获取内容的地址。数据开始和停止,和bss启动和大小或停止。然后,一个从flash复制到ram的引导程序,以便初始化的值在ram中,读/写工作。
因此,如果您的项目,无论是否称为操作系统,它只是一个庞大的代码体,被编译和链接在一起。然后不做一些特殊的事情,比如很多章节之类的。以上是您所看到的,堆栈与全局无关。因为它从来都不是正常的。
(msp/psp不像arm所暗示的那样工作,我还没有看到第二个堆栈指针的用例,如果处理器有它,它们也没有全部实现)
现在,如果您的线程实际上是单独构建的程序,您可以加载runtime...Then,那么它们完全位于ram中。所以
MEMORY
{
rom : ORIGIN = 0x00080000, LENGTH = 0x00001000
ram : ORIGIN = 0x20000000, LENGTH = 0x00001000
}
SECTIONS
{
.text : { *(.text) } > ram
.bss : { *(.bss) } > ram
.data : { *(.data) } > ram
}我们加入了-fPIC
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m0 -fPIC -c notmain.c -o notmain.o
Disassembly of section .text:
20000000 <reset-0x8>:
20000000: 20001000 andcs r1, r0, r0
20000004: 20000009 andcs r0, r0, r9
20000008 <reset>:
20000008: f000 f802 bl 20000010 <notmain>
2000000c: e7fe b.n 2000000c <reset+0x4>
...
20000010 <notmain>:
20000010: 4a07 ldr r2, [pc, #28] ; (20000030 <notmain+0x20>)
20000012: 4b08 ldr r3, [pc, #32] ; (20000034 <notmain+0x24>)
20000014: 447a add r2, pc
20000016: 58d1 ldr r1, [r2, r3]
20000018: 680b ldr r3, [r1, #0]
2000001a: 3301 adds r3, #1
2000001c: 600b str r3, [r1, #0]
2000001e: 4906 ldr r1, [pc, #24] ; (20000038 <notmain+0x28>)
20000020: 5852 ldr r2, [r2, r1]
20000022: 6013 str r3, [r2, #0]
20000024: 4a05 ldr r2, [pc, #20] ; (2000003c <notmain+0x2c>)
20000026: 447a add r2, pc
20000028: 6813 ldr r3, [r2, #0]
2000002a: 3b01 subs r3, #1
2000002c: 6013 str r3, [r2, #0]
2000002e: 4770 bx lr
20000030: 00000034 andeq r0, r0, r4, lsr r0
20000034: 00000004 andeq r0, r0, r4
20000038: 00000000 andeq r0, r0, r0
2000003c: 0000001a andeq r0, r0, sl, lsl r0
Disassembly of section .bss:
20000040 <x>:
20000040: 00000000 andeq r0, r0, r0
Disassembly of section .data:
20000044 <z.3645>:
20000044: 00000007 andeq r0, r0, r7
20000048 <y>:
20000048: 00000005 andeq r0, r0, r5
Disassembly of section .got:
2000004c <.got>:
2000004c: 20000040 andcs r0, r0, r0, asr #32
20000050: 20000048 andcs r0, r0, r8, asr #32
Disassembly of section .got.plt:
20000054 <_GLOBAL_OFFSET_TABLE_>:
...因为您可能需要能够在ram中的任何地方(在规则范围内)加载程序。
代码都是相对的,但是由于编译和链接的性质,数据需要一些硬编码。所以他们设置了一个全局偏移表。got的位置相对于代码,您不能更改它。
20000010: 4a07 ldr r2, [pc, #28] ; (20000030 <notmain+0x20>)
20000012: 4b08 ldr r3, [pc, #32] ; (20000034 <notmain+0x24>)
20000014: 447a add r2, pc
20000016: 58d1 ldr r1, [r2, r3]
20000018: 680b ldr r3, [r1, #0]
2000001a: 3301 adds r3, #1
2000001c: 600b str r3, [r1, #0]这是您的y++时,建立独立的位置。
r2得到一个偏移量,r3得到另一个偏移量。r2是与代码之间的GOT的相对偏移量(您不能将它们分开,不能移动其中一个,而不是另一个位置独立的意思),所以现在r2指向got。r3是GOT到y地址的偏移量,r1得到y的地址,现在它就像以前在r3中得到y,添加一个,节省y到内存。
现在,如果您要将这个地址重新定位到一个不是0x20000000的地址,您的引导程序需要转到GOT并修补所有的地址,所以您需要链接魔法才能获得got的位置和它的位数,etc...Use会让pc知道您在哪里,然后进行调整。如果在0x20002000加载到内存中,则需要将0x2000添加到表中的每个条目中,然后所有这些都将正常工作。(仍然没有堆栈,堆栈不相关)。
如果你有空间的话,这是个小把戏。
请注意,我将bss放在数据之前,并且至少有一个.data项。如果您能够保证这一点(例如,在引导中强制一个.data )。
00000000 00 10 00 20 09 00 00 20 00 f0 02 f8 fe e7 00 00 |... ... ........|
00000010 07 4a 08 4b 7a 44 d1 58 0b 68 01 33 0b 60 06 49 |.J.KzD.X.h.3.`.I|
00000020 52 58 13 60 05 4a 7a 44 13 68 01 3b 13 60 70 47 |RX.`.JzD.h.;.`pG|
00000030 34 00 00 00 04 00 00 00 00 00 00 00 1a 00 00 00 |4...............|
00000040 00 00 00 00 07 00 00 00 05 00 00 00 40 00 00 20 |............@.. |
00000050 48 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 |H.. ............|
00000060
20000040 <x>:
20000040: 00000000 andeq r0, r0, r0Objdump将-O二进制的二进制与.bss的零放在一起,如果最后将它放在最后,则假定它不起作用。
因此,我不知道这段代码是如何使用线程和全局的,它是否试图保留每个线程的特定变量?如果是这样的话,它是否在前面使用静态局部变量,然后在堆栈上传递地址(即使在那里,您使用的堆栈指针也不重要,除非您通常没有正确地使用堆栈,如果没有,则全局值不是您的问题。)
如果在一个堆栈指针上启动线程或任何代码,并暗示完全独立的堆栈(内存地址空间)。然后切换,放弃代码进出函数所需的堆栈信息,然后如果在转换堆栈之后从函数返回,所有代码都会中断,而不仅仅是指向传递给静态局部变量的指针。
所以,一个很小的例子可以为我们证实到底发生了什么,你的问题到底是什么,问题是什么。如果您想使用两个堆栈指针作为皮层-m,您需要仔细阅读,您还需要编写一些丢弃的代码示例,看看它是如何工作的,然后将它应用到工具生成的代码中。
再一次,如果这是太基本,而我离真正的问题很远,我肯定会删除这个没有问题。
https://stackoverflow.com/questions/72772325
复制相似问题