LINUX.ORG.RU

Многострочный #define


0

0

Пишу на ассембелере для AVR использую avr-as. Поскольку для компиляции используется avr-gcc, то допускаются директивы Си-препроцессора (#include, #define, ...).

Хочу написать макрос, который бы после препроцессирования преобразовывался в _многострочный_ код.

Пример:

есть кусок кода, вызывающийся довольно часто

ldi r16,num
rcall delay

хочется его заменить на

wait(num)

Поскольку в ассемблере нет символа, разделяющего команды, нужно чтобы макрос становился именно многострочным.

Макрос

#define wait(n) ldi r16,n \
rcall delay

выраждается в

ldi r16,n rcall delay

Соответственно, avr-as матерится на мусор в конце строки:
avr-gcc -I. -mmcu=attiny15 -x assembler-with-cpp -Wa,-gstabs,-ahlms=main.lst -c main.S -o main.o
main.S: Assembler messages:
main.S:100: Error: garbage at end of line
make: *** [main.o] Error 1

anonymous

Х.З, не слышал о такой возможности. Я бы всунул в цепочку еще один препроцессор (sed).

ratatosk
()
Ответ на: комментарий от anonymous

bash-3.2$ cat main.S 
.macro wait n
    ldi r16,\n 
    rcall delay
.endm

.global main
 
main:
        wait 0x15
        rjmp    main     /* loop forever */
 
delay:
        subi r16,0x01
        brne delay
        ret

bash-3.2$ avr-gcc -I. -mmcu=attiny15 -x assembler-with-cpp -Wa,-gstabs,-ahlms=main.lst -c main.S -o main.o

bash-3.2$ cat main.lst
GAS LISTING /tmp/ccijPWU2.s                     page 1


   1                    # 1 "main.S"
   2                    # 1 "<built-in>"
   1                    .macro wait n
   0               
   0               
   2                        ldi r16,\n 
   3                        rcall delay
   4                    .endm
   5               
   6                    .global main
   7                     
   8                    main:
   9:main.S        ****         wait 0x15
   9 0000 05E1          > ldi r16,0x15
   9 0002 00D0          > rcall delay
  10:main.S        ****         rjmp    main     /* loop forever */
  11                     
  12                    delay:
  13:main.S        ****         subi r16,0x01
  14:main.S        ****         brne delay
  15:main.S        ****         ret

GAS LISTING /tmp/ccijPWU2.s                     page 2


DEFINED SYMBOLS
                            *ABS*:00000000 main.S
              main.S:8      .text:00000000 main
              main.S:12     .text:00000006 delay

NO UNDEFINED SYMBOLS

anonymous
()
Ответ на: комментарий от rei3er

Он пишет на ассемблере - у gas есть свой препроцессор - зачем эти извраты с #define. В примере выше я уж все разложил по полочкам :)

bash-3.2$ avr-gcc -I. -mmcu=attiny15 -x assembler-with-cpp -Wa,-gstabs,-ahlms=main.lst  main.S -o main.elf
bash-3.2$ /usr/local/AVR/bin/avr-objdump -S main.elf > main.disasmbash-3.2$ cat main.disasm

main.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__vectors>:
   0:   08 c0           rjmp    .+16            ; 0x12 <__ctors_end>
   2:   08 c0           rjmp    .+16            ; 0x14 <__bad_interrupt>
   4:   07 c0           rjmp    .+14            ; 0x14 <__bad_interrupt>
   6:   06 c0           rjmp    .+12            ; 0x14 <__bad_interrupt>
   8:   05 c0           rjmp    .+10            ; 0x14 <__bad_interrupt>
   a:   04 c0           rjmp    .+8             ; 0x14 <__bad_interrupt>
   c:   03 c0           rjmp    .+6             ; 0x14 <__bad_interrupt>
   e:   02 c0           rjmp    .+4             ; 0x14 <__bad_interrupt>
  10:   01 c0           rjmp    .+2             ; 0x14 <__bad_interrupt>

00000012 <__ctors_end>:
  12:   01 c0           rjmp    .+2             ; 0x16 <main>

00000014 <__bad_interrupt>:
  14:   f5 cf           rjmp    .-22            ; 0x0 <__vectors>

00000016 <main>:

.global main
 
main:
        wait 0x15
  16:   05 e1           ldi     r16, 0x15       ; 21
  18:   01 d0           rcall   .+2             ; 0x1c <delay>
        rjmp    main     /* loop forever */
  1a:   fd cf           rjmp    .-6             ; 0x16 <main>

0000001c <delay>:
 
delay:
        subi r16,0x01
  1c:   01 50           subi    r16, 0x01       ; 1
        brne delay
  1e:   f1 f7           brne    .-4             ; 0x1c <delay>
        ret
  20:   08 95           ret

Видим что все что мы хотели на месте. 
Кстати экранировать \n обязательно - иначе компилятор примет этот символ за метку. Вообще не очень понятно  желание писать на асме :) В этом вся прелесть gcc - это халявный качественный С. 
Куча библиотек готовых для AVR на С есть.

