我试图为atmega控制器做一个多线程库,首先我尝试操作堆栈指针,然后返回函数" go_to_func"该程序进入功能" func"。功能" go_to_func"是在asm1.s文件中编写的,这是一个函数,其中堆栈指针被修改为程序在" func"的起始地址返回。但是我的节目并没有在" func"返回" go_to_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>
答案 0 :(得分:0)
addr_l = (uint8_t)(uint16_t)(stack + stack_size ); addr_h = (uint8_t)(uint16_t)(stack + stack_size + 1);
你的&#34; addr_h&#34;要么需要一些移位,要么你必须在go_to_func()函数中使用r23或r25。 (这不是唯一的错误,但它是最重要的。) 我不知道你为什么不只是传递全长&#34; int&#34; ......
你知道切换任务要比改变SP要多得多,对吗?您还没有对被调用者保存的寄存器做任何事情......
我建议以与处理器相同的方式布局和操作新堆栈,并使用推送器的指针递减...
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中使用模拟器的好时机......