C Collect2 Multiple Definition Error [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am writing a driver for FRAM for a robot, and all of a sudden I started getting this error:
C:\Users\james\AppData\Local\Temp\cciezvMm.o: In function `_FRAM_driver_setup':
(.text+0x0): multiple definition of `_FRAM_driver_setup'
cmm/FRAM_driver.o:(.text+0x0): first defined here
C:\Users\james\AppData\Local\Temp\cciezvMm.o: In function `_FRAM_log_data':
(.text+0xf): multiple definition of `_FRAM_log_data'
cmm/FRAM_driver.o:(.text+0xf): first defined here
C:\Users\james\AppData\Local\Temp\cciezvMm.o: In function `_FRAM_read_data':
(.text+0x7a): multiple definition of `_FRAM_read_data'
cmm/FRAM_driver.o:(.text+0x7a): first defined here
collect2: ld returned 1 exit status
Done. Build Failed!
I am not sure what brought this about, but I have not been able to find multiple definitions in my code. Here is the header file:
#ifndef FRAM_DRIVER_H_
#define FRAM_DRIVER_H_
#include "simpletools.h"
typedef struct FRAM_driver_type {
i2c* busID;
} FRAM_driver_type;
void FRAM_driver_setup(FRAM_driver_type* ptr, int sclPin, int sdaPin,
int sclDrive);
void FRAM_log_data(unsigned char* string, FRAM_driver_type* ptr);
void FRAM_read(FRAM_driver_type* ptr);
#endif
Here is the c file:
#include "FRAM_driver.h"
#define FRAM_DEFAULT_ADDR (0x50)
#define FRAM_MAX_MEM_ADDRESS (0x00)
#define FRAM_FIRST_MEM_ADDR (0x01)
#define FRAM_ADDR_SIZE ( 2 )
#define FRAM_DATA_SIZE ( 1 )
#define INT_SIZE ( 1 )
void FRAM_driver_setup(FRAM_driver_type* ptr, int sclPin, int sdaPin,
int sclDrive){
ptr->busID = i2c_newbus(sclPin, sdaPin, sclDrive);
}
void FRAM_log_data(unsigned char* data, FRAM_driver_type* ptr){
// Create a static integer initialized to the first memory address of the
// FRAM. It is 0x01 instead of 0x00 because 0x00 is going to be used to
// store the last memory adress being used. Also, create the int data_Size
// and set it equal to the length of the string plus one.
//
static int mem_Addr = FRAM_FIRST_MEM_ADDR;
int data_Size = strlen(data) + 1;
// Send the size of the data being sent to the next available memory
// address. This allows the FRAM_read_data funtion to know what size of
// data to read. Then increment up by one memory address.
//
i2c_out(ptr->busID, FRAM_DEFAULT_ADDR, mem_Addr, FRAM_ADDR_SIZE, data_Size,
INT_SIZE);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
mem_Addr += 0x01;
// Write data to the next address when the FRAM is not busy, then increment
// the memory address by one again.
//
i2c_out(ptr->busID, FRAM_DEFAULT_ADDR, mem_Addr, FRAM_ADDR_SIZE, data,
data_Size);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
mem_Addr += 0x01;
// Write the last memory address used to the first memory address of the
// FRAM. Then wait for the FRAM to not be busy.
//
i2c_out(ptr->busID, FRAM_DEFAULT_ADDR, FRAM_FIRST_MEM_ADDR, FRAM_ADDR_SIZE,
mem_Addr, INT_SIZE);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
}
void FRAM_read_data(FRAM_driver_type* ptr){
// Initialize unsigned characters to receive data from i2c_in.
//
unsigned char logged_Data = 1;
unsigned char logged_Data_Size;
unsigned char last_Memory_Address;
// Get the last memory address written to from FRAM_MAX_MEM_ADDRESS and
// store it in last_Memory_Address.
//
i2c_in(ptr->busID, FRAM_DEFAULT_ADDR, FRAM_MAX_MEM_ADDRESS, FRAM_ADDR_SIZE,
&last_Memory_Address, INT_SIZE);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
// Loop through all of the filled memory addresses in the FRAM and print
// the logged data in each address.
//
for (int i = FRAM_FIRST_MEM_ADDR; i <= last_Memory_Address; i+=2){
// Get the data_Size from the odd memory address and store it in
// logged_Data_Size. Then wait until the FRAM isn't busy.
//
i2c_in(ptr->busID, i, FRAM_FIRST_MEM_ADDR,
FRAM_ADDR_SIZE, &logged_Data_Size, INT_SIZE);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
// Use logged_Data_Size to store the data to logged_Data and then print
// the data. Wait until the FRAM isn't busy.
//
i2c_in(ptr->busID, i++, FRAM_FIRST_MEM_ADDR,
FRAM_ADDR_SIZE, &logged_Data, logged_Data_Size);
print("Log: %d \n", logged_Data);
while(i2c_busy(ptr->busID, FRAM_DEFAULT_ADDR));
}
}
Lastly, here is the testbench file:
#include "FRAM_driver.h"
#define FRAM_SCL_PIN 28
#define FRAM_SDA_PIN 29
static FRAM_driver_type fram_obj;
int main() {
const unsigned char* data = 2;
FRAM_driver_setup(&fram_obj, FRAM_SCL_PIN, FRAM_SDA_PIN, 0);
FRAM_log_data(data , &fram_obj);
FRAM_read_data(&fram_obj);
}
Any help would be greatly appreciated. Also, I am using simpleIDE and the simpletools library for a Propeller microcontroller.

C:\Users\james\AppData\Local\Temp\cciezvMm.o: In function '_FRAM_driver_setup:
(.text+0x0): multiple definition of '_FRAM_driver_setup'
cmm/FRAM_driver.o:(.text+0x0): first defined here
This error means that your link line is referencing FRAM_driver.c twice, and looks something like this:
gcc ... cmm/FRAM_driver.o ... cmm/FRAM_driver.c ...
Don't do that -- it obviously can't work.

SimpleIDE was including a backup of a file that was not included in the project directories. Actually, I couldn't find it anywhere. It was as if it was creating the backup copy of the code I was working on and then storing it in a temporary location whenever I ran the code. The file was removed from the SimpleIDE project files and then it worked.

Related

Linkage problem with extern variable when compiling?

I'm using MikroC for PIC v7.2, to program a PIC18f67k40.
Within functii.h, I have the following variable declaration:
extern volatile unsigned char byte_count;
Within main.c, the following code:
#include <functii.h>
// ...
volatile unsigned char byte_count = 0;
// ...
void interrupt () {
if (RC1IF_bit) {
uart_rx = Uart1_read();
uart_string[byte_count] = uart_rx;
byte_count++;
}
// ...
}
Then, within command.c, I have the following code:
#include <functii.h>
void how_many_bytes () {
// ...
uart1_write(byte_count);
// ...
}
In main.c, I process data coming through the UART, using an interrupt. Once the end of transmission character is received, I call how_many_bytes(), which sends back the length of the message that was received (plus the data bytes themselves, the code for which I didn't include here, but those are all OK!!).
The problem is that on the uart1_write() call, byte_count is always 0, instead of having been incremented in the interrupt sequence.
Probably you need some synchronization between the interrupt handler and the main processing.
If you do something like this
if(byte_count != 0) {
uart1_write(byte_count);
byte_count = 0;
}
the interrupt can occur anywhere, for example
between if(byte_count != 0)and uart1_write(byte_count); or
during the processing of uart1_write(byte_count); which uses a copy of the old value while the value gets changed or
between uart1_write(byte_count); and byte_count = 0;.
With the code above case 1 is no problem but 2 and 3 are. You would lose all characters received after reading byte_count for the function call.
Maybe you can disable/enable interrupts at certain points.
A better solution might be to not reset byte_count outside of interrupt() but instead implement a ring buffer with separate read and write index. The read index would be modified by how_many_bytes() (or uart1_write()) only and the write index by interrupt() only.

How to create a process that runs a routine with variable number of parameters?

I know there are lots of questions here about functions that take a variable number of arguments. I also know there's lots of docs about stdarg.h and its macros. And I also know how printf-like functions take a variable number of arguments. I already tried each of those alternatives and they didn't help me. So, please, keep that in mind before marking this question as duplicate.
I'm working on the process management features of a little embedded operating system and I'm stuck on the design of a function that can create processes that run a function with a variable number of parameters. Here's a simplified version of how I want my API to looks like:
// create a new process
// * function is a pointer to the routine the process will run
// * nargs is the number of arguments the routine takes
void create(void* function, uint8_t nargs, ...);
void f1();
void f2(int i);
void f3(float f, int i, const char* str);
int main()
{
create(f1, 0);
create(f2, 1, 9);
create(f3, 3, 3.14f, 9, "string");
return 0;
}
And here is a pseudocode for the relevant part of the implementation of system call create:
void create(void* function, uint8_t nargs, ...)
{
process_stack = create_stack();
first_arg = &nargs + 1;
copy_args_list_to_process_stack(process_stack, first_arg);
}
Of course I'll need to know the calling convention in order to be able to copy from create's activation record to the new process stack, but that's not the problem. The problem is how many bytes do I need to copy. Even though I know how many arguments I need to copy, I don't know how much space each of those arguments occupy. So I don't know when to stop copying.
The Xinu Operating System does something very similar to what I want to do, but I tried hard to understand the code and didn't succeed. I'll transcript a very simplified version of the Xinu's create function here. Maybe someone understand and help me.
pid32 create(void* procaddr, uint32 ssize, pri16 priority, char *name, int32 nargs, ...)
{
int32 i;
uint32 *a; /* points to list of args */
uint32 *saddr; /* stack address */
saddr = (uint32 *)getstk(ssize); // return a pointer to the new process's stack
*saddr = STACKMAGIC; // STACKMAGIC is just a marker to detect stack overflow
// this is the cryptic part
/* push arguments */
a = (uint32 *)(&nargs + 1); /* start of args */
a += nargs -1; /* last argument */
for ( ; nargs > 4 ; nargs--) /* machine dependent; copy args */
*--saddr = *a--; /* onto created process's stack */
*--saddr = (long)procaddr;
for(i = 11; i >= 4; i--)
*--saddr = 0;
for(i = 4; i > 0; i--) {
if(i <= nargs)
*--saddr = *a--;
else
*--saddr = 0;
}
}
I got stuck on this line: a += nargs -1;. This should move the pointer a 4*(nargs - 1) ahead in memory, right? What if an argument's size is not 4 bytes? But that is just the first question. I also didn't understand the next lines of the code.
If you are writing an operating system, you also define the calling convention(s) right? Settle for argument sizes of sizeof(void*) and pad as necessary.

Error while trying to update array element

I am working on an embedded platform which does not have debugging features. So it is hard to say what is the error source.
I have defined in header file:
typedef struct cm_packet {
CM_Header Header; //header of packet 3 bytes
uint8_t *Data; //packet data 64 bytes
CM_Footer Footer; //footer of packet 3 bytes
} CM_Packet;
typedef struct cm_inittypedef{
uint8_t DeviceId;
CM_Packet Packet;
} CM_InitTypeDef;
extern CM_InitTypeDef cmHandler;
void CM_Init(CM_InitTypeDef *handler);
CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier
, uint8_t *data, uint8_t length);
And somewhere in implementation I have:
uint8_t bufferIndex = 0;
void CM_Init(CM_InitTypeDef *cm_initer) { //init a handler
cmHandler.DeviceId = cm_initer->DeviceId;
CM_Packet cmPacket;
cmPacket.Header.DeviceId = cm_initer->DeviceId;
cmPacket.Header.PacketStart = CM_START;
cmPacket.Footer.PacketEnd = CM_END;
//initialize data array
uint8_t emptyBuffer[CM_MAX_DATA_SIZE] = {0x00};
cmPacket.Data = emptyBuffer;
cm_initer->Packet = cmPacket;
}
CM_AppendResult CM_AppendData(CM_InitTypeDef *handler, uint8_t identifier
, uint8_t *data, uint8_t length){
//some check to see if new data does not make Data overflow
uint8_t i;
/*** ERROR HAPPENS HERE!!!! ***/
handler->Packet.Data[bufferIndex++] = identifier;
//now add the data itself
for(i = 0; i < length; i++) {
handler->Packet.Data[bufferIndex++] = data[i];
}
//reset indexer
if(bufferIndex > 64) {
PacketReady(); //mark packet as ready
bufferIndex = 0
};
//return result
}
The idea is to update the Packet.Data from some other source codes which have access to the handler. For example some other sources can call that Append function to change Packet.Data. But as you see in the code, I have commented the place which causes the micro-controller to go in hard fault mode. I am not sure what is happening here. All I know is exactly at that line micro goes into hard fault mode and never recovers!
This might be a race condition but before anything else I want to know I have written correct c !!! code then I try to rule out other problems.
In function CM_Init, you are setting cmPacket.Data to point to a local array:
uint8_t emptyBuffer[CM_MAX_DATA_SIZE] = {0x00};
cmPacket.Data = emptyBuffer;
Accessing this memory address outside the scope of the function yields undefined behavior.
As #barak manos mentioned, the buffer supplied to Data is allocated on the stack.
When you get to CM_AppendData, you are writing over memory that is no longer dedicated to the buffer.
You may want to use malloc so that the buffer is allocated on the heap instead of on the stack. Just remember to call free so that you are not leaking memory.
If you can't use dynamic allocation, it's possible to dedicate some scratch memory for all the Data uses. It just needs to be static.
Hope that helps :)

