User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Some advanced C Questions

Mon Jul 23, 2012 8:01 am

Ok, this has perhaps nothing to do with Bare metal, but I have two questions, I would like to ask:

1) at the moment im refactoring my code and i have 6 functions, which share one function in common, exp.:

Code: Select all

static void bar(INT32 x)
{
}

void foo1()
{
  bar(1);
}

void foo2()
{
  bar(2);
}
now my question, is there a trick, i could put foo1 and foo2 in seperate .c files and keep bar still "static" thus invisible to outside linking?

2) i would like to create stripped relocateable elf files (later my "exe" files, which are loaded from disk, relocated in memory and then executed). How does a linker script for this purpose look like? At the moment everything is linked to a fixed adress. and if i use the "-r" option in LD, it got a full bloathed file, with lots of stuff i dont need (.comment as an example). Any suggestions?

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 23065
Joined: Sat Jul 30, 2011 7:41 pm

Re: Some advanced C Questions

Mon Jul 23, 2012 8:30 am

1. No, as soon as you move code to other C files, you need external linking, so the function cannot be static.

2. strip -s? Anyway, the strip command seem to be the one you need.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed. Here's an example...
"My grief counseller just died, luckily, he was so good, I didn't care."

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Some advanced C Questions

Mon Jul 23, 2012 9:11 am

As James says, (1) is not possible using the normal C tool-chain in the normal way. Therefore it is a bad idea to do it; using your tools in ways they were not intended to be used always causes trouble.

However, there are two ways it might be done if you have very good reasons for doing it.

1) It is possible to link just those three files before anything else (GNI ld switch -r) and then use some tool to remove references to all satisfied linkages. The GNU ld linker --retain-symbols-file switch allows you to specify a file containing the names of all symbols you want exported from an output file, so just list all the symbols except the one you want to not be there. Unfortunately ld doesn't support removing only specific symbols in anything other than the i386 PE version (ie Windows).

2) You can use #include instead of linking the files.

3) You could give the function a password and obfuscate its name. (Yes, there really are only two ways ;-) )

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Mon Jul 23, 2012 11:27 am

Hmm,

ok thanks, sounds all too complicated. its just happens that i stripped alot of same code to only one function, making the whole code smaller. Then im going to keep all functions in one .c file, looks a bit untidy, but at the moment i have to live with it.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Mon Jul 23, 2012 1:12 pm

jamesh wrote: 2. strip -s? Anyway, the strip command seem to be the one you need.
When i do a strip -s -> the whole relocation table is stripped, giving me the following error:

Code: Select all

COFF File!!!
Header Read
Section Header read: BSS Section = 2
Cannot relocate an executable without symbols
This is my Test.c Program:

Code: Select all

int _test(void)
{
  return 666;
}
and these are filelength without strip/with strip:

Code: Select all

-rw-r--r--+ 1 Claus None 336 Jul 23 14:56 test1.o
-rw-r--r--+ 1 Claus None 152 Jul 23 15:09 test1.o

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Mon Jul 23, 2012 1:15 pm

Hah !! I found it :)

The magic switch for Strip is he following: -s is too much ...
--strip-unneeded

dwelch67
Posts: 955
Joined: Sat May 26, 2012 5:32 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 1:37 am

You can include one file in another

Code: Select all

bar.c:

static int bar ()...

foo.c:

#include bar.c

int fun ( int x )
{
 x = bar(5);
}

User avatar
rurwin
Forum Moderator
Forum Moderator
Posts: 4258
Joined: Mon Jan 09, 2012 3:16 pm
Contact: Website

Re: Some advanced C Questions

Tue Jul 24, 2012 6:11 am

I said that ;-)

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 6:39 am

If you do that, you need to make sure the included file doesn't get compiled by mistake, though.

Another option is to wrap your function(s) in a #define, and then invoke that whenever you need to include the function(s)

It's all 'orrible, though.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Tue Jul 24, 2012 1:44 pm

at the moment i will live with 800 lines of code with 15 functions. i want to get to an alpha stage. i coded 120new functions the last 5 days and light is at the end of tunnel.
Heres a dump of missing functions at the moment im sitting on;-)

Code: Select all

