What does '__asm__(".previous");' mean? - gcc

While trying to compile my project, that uses some third party headers, with mingw 4.4, I encountered the following error:
Assembler messages:
Error: junk at end of line, first unrecognized character is '"'
Error: unknown pseudo-op: '.previous'
I found this code at the end of one of the included headers:
__asm__(".section \".plc\"");
__asm__(".previous");
Since I do not have any experience at all with in-line assembler instructions, I googled for an explanation to it, but couldn't find the answer to my two basic questions. What does __asm__(".previous"); acctually do and why would anyone put this at the end of a header file.
These are the only __asm__ instructions in the whole project. Can I safely delete them? Or is there a way to define .previous in order to make it a known pseudo-op?
Enlighten me, please!

.previous is a directive that lets you swap back and forth between two elf sections. It is a shortcut that allows denser assembly files and lets you for example declare initialized data within a stream of code or vice versa.
For example say you have an assembler file with a data and a code section.
If you want - in the middle of a function - declare a constant in the data segment you can use the .previous statement like this:
nop // some code
.previous // swaps current section (code) with previous section (data)
MyConstant:
.word 0x0001 // some data
.previous // swaps curent section (data) with previous section (code)
nop // more code
More information can be found in the reference manual:
http://sourceware.org/binutils/docs-2.19/as/Previous.html#Previous

Related

I am trying to write a simple MIPS program that will add hexadecimal numbers, but I keep getting an error

I a writing a simple MIPS code to add two hexadecimal values and store the results in a register. I am new to MIPS so I am having trouble finding the fix to an error message I have. Any help would be appreciated.
.text
.globl main
main: add $t2,$t0,$t1 # add contents of $t0 and $t1, and store result in $t2
li $v0,10 # terminate execution
syscall
the error message:
Error in C:\Users\smpan\OneDrive\Desktop\Computer\Computer Lab 2\Exercise4_3.asm line 4: Runtime exception at 0x00400000: arithmetic overflow
My goal for the program is to try and verify my hexadecimal addition is correct. I am adding 0x7FAA3278 and 0x6024CD12. The program should store the result 0xDFCEFF8A is the registered $t2.
Line 14 is the line that contains main:
The result of that addition is too big to fit in a signed 32 bit value, and the CPU is telling you exactly that.
If you're expecting an unsigned result, or are happy with a negative result from adding two positive numbers, there's an 'add unsigned' instruction.
See here:
Difference between add and addu

Linker error: "bad address <value> for zero page symbol <name>"!

I'm trying to make COSMIC compiler allocate a struct at a specific address in the memory (0x5420). I added the following lines in my C code (where CAN_TypeDef is a typedef struct):
#pragma section [mycan]
CAN_TypeDef CAN;
#pragma section []
In the IDE (STVD), I created a new section named Can inside which I created a new section named .mycan.
When I build the code in STVD, a linker error appears saying:
#error clnk Debug\can.lkf:1 bad address (0x5420) for zero page symbol _CAN
In the above picture, it is clear that Can and Zero Page are two different segments. What can be the cause of this error and how can I solve it?
I don't know the STM8, but I think I found it. In the STVD documentation I read:
Global variables
When the category is set to General , you can use
the Global Variables list box to specify the default location of
global variables:
In Zero Page: This is the default option.
In Data: Specifies to place global variables in the first 64Kbytes of
memory.
So the compiler assumes all global data sitting in the zero page and the addresses are just eight bit wide. Only the linker sees that the section .mycan is not in the zero page and you get an error. I would try #near CAN_TypeDef CAN; or simply extern CAN_TypeDef CAN #5420; without creating your own section.

What input section attributes are required to place a C variable in a data memory output section?

