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 中使用模拟器了...