src/kickstart/lib.dos/_functab.c:68:12: error: 'dos_LockRecords' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:70:12: error: 'dos_UnLockRecords' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:72:12: error: 'dos_SelectInput' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:73:12: error: 'dos_SelectOutput' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:80:12: error: 'dos_FPuts' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:81:12: error: 'dos_VFWritef' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:82:12: error: 'dos_VFPrintf' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:84:12: error: 'dos_SetVBuf' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:87:12: error: 'dos_OpenFromLock' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:90:12: error: 'dos_SetFileDate' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:91:12: error: 'dos_NameFromLock' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:92:12: error: 'dos_NameFromFH' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:93:12: error: 'dos_SplitName' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:96:12: error: 'dos_ExAll' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:97:12: error: 'dos_ReadLink' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:99:12: error: 'dos_ChangMode' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:103:12: error: 'dos_Fault' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:104:12: error: 'dos_PrintFault' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:105:12: error: 'dos_ErrorReport' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:108:12: error: 'dos_CreateNewProc' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:109:12: error: 'dos_RunCommand' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:110:12: error: 'dos_GetConsoleTask' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:111:12: error: 'dos_SetConsoleTask' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:112:12: error: 'dos_GetFileSysTask' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:113:12: error: 'dos_SetFileSysTask' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:114:12: error: 'dos_GetArgStr' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:115:12: error: 'dos_SetArgStr' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:116:12: error: 'dos_FindCli' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:117:12: error: 'dos_MaxCli' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:118:12: error: 'dos_SetCurrentDirName' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:119:12: error: 'dos_GetCurrentDirName' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:120:12: error: 'dos_SetProgramName' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:121:12: error: 'dos_GetProgramName' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:122:12: error: 'dos_SetPrompt' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:123:12: error: 'dos_GetPrompt' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:124:12: error: 'dos_SetProgramDir' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:125:12: error: 'dos_GetProgramDir' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:129:12: error: 'dos_Assign' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:130:12: error: 'dos_AssignLate' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:131:12: error: 'dos_AssignPath' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:132:12: error: 'dos_AddAssign' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:133:12: error: 'dos_RemAssign' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:141:12: error: 'dos_FindDosEntry' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:142:12: error: 'dos_NextDosEntry' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:145:12: error: 'dos_IsFileSystem' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:152:12: error: 'dos_CompareDates' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:153:12: error: 'dos_DateToStr' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:154:12: error: 'dos_StrToDate' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:156:12: error: 'dos_CheckSignal' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:157:12: error: 'dos_ReadArgs' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:158:12: error: 'dos_FindArg' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:159:12: error: 'dos_ReadItem' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:160:12: error: 'dos_StrToLong' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:161:12: error: 'dos_MatchFirst' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:162:12: error: 'dos_MatchNext' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:163:12: error: 'dos_MatchEnd' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:164:12: error: 'dos_ParsePattern' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:165:12: error: 'dos_MatchPattern' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:166:12: error: 'dos_FreeArgs' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:167:12: error: 'dos_FilePart' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:168:12: error: 'dos_PathPart' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:169:12: error: 'dos_AddPart' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:171:12: error: 'dos_StartNotify' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:172:12: error: 'dos_EndNotif' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:174:12: error: 'dos_SetVar' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:175:12: error: 'dos_GetVar' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:176:12: error: 'dos_DeleteVar' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:177:12: error: 'dos_FindVar' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:179:12: error: 'dos_CliInit' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:180:12: error: 'dos_CliInitNewCli' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:181:12: error: 'dos_CliInitRun' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:183:12: error: 'dos_WriteChars' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:184:12: error: 'dos_PutStr' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:185:12: error: 'dos_VPrintf' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:187:12: error: 'dos_PreParseNoCase' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:188:12: error: 'dos_MatchPatternNoCase' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:189:12: error: 'dos_GetString' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:190:12: error: 'dos_SameDevice' undeclared here (not in a function)
src/kickstart/lib.dos/_functab.c:192:12: error: 'dos_ExAllEnd' undeclared here (not in a function)
after successfully bringing them up, i will remake your makefile tufty and clean things up. ;)

@tufty: i left a comment on your blog about the clrex. have you seen it? how should i use it for an atomic inc on a semaphore? strex/ldrex and then clrex?

ecw
Posts: 10
Joined: Tue Jan 10, 2012 1:56 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 3:26 pm

You don't need clrex, ldrex and strex will do. Surround them with membars (dmb) to ensure a consistent memory view.

off the top of my head, an atomic inc using ldex/strex -

; address of variable passed in r0. returns value (1 + *r0)
atomic_inc:
dmb
ldrex r1, [r0]
add r1, r1, #1
strex r2, r1, [r0]
cbnz r2, atomic_inc
dmb
mov r0, r1
bx lr

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Tue Jul 24, 2012 3:57 pm

tufty wrote:If you do that, you need to make sure the included file doesn't get compiled by mistake, though.

Another option is to wrap your function(s) in a #define, and then invoke that whenever you need to include the function(s)

