Atmega多线程无法操作堆栈指针
Atmega multithreading can't manipulate stack pointer
我正在尝试为 atmega 控制器创建一个多线程库,首先我尝试操纵堆栈指针,在函数 "go_to_func" 的 return 之后,程序进入函数 "func"。函数 "go_to_func" 写在 asm1.s 文件中,这是在 "func" 的起始地址处将程序的堆栈指针修改为 return 的函数,但我的程序不在 "go_to_func" 的 return 之后 "func" 上的地理坐标(当程序到达 "func" 时,PORTD 位 3 打开)。谁能告诉我我必须在 "go_to_func" 上写些什么才能使我的程序正常运行。下面是我代码的漏洞信息
main.c
#include <avr/io.h>
#include <stdlib.h>
#include "asm1.h"
#define CALL_FCT __attribute__ ((noinline))
#define RETURN_SIZE 2
uint8_t fn_stack[128];
uint8_t addr_l;
uint8_t addr_h;
void CALL_FCT func( void )
{
PORTD = 0x08 ;
while(1)
{
}
}
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
*(stack + stack_size - RETURN_SIZE ) = (uint16_t)fn >> 8;
*(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;
addr_l = (uint8_t)(uint16_t)(stack + stack_size );
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
go_to_func(addr_l,addr_h);
}
int CALL_FCT main(void)
{
DDRD |= 0x0C ;
init(func,fn_stack,sizeof(fn_stack));
PORTD = 0x04 ;
while (1)
{
}
}
asm1.h
#ifndef HEADER_H_
#define HEADER_H_
#include <stdint.h>
extern void go_to_func(uint8_t,uint8_t);
#endif /* HEADER_H_ */
asm1.s
#include <avr/io.h>
.global go_to_func
go_to_func:
out _SFR_IO_ADDR(SPH), r22
out _SFR_IO_ADDR(SPL), r24
ret
/* *.lss the file of my program in assembly */
void CALL_FCT func( void )
{
PORTD = 0x08 ;
96: 88 e0 ldi r24, 0x08 ; 8
98: 8b b9 out 0x0b, r24 ; 11
9a: ff cf rjmp .-2 ; 0x9a <func+0x4>
0000009c <init>:
}
}
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
*(stack + stack_size - RETURN_SIZE ) = (uint16_t)fn >> 8;
9c: 9b 01 movw r18, r22
9e: 24 0f add r18, r20
a0: 35 1f adc r19, r21
a2: f9 01 movw r30, r18
a4: 32 97 sbiw r30, 0x02 ; 2
a6: 90 83 st Z, r25
*(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;
a8: 31 96 adiw r30, 0x01 ; 1
aa: 80 83 st Z, r24
addr_l = (uint8_t)(uint16_t)(stack + stack_size );
ac: 20 93 01 01 sts 0x0101, r18 ; 0x800101 <addr_l>
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
b0: 4f 5f subi r20, 0xFF ; 255
b2: 5f 4f sbci r21, 0xFF ; 255
b4: 64 0f add r22, r20
b6: 75 1f adc r23, r21
b8: 60 93 00 01 sts 0x0100, r22 ; 0x800100 <_edata>
go_to_func(addr_l,addr_h);
bc: 82 2f mov r24, r18
be: 0e 94 48 00 call 0x90 ; 0x90 <go_to_func>
c2: 08 95 ret
000000c4 <main>:
}
int CALL_FCT main(void)
{
DDRD |= 0x0C ;
c4: 8a b1 in r24, 0x0a ; 10
c6: 8c 60 ori r24, 0x0C ; 12
c8: 8a b9 out 0x0a, r24 ; 10
init(func,fn_stack,sizeof(fn_stack));
ca: 40 e8 ldi r20, 0x80 ; 128
cc: 50 e0 ldi r21, 0x00 ; 0
ce: 62 e0 ldi r22, 0x02 ; 2
d0: 71 e0 ldi r23, 0x01 ; 1
d2: 8b e4 ldi r24, 0x4B ; 75
d4: 90 e0 ldi r25, 0x00 ; 0
d6: 0e 94 4e 00 call 0x9c ; 0x9c <init>
PORTD = 0x04 ;
da: 84 e0 ldi r24, 0x04 ; 4
dc: 8b b9 out 0x0b, r24 ; 11
de: ff cf rjmp .-2 ; 0xde <main+0x1a>
000000e0 <_exit>:
e0: f8 94 cli
000000e2 <__stop_program>:
e2: ff cf rjmp .-2 ; 0xe2 <__stop_program>
addr_l = (uint8_t)(uint16_t)(stack + stack_size );
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
您的 "addr_h" 要么需要一些移位,要么您必须在 go_to_func() 函数中使用 r23 或 r25。 (这不是唯一的问题,但这是大问题。)
我不知道你为什么不只是通过 full-length "int" ...
你知道切换任务比改变SP要复杂得多,对吧?你还没有对应该由被调用者保存的寄存器做任何事情...
我建议以与处理器相同的方式布置和操作新堆栈,使用 post-decrement 指针用于推送...
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
uint8_t *newsp = (stack+stack_size) - 1; // last byte of new stack
*newsp-- = (uint8_t)(uint16_t)fn; // "push" low fn addr
*newsp-- = (uint16_t)fn >> 8; // "push" high fn addr
go_to_func(newsp); // newsp is now properly decremented for a "ret"
}
PS: 是时候学习在 AS7 中使用模拟器了...
我正在尝试为 atmega 控制器创建一个多线程库,首先我尝试操纵堆栈指针,在函数 "go_to_func" 的 return 之后,程序进入函数 "func"。函数 "go_to_func" 写在 asm1.s 文件中,这是在 "func" 的起始地址处将程序的堆栈指针修改为 return 的函数,但我的程序不在 "go_to_func" 的 return 之后 "func" 上的地理坐标(当程序到达 "func" 时,PORTD 位 3 打开)。谁能告诉我我必须在 "go_to_func" 上写些什么才能使我的程序正常运行。下面是我代码的漏洞信息
main.c
#include <avr/io.h>
#include <stdlib.h>
#include "asm1.h"
#define CALL_FCT __attribute__ ((noinline))
#define RETURN_SIZE 2
uint8_t fn_stack[128];
uint8_t addr_l;
uint8_t addr_h;
void CALL_FCT func( void )
{
PORTD = 0x08 ;
while(1)
{
}
}
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
*(stack + stack_size - RETURN_SIZE ) = (uint16_t)fn >> 8;
*(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;
addr_l = (uint8_t)(uint16_t)(stack + stack_size );
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
go_to_func(addr_l,addr_h);
}
int CALL_FCT main(void)
{
DDRD |= 0x0C ;
init(func,fn_stack,sizeof(fn_stack));
PORTD = 0x04 ;
while (1)
{
}
}
asm1.h
#ifndef HEADER_H_
#define HEADER_H_
#include <stdint.h>
extern void go_to_func(uint8_t,uint8_t);
#endif /* HEADER_H_ */
asm1.s
#include <avr/io.h>
.global go_to_func
go_to_func:
out _SFR_IO_ADDR(SPH), r22
out _SFR_IO_ADDR(SPL), r24
ret
/* *.lss the file of my program in assembly */
void CALL_FCT func( void )
{
PORTD = 0x08 ;
96: 88 e0 ldi r24, 0x08 ; 8
98: 8b b9 out 0x0b, r24 ; 11
9a: ff cf rjmp .-2 ; 0x9a <func+0x4>
0000009c <init>:
}
}
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
*(stack + stack_size - RETURN_SIZE ) = (uint16_t)fn >> 8;
9c: 9b 01 movw r18, r22
9e: 24 0f add r18, r20
a0: 35 1f adc r19, r21
a2: f9 01 movw r30, r18
a4: 32 97 sbiw r30, 0x02 ; 2
a6: 90 83 st Z, r25
*(stack + stack_size - RETURN_SIZE + 1) = (uint8_t)(uint16_t)fn;
a8: 31 96 adiw r30, 0x01 ; 1
aa: 80 83 st Z, r24
addr_l = (uint8_t)(uint16_t)(stack + stack_size );
ac: 20 93 01 01 sts 0x0101, r18 ; 0x800101 <addr_l>
addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
b0: 4f 5f subi r20, 0xFF ; 255
b2: 5f 4f sbci r21, 0xFF ; 255
b4: 64 0f add r22, r20
b6: 75 1f adc r23, r21
b8: 60 93 00 01 sts 0x0100, r22 ; 0x800100 <_edata>
go_to_func(addr_l,addr_h);
bc: 82 2f mov r24, r18
be: 0e 94 48 00 call 0x90 ; 0x90 <go_to_func>
c2: 08 95 ret
000000c4 <main>:
}
int CALL_FCT main(void)
{
DDRD |= 0x0C ;
c4: 8a b1 in r24, 0x0a ; 10
c6: 8c 60 ori r24, 0x0C ; 12
c8: 8a b9 out 0x0a, r24 ; 10
init(func,fn_stack,sizeof(fn_stack));
ca: 40 e8 ldi r20, 0x80 ; 128
cc: 50 e0 ldi r21, 0x00 ; 0
ce: 62 e0 ldi r22, 0x02 ; 2
d0: 71 e0 ldi r23, 0x01 ; 1
d2: 8b e4 ldi r24, 0x4B ; 75
d4: 90 e0 ldi r25, 0x00 ; 0
d6: 0e 94 4e 00 call 0x9c ; 0x9c <init>
PORTD = 0x04 ;
da: 84 e0 ldi r24, 0x04 ; 4
dc: 8b b9 out 0x0b, r24 ; 11
de: ff cf rjmp .-2 ; 0xde <main+0x1a>
000000e0 <_exit>:
e0: f8 94 cli
000000e2 <__stop_program>:
e2: ff cf rjmp .-2 ; 0xe2 <__stop_program>
addr_l = (uint8_t)(uint16_t)(stack + stack_size ); addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
您的 "addr_h" 要么需要一些移位,要么您必须在 go_to_func() 函数中使用 r23 或 r25。 (这不是唯一的问题,但这是大问题。) 我不知道你为什么不只是通过 full-length "int" ...
你知道切换任务比改变SP要复杂得多,对吧?你还没有对应该由被调用者保存的寄存器做任何事情...
我建议以与处理器相同的方式布置和操作新堆栈,使用 post-decrement 指针用于推送...
void CALL_FCT init( void (*fn)(void), uint8_t* stack, uint16_t stack_size)
{
uint8_t *newsp = (stack+stack_size) - 1; // last byte of new stack
*newsp-- = (uint8_t)(uint16_t)fn; // "push" low fn addr
*newsp-- = (uint16_t)fn >> 8; // "push" high fn addr
go_to_func(newsp); // newsp is now properly decremented for a "ret"
}
PS: 是时候学习在 AS7 中使用模拟器了...