C/STM32 structure pointer

I've been working with stm32f103, now I'm trying to lunch some codes on stm32f407.
To communicate through USART interface I use fifo query in form of structure, defined in header file:
#define FIFO_BUF_SIZE 128
typedef struct {
char data[FIFO_BUF_SIZE];
uint16_t startIndex;
uint16_t endIndex;
}FIFO, *ptrFIFO;
Global declaration of this structure in source file:
FIFO RX_Buff={{},0,0};
FIFO TX_Buff={{},0,0};
Now I want to put data from char array to fifo query:
void USART_PrintData(USART_TypeDef * USART, char str[]){
ptrFIFO pTX = &TX_Buff;
int i=0;
while(str[i]!='\0'){
FIFO_Put(pTX, str[i]);
i++;
}
//here in working program is code for sending data
//deleted from program for tests
}
void FIFO_Put(ptrFIFO fifo, char data){
uint16_t tmp;
tmp = fifo->startIndex;
fifo->data[tmp]=data;
tmp = (tmp+1)%(FIFO_BUF_SIZE-1);
fifo->startIndex=tmp;
}
This code has been worked on stm32f103 but won't on f407. After last sign passed to FIFO_Put() and write to fifo query, programm go to Default_Handler or strange address in memory (depends of humor), but when I using this structure directly it works fine:
void FIFO_Put(char data){
uint16_t tmp;
tmp = TX_Buff.startIndex;
TX_Buff.data[tmp]=data;
tmp = (tmp+1)%(FIFO_BUF_SIZE-1);
TX_Buff.startIndex=tmp;
}
I have no idea what's wrong.
Thanks for any help.
I've tried to debug, and the problem is in last line in function FIFO_Put():
fifo->startIndex=tmp;
When function putting last sign to fifo, after last line program jump to default_handler.
If I comment this line, program works fine.
Check the program stack size - from my experience, such kind of undefined behavior may be caused by stack overflow.