It's all 'orrible, though.
There is another Problem, i dont want to bloat up the code. with an include the static functions gets implemented with every include. let say the common used function is 5kb and the 5 others are 1kb = 20kb if they stick in one c file. if i do it the include way, it will be 5* 1* 15 = 80kb. I know, in times of memory you will laugh at me ;-)

but to the solution of not compiling. just use another ending like .inc (function1.inc). this wont be compiled.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Tue Jul 24, 2012 4:04 pm

ecw wrote:You don't need clrex, ldrex and strex will do. Surround them with membars (dmb) to ensure a consistent memory view.

off the top of my head, an atomic inc using ldex/strex -

; address of variable passed in r0. returns value (1 + *r0)
atomic_inc:
dmb
ldrex r1, [r0]
add r1, r1, #1
strex r2, r1, [r0]
cbnz r2, atomic_inc
dmb
mov r0, r1
bx lr
i will try it, because of the post on Simons Blog i thought i need the clrex. i solved it the >ARMV6 way, just disable the interupts at the moment.

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 4:08 pm

You only need clrex if you abandon an operation, and as part of your context switch code.

dwelch67
Posts: 955
Joined: Sat May 26, 2012 5:32 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 6:23 pm

rurwin wrote:I said that ;-)
sorry...

dwelch67
Posts: 955
Joined: Sat May 26, 2012 5:32 pm

Re: Some advanced C Questions

Tue Jul 24, 2012 6:27 pm

remember to be careful with ldrex/strex they are not meant to be used in uniprocessor systems, they are for a multicore/processor systems. They do not always work on uniprocessor systems. I have tested them on the raspberry pi processor and it is OKAY to use them...Just be careful if you take that code anywhere else, you have to test each system for use of that instruction pair. It becomes extremely obvious when they dont work as you go into an infinite loop strex always fails.

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Some advanced C Questions

Wed Jul 25, 2012 3:59 pm

dwelch67 wrote:remember to be careful with ldrex/strex they are not meant to be used in uniprocessor systems, they are for a multicore/processor systems. They do not always work on uniprocessor systems.
ARM say otherwise, Dave.
From ARMv6, use of the SWP and SWPB instructions is deprecated. ARM Limited recommends strongly that all software migrates to using the new synchronization primitives described in this section.
Cycl0ne - I found the ref in the ARM-ARM regarding the use of clrex (A3.4.4 in my copy):
A3.4.4 Context switch support
After a context switch, software must ensure that the local monitor is in the Open Access state. This requires it to either:
• execute a CLREX instruction • execute a dummy STREX to a memory address allocated for this purpose.
• Using a dummy STREX for this purpose is backwards-compatible with the ARMv6 implementation of the exclusive operations. The CLREX instruction is introduced in ARMv6K.
• Context switching is not an application level operation. However, this information is included here to complete the description of the exclusive operations.
The STREX or CLREX instruction following a context switch might cause a subsequent Store-Exclusive to fail, requiring a load ... store sequence to be replayed. To minimize the possibility of this happening, ARM Limited recommends that the Store-Exclusive instruction is kept as close as possible to the associated Load-Exclusive instruction, see Load-Exclusive and Store-Exclusive usage restrictions.
...
If the target address of an STREX is different from the preceding LDREX in the same execution thread, behavior can be UNPREDICTABLE. As a result, an LDREX/STREX pair can only be relied upon to eventually succeed if they are executed with the same address. Where a context switch or exception might result in a change of execution thread, a CLREX instruction or a dummy STREX instruction must be executed to avoid unwanted effects, as described in Context switch support Using an STREX in this way is the only occasion where software can program an STREX with a different address from the previously executed LDREX.
...and so on.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Some advanced C Questions

Wed Jul 25, 2012 7:15 pm

tufty wrote: If the target address of an STREX is different from the preceding LDREX in the same execution thread, behavior can be UNPREDICTABLE. As a result, an LDREX/STREX pair can only be relied upon to eventually succeed if they are executed with the same address. Where a context switch or exception might result in a change of execution thread, a CLREX instruction or a dummy STREX instruction must be executed to avoid unwanted effects, as described in Context switch support Using an STREX in this way is the only occasion where software can program an STREX with a different address from the previously executed LDREX.
...and so on.[/quote]

Sounds too complicated. i stick to my disable()/enable() pair ;)

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Some advanced C Questions

Wed Jul 25, 2012 7:58 pm

Disabling interrupts isn't worth it. It's pretty much guaranteed to come back and bite you in the ass later.

The concept of ldrex / strex is really simple, and the only twist comes with context switching - a single clrex in your context switcher (and, potentially, handlers for the undefined instruction, data and prefetch abort) does away with your woes. Simple as.

Simon

Return to “Bare metal, Assembly language”