My application has a number of modules that each require some variables to be stored in off-chip non-volatile memory. To make the reading and writing of these easier, I'm trying to collect them together into a contiguous region of RAM, to that the NVM driver can address a single block of memory when communicating with the NVM device.
To achieve this, I have created a custom linker script containing the following section definition.
.nvm_fram :
{
/* Include the "nvm_header" input section first. */
*(.nvm_header)
/* Include all other input sections prefixed with "nvm_" from all modules. */
*(.nvm_*)
/* Allocate a 16 bit variable at the end of the section to hold the CRC. */
. = ALIGN(2);
_gld_NvmFramCrc = .;
LONG(0);
} > data
_GLD_NVM_FRAM_SIZE = SIZEOF(.nvm_fram);
The data region is defined in the MEMORY section using the standard definition provided by Microchip for the target device.
data (a!xr) : ORIGIN = 0x1000, LENGTH = 0xD000
One example of a C source file which attempts to place its variables in this section is the NVM driver itself. The driver saves a short header structure at teh beginning of the NVM section so that it can verify the content of the NVM device before loading it into RAM. No linker error reported for this variable.
// Locate the NVM configuration in the non-volatile RAM section.
nvm_header_t _nvmHeader __attribute__((section(".nvm_header")));
Another module that has variables to store in the .nvm_fram section is the communications (CANopen) stack. This saves the Module ID and bitrate in NVM.
// Locate LSS Slave configuration in the non-volatile RAM section.
LSS_slave_config_t _slaveConfig __attribute__((section(".nvm_canopen"))) =
{ .BitRate = DEFAULT_BITRATE, .ModuleId = DEFAULT_MODULEID };
Everything compiles nicely, but when the linker runs, the following error stops the build.
elf-ld.exe: Link Error: attributes for input section '.nvm_canopen' conflict with
output section '.nvm_fram'
It's important that the variables can be initialised with values by the crt startup, as shown by the _slaveConfig declaration above, in case the NVM driver cannot load them from the NVM device (it's blank, or the software version has changed, etc.). Is this what's causing the attributes mismatch?
There are several questions here and on the Microchip forums, which relate to accessing symbols that are defined in the linker script from C. Most of these concern values in the program Flash memory and how to access them from C; I know how to do this. There is a similar question, but this doesn't appear to address the attributes issue, and is a little confusing due to being specific to a linker for a different target processor.
I've read the Microchip linker manual and various GCC linker documents online, but can't find the relevant sections because I don't really understand what the error means and how it relates to my code. What are the 'input and output section attributes', where are they specified in my code, and how do I get them to match eachother?
The problem is due to the _nvmHeader variable not having an initial value assigned to it in the C source, but the _slaveConfig variable does.
This results in the linker deducing that the .nvm_fram output section is uninitialised (nbss) from the .nvm_header input section attributes. So, when it enconters initialised data in the .nvm_canopen input section from the _slaveConfig variable, there is a mismatch in the input section attributes: .nvm_fram is for uninitialised data, but .nvm_canopen contains initialised data.
The solution is to ensure that all variables that are to be placed in the .nvm_fram output section are given initial values in the C source.
// Type used to hold metadata for the content of the NVM.
typedef struct
{
void* NvmBase; // The original RAM address.
uint16_t NvmSize; // The original NVM section size.
} nvm_header_t;
// The linker supplies the gld_NVM_FRAM_SIZE symbol as a 'number'.
// This is represented as the address of an array of unspecified
// length, so that it cannot be implicitly dereferenced, and cast
// to the correct type when used.
extern char GLD_NVM_FRAM_SIZE[];
// The following defines are used to convert linker symbols into values that
// can be used to initialise the _nvmHeader structure below.
#define NVM_FRAM_BASE ((void*)&_nvmHeader)
#define NVM_FRAM_SIZE ((uint16_t)GLD_NVM_FRAM_SIZE)
// Locate the NVM configuration in the non-volatile RAM section.
nvm_header_t _nvmHeader __attribute__((section(".nvm_header"))) =
{
.NvmBase = NVM_FRAM_BASE, .NvmSize = NVM_FRAM_SIZE
};
The answer is therefore that the output section attributes may be determined partly by the memory region in which the section is to be located and also by the attributes of the first input section assigned to it. Initialised and uninitialised C variables have different input section attributes, and therefore cannot be located within the same output section.

