Atmega多线程无法操纵堆栈指针

时间:2018-04-05 06:12:39

标签: multithreading disassembly atmega16

我试图为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>

1 个答案:

答案 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中使用模拟器的好时机......