Finding the address range of the data segment

As a programming exercise, I am writing a mark-and-sweep garbage collector in C. I wish to scan the data segment (globals, etc.) for pointers to allocated memory, but I don't know how to get the range of the addresses of this segment. How could I do this?
If you're working on Windows, then there are Windows API that would help you.
//store the base address the loaded Module
dllImageBase = (char*)hModule; //suppose hModule is the handle to the loaded Module (.exe or .dll)
//get the address of NT Header
IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(hModule);
//after Nt headers comes the table of section, so get the addess of section table
IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *) (pNtHdr + 1);
ImageSectionInfo *pSectionInfo = NULL;
//iterate through the list of all sections, and check the section name in the if conditon. etc
for ( int i = 0 ; i < pNtHdr->FileHeader.NumberOfSections ; i++ )
{
char *name = (char*) pSectionHdr->Name;
if ( memcmp(name, ".data", 5) == 0 )
{
pSectionInfo = new ImageSectionInfo(".data");
pSectionInfo->SectionAddress = dllImageBase + pSectionHdr->VirtualAddress;
**//range of the data segment - something you're looking for**
pSectionInfo->SectionSize = pSectionHdr->Misc.VirtualSize;
break;
}
pSectionHdr++;
}
Define ImageSectionInfo as,
struct ImageSectionInfo
{
char SectionName[IMAGE_SIZEOF_SHORT_NAME];//the macro is defined WinNT.h
char *SectionAddress;
int SectionSize;
ImageSectionInfo(const char* name)
{
strcpy(SectioName, name);
}
};
Here's a complete, minimal WIN32 console program you can run in Visual Studio that demonstrates the use of the Windows API:
#include <stdio.h>
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment( lib, "dbghelp.lib" )
void print_PE_section_info(HANDLE hModule) // hModule is the handle to a loaded Module (.exe or .dll)
{
// get the location of the module's IMAGE_NT_HEADERS structure
IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(hModule);
// section table immediately follows the IMAGE_NT_HEADERS
IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pNtHdr + 1);
const char* imageBase = (const char*)hModule;
char scnName[sizeof(pSectionHdr->Name) + 1];
scnName[sizeof(scnName) - 1] = '\0'; // enforce nul-termination for scn names that are the whole length of pSectionHdr->Name[]
for (int scn = 0; scn < pNtHdr->FileHeader.NumberOfSections; ++scn)
{
// Note: pSectionHdr->Name[] is 8 bytes long. If the scn name is 8 bytes long, ->Name[] will
// not be nul-terminated. For this reason, copy it to a local buffer that's nul-terminated
// to be sure we only print the real scn name, and no extra garbage beyond it.
strncpy(scnName, (const char*)pSectionHdr->Name, sizeof(pSectionHdr->Name));
printf(" Section %3d: %p...%p %-10s (%u bytes)\n",
scn,
imageBase + pSectionHdr->VirtualAddress,
imageBase + pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize - 1,
scnName,
pSectionHdr->Misc.VirtualSize);
++pSectionHdr;
}
}
// For demo purpopses, create an extra constant data section whose name is exactly 8 bytes long (the max)
#pragma const_seg(".t_const") // begin allocating const data in a new section whose name is 8 bytes long (the max)
const char const_string1[] = "This string is allocated in a special const data segment named \".t_const\".";
#pragma const_seg() // resume allocating const data in the normal .rdata section
int main(int argc, const char* argv[])
{
print_PE_section_info(GetModuleHandle(NULL)); // print section info for "this process's .exe file" (NULL)
}
This page may be helpful if you're interested in additional uses of the DbgHelp library.
You can read the PE image format here, to know it in details. Once you understand the PE format, you'll be able to work with the above code, and can even modify it to meet your need.
PE Format
Peering Inside the PE: A Tour of the Win32 Portable Executable File Format
An In-Depth Look into the Win32 Portable Executable File Format, Part 1
An In-Depth Look into the Win32 Portable Executable File Format, Part 2
Windows API and Structures
IMAGE_SECTION_HEADER Structure
ImageNtHeader Function
IMAGE_NT_HEADERS Structure
I think this would help you to great extent, and the rest you can research yourself :-)
By the way, you can also see this thread, as all of these are somehow related to this:
Scenario: Global variables in DLL which is used by Multi-threaded Application
The bounds for text (program code) and data for linux (and other unixes):
#include <stdio.h>
#include <stdlib.h>
/* these are in no header file, and on some
systems they have a _ prepended
These symbols have to be typed to keep the compiler happy
Also check out brk() and sbrk() for information
about heap */
extern char etext, edata, end;
int
main(int argc, char **argv)
{
printf("First address beyond:\n");
printf(" program text segment(etext) %10p\n", &etext);
printf(" initialized data segment(edata) %10p\n", &edata);
printf(" uninitialized data segment (end) %10p\n", &end);
return EXIT_SUCCESS;
}
Where those symbols come from: Where are the symbols etext ,edata and end defined?
Since you'll probably have to make your garbage collector the environment in which the program runs, you can get it from the elf file directly.
Load the file that the executable came from and parse the PE headers, for Win32. I've no idea about on other OSes. Remember that if your program consists of multiple files (e.g. DLLs) you may have multiple data segments.
For iOS you can use this solution. It shows how to find the text segment range but you can easily change it to find any segment you like.

Resources