avr-g++ generating wrong code for function in init section

Go To Last Post
24 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

when compiling the following code with avr-g++ 4.3.3 using -Wall -O2 -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -std=gnu99 -funsigned-char -funsigned-bitfields -mmcu=atmega1281:

void assertion_lite(void) __attribute__ ((noreturn));

void get_mcusr(void) __attribute__ ((naked, section(".init3")));
void get_mcusr(void)
{
    if (!(SP == RAMEND)) assertion_lite();
}

I get the following assembler:

000003de <_Z9get_mcusrv>:
     3de:	8d b7       	in	r24, 0x3d	; 61
     3e0:	9e b7       	in	r25, 0x3e	; 62
     3e2:	8f 5f       	subi	r24, 0xFF	; 255
     3e4:	91 42       	sbci	r25, 0x21	; 33
     3e6:	01 f4       	brne	.+0      	; 0x3e8 <_Z9get_mcusrv+0xa>
     3e8:	4c d0       	rcall	.+152    	; 0x482 <_Z14assertion_litev>

000003ea <__do_copy_data>:
     3ea:	12 e0       	ldi	r17, 0x02	; 2
     3ec:	a0 e0       	ldi	r26, 0x00	; 0
.
.
.

which is obviously wrong, since assertion_lite() is called regardless of the SP check (I don't if this happens because the compiler doesn't correctly handle that the function has no ret instruction due to being in the .initx chain). Has anybody seen this issue before, and if so, is there a way to get around it?

 

Thanks.

 

NB. Using -Os or -O1 I don't get this problem (it evaluates to a breq +2 that skips the rcall.

Last Edited: Wed. Feb 7, 2018 - 04:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hooverphonique wrote:
which is obviously wrong,
Looks like code that has not been linked (in which case things like branch offsets default to 0 until the fixup performed at link time has been done).

 

Show your toolchain invocation.

 

BTW why use such an astronomically old version anyway? 4.3.3 is now 8+ years old.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK so as a test I tried this:

C:\SysGCC\avr\bin>type avr.cpp
#include <avr/io.h>

void assertion_lite(void) __attribute__ ((noreturn));

void get_mcusr(void) __attribute__ ((naked, section(".init3")));
void get_mcusr(void)
{
    if (!(SP == RAMEND)) assertion_lite();
}

void assertion_lite(void) {
        while(1);
}

int main(void) {

}
C:\SysGCC\avr\bin>avr-gcc -Wall -O2 -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -std=gnu99 -funsigned-char -funsigned-bitfields -m
mcu=atmega1281 avr.cpp -o avr.elf
cc1plus.exe: warning: command line option '-std=gnu99' is valid for C/ObjC but not for C++

C:\SysGCC\avr\bin>avr-objdump.exe -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0c 94 66 00     jmp     0xcc    ; 0xcc <__ctors_end>
   4:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
   8:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
   c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  10:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  14:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  18:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  1c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  20:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  24:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  28:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  2c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  30:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  34:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  38:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  3c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  40:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  44:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  48:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  4c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  50:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  54:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  58:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  5c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  60:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  64:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  68:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  6c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  70:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  74:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  78:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  7c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  80:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  84:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  88:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  8c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  90:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  94:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  98:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  9c:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  a0:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  a4:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  a8:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  ac:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  b0:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  b4:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  b8:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  bc:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  c0:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  c4:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>
  c8:   0c 94 76 00     jmp     0xec    ; 0xec <__bad_interrupt>

000000cc <__ctors_end>:
  cc:   11 24           eor     r1, r1
  ce:   1f be           out     0x3f, r1        ; 63
  d0:   cf ef           ldi     r28, 0xFF       ; 255
  d2:   d1 e2           ldi     r29, 0x21       ; 33
  d4:   de bf           out     0x3e, r29       ; 62
  d6:   cd bf           out     0x3d, r28       ; 61

000000d8 <_Z9get_mcusrv>:
  d8:   8d b7           in      r24, 0x3d       ; 61
  da:   9e b7           in      r25, 0x3e       ; 62
  dc:   8f 3f           cpi     r24, 0xFF       ; 255
  de:   91 42           sbci    r25, 0x21       ; 33
  e0:   09 f0           breq    .+2             ; 0xe4 <_Z9get_mcusrv+0xc>
  e2:   ff cf           rjmp    .-2             ; 0xe2 <_Z9get_mcusrv+0xa>
  e4:   0e 94 79 00     call    0xf2    ; 0xf2 <main>
  e8:   0c 94 7c 00     jmp     0xf8    ; 0xf8 <_exit>

000000ec <__bad_interrupt>:
  ec:   0c 94 00 00     jmp     0       ; 0x0 <__vectors>

000000f0 <_Z14assertion_litev>:
  f0:   ff cf           rjmp    .-2             ; 0xf0 <_Z14assertion_litev>

000000f2 <main>:
  f2:   80 e0           ldi     r24, 0x00       ; 0
  f4:   90 e0           ldi     r25, 0x00       ; 0
  f6:   08 95           ret

000000f8 <_exit>:
  f8:   f8 94           cli

000000fa <__stop_program>:
  fa:   ff cf           rjmp    .-2             ; 0xfa <__stop_program>

Which apparently worked just fine. Do note the warning about use of -std=gnu99 I imagine you really meant to use -std=g++98 or similar (and that is 98 not 99)? Your version should also support -std=g++03 but being so old you won't have access to the likes of -std=g++11, -std=g++14, -std=g++17

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