koTuk
()
Ответ на: комментарий от koTuk

> Он пишет на ассемблере - у gas есть свой препроцессор - зачем эти 
> извраты с #define

как это не смешно звучит, но так более переносимо
препроцессор можно использовать в связке с любым компилятором, а не только GAS

rei3er
()
Ответ на: комментарий от rei3er

>как это не смешно звучит, но так более переносимо
>препроцессор можно использовать в связке с любым компилятором, а не только GAS

Звучит не очень оптимистично - у AVR как раз более-менее поддерживается
 у разных реализаций синтаксис оригинального AVR ASM с небольшими своими
 дополнениями к препроцессору расширяющему его возможности. А вот код на
 С разных реализаций (тот же IAR против gcc) напрямую скомпилировать 
удастся далеко не всегда. 

koTuk
()
Ответ на: комментарий от rei3er

>так не пойдет?
>
>#define wait(n) \
>   ldi r16, n; \
>   rcall delay

Собирается без ошибок но код урезается до одной строки - чего и следовало ожидать.

bash-3.2$ cat main.S
#define wait(n) \
    ldi r16, n; \
    rcall delay

.global main
 
main:
        wait (0x15)
        rjmp    main     /* loop forever */
 
delay:
        subi r16,0x01
        brne delay
        ret

bash-3.2$ avr-gcc -I. -mmcu=attiny15 -x assembler-with-cpp -Wa,-gstabs,-ahlms=main.lst  main.S -o main.elf
bash-3.2$ avr-objdump -S main.elf > main.disasm
bash-3.2$ cat main.disasm

main.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__vectors>:
   0:   08 c0           rjmp    .+16            ; 0x12 <__ctors_end>
   2:   08 c0           rjmp    .+16            ; 0x14 <__bad_interrupt>
   4:   07 c0           rjmp    .+14            ; 0x14 <__bad_interrupt>
   6:   06 c0           rjmp    .+12            ; 0x14 <__bad_interrupt>
   8:   05 c0           rjmp    .+10            ; 0x14 <__bad_interrupt>
   a:   04 c0           rjmp    .+8             ; 0x14 <__bad_interrupt>
   c:   03 c0           rjmp    .+6             ; 0x14 <__bad_interrupt>
   e:   02 c0           rjmp    .+4             ; 0x14 <__bad_interrupt>
  10:   01 c0           rjmp    .+2             ; 0x14 <__bad_interrupt>

00000012 <__ctors_end>:
  12:   01 c0           rjmp    .+2             ; 0x16 <main>

00000014 <__bad_interrupt>:
  14:   f5 cf           rjmp    .-22            ; 0x0 <__vectors>

00000016 <main>:

.global main
 
main:
        wait (0x15)
  16:   05 e1           ldi     r16, 0x15       ; 21
        rjmp    main     /* loop forever */
  18:   fe cf           rjmp    .-4             ; 0x16 <main>

0000001a <delay>:
 
delay:
        subi r16,0x01
  1a:   01 50           subi    r16, 0x01       ; 1
        brne delay
  1c:   f1 f7           brne    .-4             ; 0x1a <delay>
        ret
  1e:   08 95           ret

koTuk
()
Ответ на: комментарий от koTuk

> Собирается без ошибок но код урезается до одной строки - чего и 
> следовало ожидать.

вообще говоря странно
gcc для x86-64 интерпретирует ; не как комментарий, а как разделитель инструкций наравне с \n

rei3er
()
Ответ на: комментарий от rei3er

>вообще говоря странно
>gcc для x86-64 интерпретирует ; не как комментарий, а как разделитель инструкций наравне с \n

Ничего странного - gcc для любой архитектуры делает именно так, дело в 
препроцессоре gas впрочем как и любой assembler воспринимает ; как 
коментарий окончанием которого служит перевод строки. При компиляции 
assembler-файла из gcc исходный код проходит оба препроцессора.

#define wait(n) \
    ldi r16, n; \
    rcall delay

.global main

gas воспринимает rcall delay как коментарий следующий после ;

koTuk
()
Ответ на: комментарий от koTuk

епт...

/* main.S */
#define wait(n) \   
    movl    $n, %eax;   \
    ret

.text
main:
    wait(0)
.globl main

# gcc -c main.c
# objdump -d .text main.o

a.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <main>:
   0:   b8 00 00 00 00          mov    $0x0,%eax
   5:   c3                      retq  

rei3er
()
Ответ на: комментарий от rei3er

Мда... на i386 это тоже работает.. Похоже я не прав. Тем не менее 
avr-gcc v.4.2.2 делает так как я запостил выше.

koTuk
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.