How to specify custom section start addresses for PE sections?

On Linux, when linking I can specify any virtual address for a section:
ld -Ttext 0x10000000 -Tdata 0x20000000 foo.o -o foo
But I don't see such option for Windows' link.exe.
Is it possible to specify PE section start addresses somehow?
MinGW ld can put the sections at arbitrary addresses. Dumpbin and disassemblers can handle it without problem.
But it seems Windows does not accept anything but the default address: if you try to set it to a different value Windows will say "not a valid Win32 application".
The base address must be 0x400000 or 0x1000000.
And the .text section must be at 0x401000 or 0x1001000.
Also it seems no gaps allowed between the sections. If I try to place the .data section to 0x403000 instead of 0x402000, then Windows is unable to load it...
(I maybe wrong, or mingw ld is buggy...)
When using GCC, this page explains how to define variables at absolute addresses (including mentioning the section in which they should reside) : https://mcuoneclipse.com/2012/11/01/defining-variables-at-absolute-addresses-with-gcc/
The idea I use here is to put the variable with a special section
name, and then place it in the linker file at an absolute address.
unsigned char __attribute__((section (".myBufSection"))) buf[128]
__attribute__ ((aligned (512)));
With this, my variable will be put into a section named
‘.myBufSection’, and it will be aligned on a 512 address boundary.
The next step is to place that section at an address in the linker file.
SECTIONS
{
/* placing my named section at given address: */
.myBufBlock 0x20000000 :
{
KEEP(*(.myBufSection)) /* keep my variable even if not referenced */
} > m_data
/* other placements follow here... */
}
PS: Another method is mentioned in How can I declare a variable at an absolute address with GCC?
PS 2: Another related (alas unanswered) question is this : How to place a variable at a given absolute address in memory (with Visual C++)

How to Write GRUB stage1.S in NASM?

I am trying to write a multi stage boot loader using NASM and gcc.
For this purpose I am referring grub boot loader source.
I have written a stage1 loader, but stuck at over writing partition
tables of MBR.
In grub stage1.S, they are using code like this to skip partition tables:
. = _start + STAGE1_PARTEND
.word STAGE1_SIGNATURE
How can I do that in NASM?.
using times it will over write the partition tables.
So please help me.
Assigning a value to . is treated the same as a .org directive (see this page).
Thus, the code you pasted is changing the current origin to _start + STAGE1_PARTEND and placing a word with the value STAGE1_SIGNATURE there.
So in NASM code you should be able to do something like:
fill: times _start+STAGE1_PARTEND-$ db 0
dw STAGE1_SIGNATURE
; .word is 16 bits on x86 (regardless of .code16 / .code64)
Also see this example in the NASM manual showing how to pad a BIOS boot sector this way, as a replacement for MASM-style org or GAS-style . = new_position actually seeking and filling with padding in a flat binary output file.
times STAGE1_PARTEND-($-_start) db 0
dw STAGE1_SIGNATURE
Right, Nasm will accept only one "org" directive. The Nasm equivalent of "." is "$", but I don't think that'll help you either. I don't have the GRUB code on hand, or I'd look. Where does the partition table "come from"? If it's read from disk, there may be a signature already in place(?). Perhaps you can simply "stop" the Nasm code before overwriting the partition table and leave the existing sig in place? Nasm will do almost "anything you want", but this may be an exception. It won't "move" (skip) and assemble more at a new place as (G)as is apparently doing here - at least not readily. I may need to download the GRUB code to figure out a workaround. Possibly something like...
; stage1 code
; possible padding here?
%incbin "partition_table.bin"
dw (SIG) ; if not part of the .bin code?
... or something.

Resources