PS was there ever any doubt that for a 1281 that SP==RAMEND (like all "modern" AVR it loads that at power on) ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

hooverphonique wrote:
which is obviously wrong,
Looks like code that has not been linked (in which case things like branch offsets default to 0 until the fixup performed at link time has been done).

 

Show your toolchain invocation.

 

BTW why use such an astronomically old version anyway? 4.3.3 is now 8+ years old.

 

no, the zero is not due to no linking.. the assembly is taken from the listing file generated from the elf. I use that avr-gcc version since it is part of the latest winavr release (that I could find, anyway) - I should replace it, I know :-/

 

To prove it's not a linking fixup issue, take a look at this:

void get_mcusr(void) __attribute__ ((naked, section(".init3")));
void get_mcusr(void)
{
	if (!(SP == RAMEND)) assertion_lite();
	// reserves space at the top of sram for the reboot cookie
	__asm__ __volatile__ ( "push __zero_reg__ \n\t" : : );
}

with -Os it (correctly) becomes:

000003de <_Z9get_mcusrv>:
     3de:	8d b7       	in	r24, 0x3d	; 61
     3e0:	9e b7       	in	r25, 0x3e	; 62
     3e2:	8f 5f       	subi	r24, 0xFF	; 255
     3e4:	91 42       	sbci	r25, 0x21	; 33
     3e6:	09 f0       	breq	.+2      	; 0x3ea <_Z9get_mcusrv+0xc>
     3e8:	4d d0       	rcall	.+154    	; 0x484 <_Z14assertion_litev>
     3ea:	1f 92       	push	r1

with -O2 it (wrongly) becomes:

000003de <_Z9get_mcusrv>:
     3de:	8d b7       	in	r24, 0x3d	; 61
     3e0:	9e b7       	in	r25, 0x3e	; 62
     3e2:	8f 5f       	subi	r24, 0xFF	; 255
     3e4:	91 42       	sbci	r25, 0x21	; 33
     3e6:	09 f4       	brne	.+2      	; 0x3ea <_Z9get_mcusrv+0xc>
     3e8:	1f 92       	push	r1
     3ea:	4c d0       	rcall	.+152    	; 0x484 <_Z14assertion_litev>

instead of skipping the call to assertion_lite, it skips the push r1 instruction.

 

I did *not* touch the source code in between those two compiler invocations.

 

I'm using the same get_mcusr function in a different project where it compiles correctly, so it seems it's a side effect of some sort.

 

Maybe it's stupid to check the value of SP (it is initalized to x021FF in .init2 by the compiler), but that is beside the point :-)

Last Edited: Wed. Feb 7, 2018 - 05:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried to compile it with avr-g++ 4.9.2 from the atmel toolchain, which generates the following with -O2:

000003d2 <_Z9get_mcusrv>:
     3d2:	8d b7       	in	r24, 0x3d	; 61
     3d4:	9e b7       	in	r25, 0x3e	; 62
     3d6:	8f 3f       	cpi	r24, 0xFF	; 255
     3d8:	91 42       	sbci	r25, 0x21	; 33
     3da:	09 f0       	breq	.+2      	; 0x3de <_Z9get_mcusrv+0xc>
     3dc:	50 d0       	rcall	.+160    	; 0x47e <_Z14assertion_litev>
     3de:	1f 92       	push	r1

which looks fine - I haven't tried to run it yet, though, as I'm away from the target hardware. Of course there could be other differences now which causes different behavior in other parts of the code base.

Oddly I'm getting some C++11 warnings about narrowing even though I have "-std=gnu++98" in the compiler options (if I use "-std=g++98" I get an unrecognized option error)I.

Last Edited: Wed. Feb 7, 2018 - 09:40 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Congrats with your new compiler.

Ther doesn't seem to be a "-std=g++98" in the version I have either. You can try "-std=c++98"

 

Maybe you also want to toy around with some other new standards.

There seem to be quite some changes in the last few years, especiially in the "++" part of course.

https://isocpp.org/

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you are running windows and want to play with the bleeding edge avr-gcc (version 8.0.1), forum member sprintersb has recently posted a version compiled with mingw:

https://osdn.net/projects/sfnet_...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ther doesn't seem to be a "-std=g++98" in the version I have either.

My typo. blush

 

The standards supported, as the user manual will tell you, are either -std=c++98 or -std=gnu++98. I mistakenly typed -std=g++98 above without the "nu".

 

BTW I found that you can do this:

C:\SysGCC\avr\bin>avr-gcc --help=c++
The following options are supported by the language C++:
  --all-warnings              This switch lacks documentation
  --ansi                      This switch lacks documentation
  --assert                    This switch lacks documentation
  --assert=                   This switch lacks documentation
  --comments                  This switch lacks documentation
  --comments-in-macros        This switch lacks documentation
  --define-macro              This switch lacks documentation
  --define-macro=             This switch lacks documentation
  --dependencies              This switch lacks documentation
  --dump                      This switch lacks documentation
  --dump=                     This switch lacks documentation
  --imacros                   This switch lacks documentation
  --imacros=                  This switch lacks documentation
  --include                   This switch lacks documentation
  --include-barrier           This switch lacks documentation
  --include-directory         This switch lacks documentation
  --include-directory-after   This switch lacks documentation
  --include-directory-after=  This switch lacks documentation
  --include-directory=        This switch lacks documentation
  --include-prefix            This switch lacks documentation
  --include-prefix=           This switch lacks documentation
  --include-with-prefix       This switch lacks documentation
  --include-with-prefix-after This switch lacks documentation
  --include-with-prefix-after= This switch lacks documentation
  --include-with-prefix-before This switch lacks documentation
  --include-with-prefix-before= This switch lacks documentation
  --include-with-prefix=      This switch lacks documentation
  --include=                  This switch lacks documentation
  --no-line-commands          This switch lacks documentation
  --no-standard-includes      This switch lacks documentation
  --no-warnings               This switch lacks documentation
  --output                    This switch lacks documentation
  --output-pch=               This switch lacks documentation
  --output=                   This switch lacks documentation
  --pedantic                  This switch lacks documentation
  --preprocess                This switch lacks documentation
  --print-missing-file-dependencies This switch lacks documentation
  --trace-includes            This switch lacks documentation
  --traditional-cpp           This switch lacks documentation
  --trigraphs                 This switch lacks documentation
  --undefine-macro            This switch lacks documentation
  --undefine-macro=           This switch lacks documentation
  --user-dependencies         This switch lacks documentation
  --verbose                   This switch lacks documentation
  --write-dependencies        This switch lacks documentation
  --write-user-dependencies   This switch lacks documentation
  -A<question>=<answer>       Assert the <answer> to <question>.  Putting '-'
                              before <question> disables the <answer> to
                              <question>
  -C                          Do not discard comments
  -CC                         Do not discard comments in macro expansions
  -D<macro>[=<val>]           Define a <macro> with <val> as its value.  If
                              just <macro> is given, <val> is taken to be 1
  -E                          This switch lacks documentation
  -F <dir>                    Add <dir> to the end of the main framework
                              include path
  -H                          Print the name of header files as they are used
  -I <dir>                    Add <dir> to the end of the main include path
  -M                          Generate make dependencies
  -MD                         Generate make dependencies and compile
  -MF <file>                  Write dependency output to the given file
  -MG                         Treat missing header files as generated files
  -MM                         Like -M but ignore system header files
  -MMD                        Like -MD but ignore system header files
  -MP                         Generate phony targets for all headers
  -MQ <target>                Add a MAKE-quoted target
  -MT <target>                Add an unquoted target
  -P                          Do not generate #line directives
  -U<macro>                   Undefine <macro>
  -Wabi                       Warn about things that will change when compiling
                              with an ABI-compliant compiler
  -Wabi-tag                   Warn if a subobject has an abi_tag attribute that
                              the complete object type does not have
  -Wabi=                      Warn about things that change between the current
                              -fabi-version and the specified version
  -Waddress                   Warn about suspicious uses of memory addresses
  -Wall                       Enable most warning messages
  -Wbool-compare              Warn about boolean expression compared with an
                              integer value different from true/false
  -Wbuiltin-macro-redefined   Warn when a built-in preprocessor macro is
                              undefined or redefined
  -Wc++0x-compat              Deprecated in favor of -Wc++11-compat
  -Wc++11-compat              Warn about C++ constructs whose meaning differs
                              between ISO C++ 1998 and ISO C++ 2011
  -Wc++14-compat              Warn about C++ constructs whose meaning differs
                              between ISO C++ 2011 and ISO C++ 2014
  -Wcast-qual                 Warn about casts which discard qualifiers
  -Wchar-subscripts           Warn about subscripts whose type is "char"
  -Wchkp                      Warn about memory access errors found by Pointer
                              Bounds Checker
  -Wclobbered                 Warn about variables that might be changed by
                              "longjmp" or "vfork"
  -Wcomment                   Warn about possibly nested block comments, and
                              C++ comments spanning more than one physical line
  -Wcomments                  Synonym for -Wcomment
  -Wconditionally-supported   Warn for conditionally-supported constructs
  -Wconversion                Warn for implicit type conversions that may
                              change a value
  -Wconversion-null           Warn for converting NULL from/to a non-pointer
                              type
  -Wcpp                       Warn when a #warning directive is encountered
  -Wctor-dtor-privacy         Warn when all constructors and destructors are
                              private
  -Wdate-time                 Warn about __TIME__, __DATE__ and __TIMESTAMP__
                              usage
  -Wdelete-incomplete         Warn when deleting a pointer to incomplete type
  -Wdelete-non-virtual-dtor   Warn about deleting polymorphic objects with non-
                              virtual destructors
  -Wdeprecated                Warn if a deprecated compiler feature, class,
                              method, or field is used
  -Wdiv-by-zero               Warn about compile-time integer division by zero
  -Wdouble-promotion          Warn about implicit conversions from "float" to
                              "double"
  -Weffc++                    Warn about violations of Effective C++ style rules
  -Wempty-body                Warn about an empty body in an if or else
                              statement
  -Wendif-labels              Warn about stray tokens after #elif and #endif
  -Wenum-compare              Warn about comparison of different enum types
  -Werror                     Treat all warnings as errors
  -Wfloat-conversion          Warn for implicit type conversions that cause
                              loss of floating point precision
  -Wfloat-equal               Warn if testing floating point numbers for
                              equality
  -Wformat                    Warn about printf/scanf/strftime/strfmon format
                              string anomalies
  -Wformat-contains-nul       Warn about format strings that contain NUL bytes
  -Wformat-extra-args         Warn if passing too many arguments to a function
                              for its format string
  -Wformat-nonliteral         Warn about format strings that are not literals
  -Wformat-security           Warn about possible security problems with format
                              functions
  -Wformat-signedness         Warn about sign differences with format functions
  -Wformat-y2k                Warn about strftime formats yielding 2-digit years
  -Wformat-zero-length        Warn about zero-length formats
  -Wformat=                   Warn about printf/scanf/strftime/strfmon format
                              string anomalies
  -Wignored-qualifiers        Warn whenever type qualifiers are ignored.
  -Wimport                    This switch lacks documentation
  -Winherited-variadic-ctor   Warn about C++11 inheriting constructors when the
                              base has a variadic constructor
  -Winit-self                 Warn about variables which are initialized to
                              themselves
  -Wint-to-pointer-cast       Warn when there is a cast to a pointer from an
                              integer of a different size
  -Winvalid-offsetof          Warn about invalid uses of the "offsetof" macro
  -Winvalid-pch               Warn about PCH files that are found but not used
  -Wliteral-suffix            Warn when a string or character literal is
                              followed by a ud-suffix which does not begin with
                              an underscore.
  -Wlogical-not-parentheses   Warn when logical not is used on the left hand
                              side operand of a comparison
  -Wlogical-op                Warn when a logical operator is suspiciously
                              always evaluating to true or false
  -Wlong-long                 Do not warn about using "long long" when -pedantic
  -Wmain                      Warn about suspicious declarations of "main"
  -Wmaybe-uninitialized       Warn about maybe uninitialized automatic variables
  -Wmemset-transposed-args    Warn about suspicious calls to memset where the
                              third argument is constant literal zero and the
                              second is not
  -Wmissing-braces            Warn about possibly missing braces around
                              initializers
  -Wmissing-declarations      Warn about global functions without previous
                              declarations
  -Wmissing-field-initializers Warn about missing fields in struct initializers
  -Wmissing-format-attribute  This switch lacks documentation
  -Wmissing-include-dirs      Warn about user-specified include directories
                              that do not exist
  -Wmudflap                   This switch lacks documentation
  -Wmultichar                 Warn about use of multi-character character
                              constants
  -Wnarrowing                 Warn about narrowing conversions within { } that
                              are ill-formed in C++11
  -Wnoexcept                  Warn when a noexcept expression evaluates to
                              false even though the expression can't actually
                              throw
  -Wnon-template-friend       Warn when non-templatized friend functions are
                              declared within a template
  -Wnon-virtual-dtor          Warn about non-virtual destructors
  -Wnonnull                   Warn about NULL being passed to argument slots
                              marked as requiring non-NULL
  -Wnormalized                This switch lacks documentation
  -Wnormalized=<none|id|nfc|nfkc> Warn about non-normalised Unicode strings
  -Wold-style-cast            Warn if a C-style cast is used in a program
  -Wopenmp-simd               Warn if a simd directive is overridden by the
                              vectorizer cost model
  -Woverlength-strings        Warn if a string is longer than the maximum
                              portable length specified by the standard
  -Woverloaded-virtual        Warn about overloaded virtual function names
  -Wpacked-bitfield-compat    Warn about packed bit-fields whose offset changed
                              in GCC 4.4
  -Wparentheses               Warn about possibly missing parentheses
  -Wpedantic                  Issue warnings needed for strict compliance to
                              the standard
  -Wpmf-conversions           Warn when converting the type of pointers to
                              member functions
  -Wpointer-arith             Warn about function pointer arithmetic
  -Wpragmas                   Warn about misuses of pragmas
  -Wpsabi                     This switch lacks documentation
  -Wredundant-decls           Warn about multiple declarations of the same
                              object
  -Wreorder                   Warn when the compiler reorders code
  -Wreturn-type               Warn whenever a function's return type defaults
                              to "int" (C), or about inconsistent return types
                              (C++)
  -Wsequence-point            Warn about possible violations of sequence point
                              rules
  -Wshift-count-negative      Warn if shift count is negative
  -Wshift-count-overflow      Warn if shift count >= width of type
  -Wsign-compare              Warn about signed-unsigned comparisons
  -Wsign-conversion           Warn for implicit type conversions between signed
                              and unsigned integers
  -Wsign-promo                Warn when overload promotes from unsigned to
                              signed
  -Wsized-deallocation        Warn about missing sized deallocation functions
  -Wsizeof-array-argument     Warn when sizeof is applied on a parameter
                              declared as an array
  -Wsizeof-pointer-memaccess  Warn about suspicious length parameters to
                              certain string functions if the argument uses
                              sizeof
  -Wstrict-aliasing=          Warn about code which might break strict aliasing
                              rules
  -Wstrict-null-sentinel      Warn about uncasted NULL used as sentinel
  -Wstrict-overflow=          Warn about optimizations that assume that signed
                              overflow is undefined
  -Wsuggest-attribute=format  Warn about functions which might be candidates
                              for format attributes
  -Wsuggest-override          Suggest that the override keyword be used when
                              the declaration of a virtual function overrides
                              another.
  -Wswitch                    Warn about enumerated switches, with no default,
                              missing a case
  -Wswitch-bool               Warn about switches with boolean controlling
                              expression
  -Wswitch-default            Warn about enumerated switches missing a
                              "default:" statement
  -Wswitch-enum               Warn about all enumerated switches missing a
                              specific case
  -Wsync-nand                 Warn when __sync_fetch_and_nand and
                              __sync_nand_and_fetch built-in functions are used
  -Wsynth                     Deprecated.  This switch has no effect
  -Wsystem-headers            Do not suppress warnings from system headers
  -Wtrigraphs                 Warn if trigraphs are encountered that might
                              affect the meaning of the program
  -Wundef                     Warn if an undefined macro is used in an #if
                              directive
  -Wuninitialized             Warn about uninitialized automatic variables
  -Wunknown-pragmas           Warn about unrecognized pragmas
  -Wunused                    Enable all -Wunused- warnings
  -Wunused-local-typedefs     Warn when typedefs locally defined in a function
                              are not used
  -Wunused-macros             Warn about macros defined in the main file that
                              are not used
  -Wunused-result             Warn if a caller of a function, marked with
                              attribute warn_unused_result, does not use its
                              return value
  -Wuseless-cast              Warn about useless casts
  -Wvarargs                   Warn about questionable usage of the macros used
                              to retrieve variable arguments
  -Wvariadic-macros           Warn about using variadic macros
  -Wvirtual-move-assign       Warn if a virtual base has a non-trivial move
                              assignment operator
  -Wvla                       Warn if a variable length array is used
  -Wvolatile-register-var     Warn when a register variable is declared volatile
  -Wwrite-strings             In C++, nonzero means warn about deprecated
                              conversion from string literals to 'char *'.  In
                              C, similar warning, except that the conversion is
                              of course not deprecated by the ISO C standard.
  -Wzero-as-null-pointer-constant Warn when a literal '0' is used as null
                              pointer
  -ansi                       A synonym for -std=c89 (for C) or -std=c++98 (for
                              C++)
  -d<letters>                 Enable dumps from specific passes of the compiler
  -fabi-compat-version=       The version of the C++ ABI used for -Wabi
                              warnings and link compatibility aliases
  -faccess-control            Enforce class member access control semantics
  -fada-spec-parent=          -fada-spec-parent=unit  Dump Ada specs as child
                              units of given parent
  -fall-virtual               This switch lacks documentation
  -falt-external-templates    No longer supported
  -fasm                       Recognize the "asm" keyword
  -fbuilding-libgcc           This switch lacks documentation
  -fbuiltin                   Recognize built-in functions
  -fbuiltin-                  This switch lacks documentation
  -fcanonical-system-headers  Where shorter, use canonicalized paths to systems
                              headers.
  -fcheck-pointer-bounds      Add Pointer Bounds Checker instrumentation.
                              fchkp-* flags are used to control
                              instrumentation.  Currently available for C, C++
                              and ObjC.
  -fchkp-check-incomplete-type Generate pointer bounds checks for variables
                              with incomplete type
  -fchkp-check-read           Generate checks for all read accesses to memory.
  -fchkp-check-write          Generate checks for all write accesses to memory.
  -fchkp-first-field-has-own-bounds Forces Pointer Bounds Checker to use
                              narrowed bounds for address of the first field in
                              the structure.  By default pointer to the first
                              field has the same bounds as pointer to the whole
                              structure.
  -fchkp-instrument-calls     Generate bounds passing for calls.
  -fchkp-instrument-marked-only Instrument only functions marked with
                              bnd_instrument attribute.
  -fchkp-narrow-bounds        Control how Pointer Bounds Checker handle
                              pointers to object fields.  When narrowing is on,
                              field bounds are used.  Otherwise full object
                              bounds are used.
  -fchkp-narrow-to-innermost-array Forces Pointer Bounds Checker to use bounds
                              of the innermost arrays in case of nested static
                              arryas access.  By default outermost array is
                              used.
  -fchkp-optimize             Allow Pointer Bounds Checker optimizations.  By
                              default allowed on optimization levels >0.
  -fchkp-store-bounds         Generate bounds stores for pointer writes.
  -fchkp-treat-zero-dynamic-size-as-infinite With this option zero size
                              obtained dynamically for objects with incomplete
                              type will be treated as infinite.
  -fchkp-use-fast-string-functions Allow to use *_nobnd versions of string
                              functions by Pointer Bounds Checker.
  -fchkp-use-nochk-string-functions Allow to use *_nochk versions of string
                              functions by Pointer Bounds Checker.
  -fchkp-use-static-bounds    Use statically initialized variable for vars
                              bounds instead of generating them each time it is
                              required.
  -fchkp-use-static-const-bounds Use statically initialized variable for
                              constant bounds instead of generating them each
                              time it is required.
  -fchkp-use-wrappers         Transform instrumented builtin calls into calls
                              to wrappers.
  -fchkp-zero-input-bounds-for-main Use zero bounds for all incoming arguments
                              in 'main' function.  It helps when instrumented
                              binaries are used with legacy libs.
  -fcilkplus                  Enable Cilk Plus
  -fcond-mismatch             Allow the arguments of the '?' operator to have
                              different types
  -fconserve-space            Does nothing.  Preserved for backward
                              compatibility.
  -fconstexpr-depth=<number>  Specify maximum constexpr recursion depth
  -fdebug-cpp                 Emit debug annotations during preprocessing
  -fdeclone-ctor-dtor         Factor complex constructors and destructors to
                              favor space over speed
  -fdeduce-init-list          enable deduction of std::initializer_list for a
                              template type parameter from a brace-enclosed
                              initializer-list
  -fdefault-inline            Does nothing.  Preserved for backward
                              compatibility.
  -fdirectives-only           Preprocess directives only.
  -fdollars-in-identifiers    Permit '$' as an identifier character
  -fdump-ada-spec             Write all declarations as Ada code transitively
  -fdump-ada-spec-slim        Write all declarations as Ada code for the given
                              file only
  -felide-constructors        This switch lacks documentation
  -femit-struct-debug-baseonly Aggressive reduced debug info for structs
  -femit-struct-debug-detailed=<spec-list> Detailed reduced debug info for
                              structs
  -femit-struct-debug-reduced Conservative reduced debug info for structs
  -fenforce-eh-specs          Generate code to check exception specifications
  -fenum-int-equiv            This switch lacks documentation
  -fexec-charset=<cset>       Convert all strings and character constants to
                              character set <cset>
  -fext-numeric-literals      Interpret imaginary, fixed-point, or other gnu
                              number suffix as the corresponding number literal
                              rather than a user-defined number literal.
  -fextended-identifiers      Permit universal character names (\u and \U) in
                              identifiers
  -fextern-tls-init           Support dynamic initialization of thread-local
                              variables in a different translation unit
  -fexternal-templates        This switch lacks documentation
  -ffor-scope                 Scope of for-init-statement variables is local to
                              the loop
  -ffreestanding              Do not assume that standard C libraries and
                              "main" exist
  -ffriend-injection          Inject friend functions into enclosing namespace
  -fgnu-keywords              Recognize GNU-defined keywords
  -fguiding-decls             This switch lacks documentation
  -fhandle-exceptions         This switch lacks documentation
  -fhonor-std                 This switch lacks documentation
  -fhuge-objects              No longer supported
  -fimplement-inlines         Export functions even if they can be inlined
  -fimplicit-inline-templates Emit implicit instantiations of inline templates
  -fimplicit-templates        Emit implicit instantiations of templates
  -finput-charset=<cset>      Specify the default character set for source files
  -flabels-ok                 This switch lacks documentation
  -flax-vector-conversions    Allow implicit conversions between vectors with
                              differing numbers of subparts and/or differing
                              element types.
  -fms-extensions             Don't warn about uses of Microsoft extensions
  -fmudflap                   This switch lacks documentation
  -fmudflapir                 This switch lacks documentation
  -fmudflapth                 This switch lacks documentation
  -fname-mangling-version-    This switch lacks documentation
  -fnew-abi                   This switch lacks documentation
  -fnonansi-builtins          This switch lacks documentation
  -fnonnull-objects           This switch lacks documentation
  -fnothrow-opt               Treat a throw() exception specification as
                              noexcept to improve code size
  -fopenacc                   Enable OpenACC
  -fopenmp                    Enable OpenMP (implies -frecursive in Fortran)
  -fopenmp-simd               Enable OpenMP's SIMD directives
  -foperator-names            Recognize C++ keywords like "compl" and "xor"
  -foptional-diags            Does nothing.  Preserved for backward
                              compatibility.
  -fpch-deps                  This switch lacks documentation
  -fpch-preprocess            Look for and use PCH files even when preprocessing
  -fpermissive                Downgrade conformance errors to warnings
  -fpreprocessed              Treat the input file as already preprocessed
  -fpretty-templates          -fno-pretty-templates Do not pretty-print
                              template specializations as the template
                              signature followed by the arguments
  -frepo                      Enable automatic template instantiation
  -frtti                      Generate run time type descriptor information
  -fshort-double              Use the same size for double as for float
  -fshort-enums               Use the narrowest integer type possible for
                              enumeration types
  -fshort-wchar               Force the underlying type for "wchar_t" to be
                              "unsigned short"
  -fsigned-bitfields          When "signed" or "unsigned" is not given make the
                              bitfield signed
  -fsigned-char               Make "char" signed by default
  -fsized-deallocation        Enable C++14 sized deallocation support
  -fsquangle                  This switch lacks documentation
  -fstats                     Display statistics accumulated during compilation
  -fstrict-enums              Assume that values of enumeration type are always
                              within the minimum range of that type
  -fstrict-prototype          This switch lacks documentation
  -ftabstop=<number>          Distance between tab stops for column reporting
  -ftemplate-backtrace-limit= Set the maximum number of template instantiation
                              notes for a single warning or error
  -ftemplate-depth-           This switch lacks documentation
  -ftemplate-depth=<number>   Specify maximum template instantiation depth
  -fthis-is-variable          This switch lacks documentation
  -fno-threadsafe-statics     Do not generate thread-safe code for initializing
                              local statics
  -ftrack-macro-expansion     This switch lacks documentation
  -ftrack-macro-expansion=    -ftrack-macro-expansion=<0|1|2>  Track locations
                              of tokens coming from macro expansion and display
                              them in error messages
  -funsigned-bitfields        When "signed" or "unsigned" is not given make the
                              bitfield unsigned
  -funsigned-char             Make "char" unsigned by default
  -fuse-cxa-atexit            Use __cxa_atexit to register destructors
  -fuse-cxa-get-exception-ptr Use __cxa_get_exception_ptr in exception handling
  -fvisibility-inlines-hidden Marks all inlined functions and methods as having
                              hidden visibility
  -fvisibility-ms-compat      Changes visibility to match Microsoft Visual
                              Studio by default
  -fvtable-gc                 No longer supported
  -fvtable-thunks             No longer supported
  -fweak                      Emit common-like symbols as weak symbols
  -fwide-exec-charset=<cset>  Convert all wide strings and character constants
                              to character set <cset>
  -fworking-directory         Generate a #line directive pointing at the
                              current working directory
  -fxref                      No longer supported
  -idirafter <dir>            Add <dir> to the end of the system include path
  -imacros <file>             Accept definition of macros in <file>
  -imultilib <dir>            Set <dir> to be the multilib include subdirectory
  -include <file>             Include the contents of <file> before other files
  -iprefix <path>             Specify <path> as a prefix for next two options
  -iquote <dir>               Add <dir> to the end of the quote include path
  -isysroot <dir>             Set <dir> to be the system root directory
  -isystem <dir>              Add <dir> to the start of the system include path
  -iwithprefix <dir>          Add <dir> to the end of the system include path
  -iwithprefixbefore <dir>    Add <dir> to the end of the main include path
  -nostdinc                   Do not search standard system include directories
                              (those specified with -isystem will still be used)
  -nostdinc++                 Do not search standard system include directories
                              for C++
  -o <file>                   Place output into <file>
  -pedantic                   This switch lacks documentation
  -remap                      Remap file names when including files
  -std=c++03                  Conform to the ISO 1998 C++ standard revised by
                              the 2003 technical corrigendum
  -std=c++0x                  Deprecated in favor of -std=c++11
  -std=c++11                  Conform to the ISO 2011 C++ standard
  -std=c++14                  Conform to the ISO 2014 C++ standard
                              (experimental and incomplete support)
  -std=c++17                  This switch lacks documentation
  -std=c++1y                  Deprecated in favor of -std=c++14
  -std=c++1z                  Conform to the ISO 2017(?) C++ draft standard
                              (experimental and incomplete support)
  -std=c++98                  Conform to the ISO 1998 C++ standard revised by
                              the 2003 technical corrigendum
  -std=gnu++03                Conform to the ISO 1998 C++ standard revised by
                              the 2003 technical corrigendum with GNU extensions
  -std=gnu++0x                Deprecated in favor of -std=gnu++11
  -std=gnu++11                Conform to the ISO 2011 C++ standard with GNU
                              extensions (experimental and incomplete support)
  -std=gnu++14                Conform to the ISO 2014 C++ standard with GNU
                              extensions (experimental and incomplete support)
  -std=gnu++17                This switch lacks documentation
  -std=gnu++1y                This switch lacks documentation
  -std=gnu++1z                Conform to the ISO 201z(7?) C++ draft standard
                              with GNU extensions (experimental and incomplete
                              support)
  -std=gnu++98                Conform to the ISO 1998 C++ standard revised by
                              the 2003 technical corrigendum with GNU extensions
  -traditional-cpp            Enable traditional preprocessing
  -trigraphs                  Support ISO C trigraphs
  -undef                      Do not predefine system-specific and GCC-specific
                              macros
  -v                          Enable verbose output
  -w                          Suppress warnings

(you gotta love the entries that say "this switch lacks documentation"!!). Anyway that lists the -std= options for C++ listed by your compiler. The same thing done with WinAVR yields:

  -std=c++0x                  Conform to the ISO 1998 C++ standard, with
                              extensions that are likely to
  -std=c++98                  Conform to the ISO 1998 C++ standard
  -std=gnu++0x                Conform to the ISO 1998 C++ standard, with GNU
                              extensions and
  -std=gnu++98                Conform to the ISO 1998 C++ standard with GNU
                              extensions

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fixed in FSF v4.5.3:

http://gcc.gnu.org/PR42240

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

info gcc wrote:
`naked'
     Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate
     that the specified function does not need prologue/epilogue
     sequences generated by the compiler.  It is up to the programmer
     to provide these sequences. The only statements that can be safely
     included in naked functions are `asm' statements that do not have
     operands.
  All other statements, including declarations of local
     variables, `if' statements, and so forth, should be avoided.
     Naked functions should be used to implement the body of an
     assembly function, while allowing the compiler to construct the
     requisite function declaration for the assembler.

International Theophysical Year seems to have been forgotten..
Anyone remember the song Jukebox Band?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

PS was there ever any doubt that for a 1281 that SP==RAMEND (like all "modern" AVR it loads that at power on) ?

Yah know, this has been an ongoing debate over the years.  Some old skirmishes in Compiler Wars crowed about the small size of a GCC null program for AVR targets.  CodeVision e.g. was larger -- but CV did more stuff like WDR and turn off watchdog, and indeed set SP.

 

Why do it on an e.g. '1281?  Because the firmware just might end up at the reset vector without having an AVR reset.  Mis-spelled interrupt vector name, anyone?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But he's not setting it (to repair potential damage) but assert()ing when it's found not to be the case.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
But he's not setting it (to repair potential damage) but assert()ing when it's found not to be the case.

Hmm--I see what you mean.  I've lost track of where this code comes from.  Going a step further from my "arrive at address 0/reset vector without an actual reset of the AVR", the code you are pointing to enforces with a hard loop that rogue code case.  (a bootloader had better clean up after itself before jumping to 0, or use another mechanism such as watchdog reset) 

 

I'd think that in almost all cases I'd like my AVR apps to do a [soft] restart rather than a hard loop when they go rogue.  Consider the case wher an output is turned on and driving a heater or a motor or a chemical pump or whatever, and then the app goes rogue.  A restart will in all probability put outputs to a safe state, awaiting the next "trigger".

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) The code would work as expected with a gcc version that fixed PR42240.

2) Code like get_mcusr must be compiled with optimization turned on, and the function must not need frame-pointer.

3) get_mcusr should also be attributed "used", maybe also "unused" (so it works with global analysis, for example).

4) If the function needs a frame, it can be implemented as constructor (attribute constructor, no naked attribute, no section attribute). constructors will also work with non-optimized code.

5) The start code sets SP to __stack. The user can define that symbol to any value, in particular values that are not equal to RAMEND. If that's too much bloat, use custom start-up code.

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SprinterSB wrote:
3) get_mcusr should also be attributed "used", maybe also "unused" (so it works with global analysis, for example).

Aren't those two attrs contradicting each other?

 

clawson wrote:
PS was there ever any doubt that for a 1281 that SP==RAMEND (like all "modern" AVR it loads that at power on) ?

I wasn't aware that some megas init SP to RAMEND automatically at reset.. Is this documented anywhere (don't remember ever seeing it mentioned in datasheets)?

 

Anyway, the reason for the assert is that this code is at the beginning of the main application, and is jumped to by the bootloader (through the reset vector). The bootloader reads MCUSR, clears it, and disables the WDT, then stores the MCUSR value at the top of the stack, so the main app may read it. The comparison basically just checks that nothing else permanently stored anything on the stack (owerwriting the MCUSR value), but the check is redundant since only inside a function would space be reserved on the stack and the .initx functions aren't invoked from other functions.

 

I've changed it to look like this which verifies that the bootloader planted something at the top of the stack, and doing it before any other app code runs.

 

void assertion_lite(void) __attribute__ ((noreturn));

uint8_t mcusr_ __attribute__ ((section (".noinit")));

void _init(void) __attribute__ ((naked, section(".init0")));
void _init(void)
{
	// in case the check below fails and the assertion function relies on __zero_reg__
	__asm__ __volatile__ ( "clr __zero_reg__" );

	// verify bootloader stored mcusr at top of ram and unwound the stack before jumping here
	if (RAMEND-1 != SP)
		assertion_lite(); // cannot use ASSERT macro here as it relies on data having been xferred to ram

	__asm__ __volatile__ ( \
			"pop __tmp_reg__ \n\t" \
			"sts %[mcusr], __tmp_reg__ \n\t" \
			: /* no outputs */ \
			: [mcusr] "X" (&mcusr_) \
			: "memory" \
	);
}

Just thought that maybe assertion_lite should be naked instead of noreturn to avoid it potentially using the stack (we don't know what SP is).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Aren't those two attrs contradicting each other?
No. One says 'link even if not references'. The other says 'don't throw a warning if not referenced'.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hooverphonique wrote:
I wasn't aware that some megas init SP to RAMEND automatically at reset.. Is this documented anywhere (don't remember ever seeing it mentioned in datasheets)?
 

 

From the Stack Pointer section of the ATmega 640, 1280, 1281, etc. datasheet (Feb 2014, Section 7.6):

The initial value is 0x21FF which is the top of the internal SRAM...

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hooverphonique wrote:
I wasn't aware that some megas init SP to RAMEND automatically at reset.. Is this documented anywhere (don't remember ever seeing it mentioned in datasheets)?

Initial Stack Pointer value equals the last address of the internal SRAM and the Stack
Pointer must be set to point above start of the SRAM, see Table 8-3 on page 19.
 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you thought the SP was not initialized correctly then isn't your assert simply checking for the existence of .init1 from the CRT? Is there some reason you think the CRT would not be present? Is it really possible to "accidentally" use -nostartfiles?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

If you thought the SP was not initialized correctly then isn't your assert simply checking for the existence of .init1 from the CRT? Is there some reason you think the CRT would not be present? Is it really possible to "accidentally" use -nostartfiles?

 

I did realize that ASSERT(SP==RAMEND) was redundant in .init3 as I tried to explain in this sentence: ;)

Quote:
The comparison basically just checks that nothing else permanently stored anything on the stack (owerwriting the MCUSR value), but the check is redundant since only inside a function would space be reserved on the stack and the .initx functions aren't invoked from other functions.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Aren't those two attrs contradicting each other?

No.

"used": The compiler won't kick out the code even if it otherwise concluded that the code might be kicked out. This has NOTHING to do with the link stage! Symbols at link stage are kept because they are referenced, are KEEP, are the entry symbol, or because they reside in the same input section together with such a symbol.

"unused". Don't warn if the compler concludes that the code is unused (and iirc not inline). For example, in your code there's no need for the init functions to pollute global namespace (they are not referenced anywhere, in particular not by their external linkage). Hence your init function might just as well be static (or might implicitly be turned into local by global analysis + as-if rule).

> [mcusr] "X" (&mcusr_)

Don't use X as constraint: it doesn't constrain :-) "i" is fine for STS. To describe that memory is changed you can use the catch-all clobber "memory" as you did, or a fine-grained "=m" (mcusr_) as output operand (no need to mention it in the asm template).

avrfreaks does not support Opera. Profile inactive.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Very informational, SprinterSB!

 

I did not know about "i" (it is not mentioned in the avr-gcc inline assembler cookbook).

 

Something like this?

	__asm__ __volatile__ ( \
			"pop __tmp_reg__ \n\t" \
			"sts %[mcusr], __tmp_reg__ \n\t" \
			: "=m" (mcusr_) \
			: [mcusr] "i" (&mcusr_) \
	);

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes. "i" stands for immediate, i.e. known at link-time or before. It's a generic constraint (not avr-specific) like "m", "s", n", "r", "0", "1", ... and the union of "s" (symbolic) and "n" (compile-time constant).
 
 
My statement "4) If the function needs a frame, it can be implemented as constructor" was not correct as you are assuming a specific stack layout (which would not be the same if the .init3 code was implemented as a constructor).

avrfreaks does not support Opera. Profile inactive.

Last Edited: Sat. Feb 10, 2018 - 09:44 PM