I am interested on developing a way to manually locate parts of the code at a given memory location. The idea is giving a programmer an easy way to control memory placement of some parts of its code. Therefore, I came up with this:
#include<stdio.h>//////////////////////////////////////////////////////////// PIECE OF CODE THAT WE WANT TO PLACE AT 0x6000//////////////////////////////////////////////////////////// Force following code to be absolutely placed at 0x6000voiddummy_absolute_0x6000(void)__naked{__asm.area_0x6000_(ABS).org0x6000__endasm;}unsignedchar*conststr1="Hello!\r\n";unsignedchar*conststr2="This string is at 0x6000 area.\r\n";voidprintThings(){printf(str1);printf(str2);}//////////////////////////////////////////////////////////// PIECE OF CODE TO BE ALLOCATED BY THE LINKER (RELATIVE)//////////////////////////////////////////////////////////// Declare following code to be relocatablevoiddummy_relocatable_1(void)__naked{__asm.area_CSEG(REL,CON)__endasm;}unsignedchar*conststr3="This is relatively located\r\n";voidmain(void){printThings();printf(str3);while(1);}
As you can see, the idea was to add some dummy functions that help including assembler directives to locate partes of the code. I know it is kind of a hack, but it seemed to work at first. Previous C code gets compiled into this assembly code:
;--------------------------------------------------------;FileCreatedbySDCC:freeopensourceANSI-CCompiler;Version3.5.5#9498(Linux);--------------------------------------------------------.modulemain.optsdcc-mz80;--------------------------------------------------------;Publicvariablesinthismodule;--------------------------------------------------------.globl_main.globl_printThings.globl_printf.globl_str3.globl_str2.globl_str1;--------------------------------------------------------;specialfunctionregisters;--------------------------------------------------------;--------------------------------------------------------;ramdata;--------------------------------------------------------.area_DATA;--------------------------------------------------------;ramdata;--------------------------------------------------------.area_INITIALIZED;--------------------------------------------------------;absoluteexternalramdata;--------------------------------------------------------.area_DABS(ABS);--------------------------------------------------------;global&staticinitialisations;--------------------------------------------------------.area_HOME.area_GSINIT.area_GSFINAL.area_GSINIT;--------------------------------------------------------;Home;--------------------------------------------------------.area_HOME.area_HOME;--------------------------------------------------------;code;--------------------------------------------------------.area_CODE;---------------------------------;Functiondummy_absolute_0x6000;---------------------------------_dummy_absolute_0x6000::.area_0x6000_(ABS).org0x6000;---------------------------------;FunctionprintThings;---------------------------------_printThings::ldhl,(_str1)pushhlcall_printfpopafldhl,(_str2)pushhlcall_printfpopafret_str1:;;;<<<<---WhyarestringsputbelowprintThings.dw__str_0;;;insteadofabove?_str2:.dw__str_1__str_0:.ascii"Hello!".db0x0D.db0x0A.db0x00__str_1:.ascii"This string is at 0x6000 area.".db0x0D.db0x0A.db0x00;---------------------------------;Functiondummy_relocatable_1;---------------------------------_dummy_relocatable_1::.area_CSEG(REL,CON);---------------------------------;Functionmain;---------------------------------_main::call_printThingsldhl,(_str3)pushhlcall_printfpopaf00102$:jr00102$_str3:.dw__str_2__str_2:.ascii"This is relatively located".db0x0D.db0x0A.db0x00.area_CODE.area_INITIALIZER.area_CABS(ABS)
While it seems to work, there is actually a problem. Compiler rearranges functions and arrays as it considers. In this case, things are still almost in-place, but minimum changes impede this approach to work, like in this second version of the code:
#include<stdio.h>//////////////////////////////////////////////////////////// PIECE OF CODE THAT WE WANT TO PLACE AT 0x6000//////////////////////////////////////////////////////////// Force following code to be absolutely placed at 0x6000voiddummy_absolute_0x6000(void)__naked{__asm.area_0x6000_(ABS).org0x6000__endasm;}externunsignedchar*conststr1;externunsignedchar*conststr2;voidprintThings(){printf(str1);printf(str2);}unsignedchar*conststr1="Hello!\r\n";unsignedchar*conststr2="This string is at 0x6000 area.\r\n";//////////////////////////////////////////////////////////// PIECE OF CODE TO BE ALLOCATED BY THE LINKER (RELATIVE)//////////////////////////////////////////////////////////// Declare following code to be relocatablevoiddummy_relocatable_1(void)__naked{__asm.area_CSEG(REL,CON)__endasm;}unsignedchar*conststr3="This is relatively located\r\n";voidmain(void){printThings();printf(str3);while(1);}
With this minimum change (str1 and str2 are defined after printThings instead of previously), generated code puts str1 and str2 below main definition, leaving them in the relative area, instead of the absolute area, as wanted:
;---------------------------------;Functiondummy_absolute_0x6000;---------------------------------_dummy_absolute_0x6000::.area_0x6000_(ABS).org0x6000;---------------------------------;FunctionprintThings;---------------------------------_printThings::ldhl,(_str1)pushhlcall_printfpopafldhl,(_str2)pushhlcall_printfpopafret;---------------------------------;Functiondummy_relocatable_1;---------------------------------_dummy_relocatable_1::.area_CSEG(REL,CON);---------------------------------;Functionmain;---------------------------------_main::call_printThingsldhl,(_str3)pushhlcall_printfpopaf00102$:jr00102$_str1:;;;<<<<----Stringsstr1andstr2havecrosseddefined.dw__str_0;;;areasbecauseoftheirrearrangementduring_str2:;;;compilation..dw__str_1_str3:.dw__str_2__str_0:.ascii"Hello!".db0x0D.db0x0A.db0x00__str_1:.ascii"This string is at 0x6000 area.".db0x0D.db0x0A.db0x00__str_2:.ascii"This is relatively located".db0x0D.db0x0A.db0x00.area_CODE.area_INITIALIZER.area_CABS(ABS)
Sometimes, the problem is even worse. Next example defines only an array in a separate file, trying to locate it at 0x6000, using this "hack-method":
#include"dummy.h" // This is only to force syntax highlighting//////////////////////////////////////////////////////////// PIECE OF CODE THAT WE WANT TO PLACE AT 0x6000//////////////////////////////////////////////////////////// Force following code to be absolutely placed at 0x6000voiddummy_absolute_0x6000(void)__naked{__asm.area_0x6000_(ABS).org0x6000__endasm;}unsignedchar*constarray[5]={1,2,3,4,5};
But the result includes an unexpected switch to _CODE area, just below dummy function:
;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 3.5.5 #9498 (Linux)
;--------------------------------------------------------
.module main
.optsdcc -mz80
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
.globl _array
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _DATA
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _INITIALIZED
;--------------------------------------------------------
; absolute external ram data
;--------------------------------------------------------
.area _DABS (ABS)
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
.area _HOME
.area _GSINIT
.area _GSFINAL
.area _GSINIT
;--------------------------------------------------------
; Home
;--------------------------------------------------------
.area _HOME
.area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
.area _CODE
; ---------------------------------
; Function dummy_absolute_0x6000
; ---------------------------------
_dummy_absolute_0x6000::
.area _0x6000_ (ABS)
.org 0x6000
.area _CODE ;;; <<<< --- Why this change to _CODE area?
_array:
.dw #0x0001
.dw #0x0002
.dw #0x0003
.dw #0x0004
.dw #0x0005
.area _INITIALIZER
.area _CABS (ABS)
So, the questions are:
* Is there any way to make compiler generate code in the same order it finds it on the source file?
* Is there any other proper way or hack to force some code areas to be absolutelly located?
* Why does compiler rearrange code?
I already know the existence of the __at keyword, but it only applies to data (not functions / code) and would be less practical that just using a macro at the start of a section, for instance. Moreover, in the Z80 implementation, using __at keyword at different code files does not produce expected results, as some elements get 'absolutelly' located with respect to where the file is placed in the code, and not with respect to memory, as it is expected.
Thank you very much in advance :).
Last edit: Ronaldo 2016-02-16
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks Philipp, and apologizes for taking so long to reply (did not receive any email notification or similar).
Yes, I am aware of --codeseg and --constseg, but that's not what I wanted to do. I'm creating a library for other programmers and wanted to give them control over code placement without changing compiler options (directly from their code).
I found a "hack" solution for the problem. If I use 2 consecutive dummy functions like this:
// Force following code to be absolutely placed at 0x6000
void dummy_absolute_0x6000_catcher (void) {}
void dummy_absolute_0x6000 (void) __naked {
__asm
.area _0x6000_ (ABS)
.org 0x6000
__endasm;
}
The first one generates a label and a RET and acts as "catcher" in the sense that it makes all previous data definitions go after the catcher but previous to the new area and org definitions. This adds 1 byte to the binary per use of this method, but works. I've encapsulated this solution into macros, and that gives other coders access to this functionality directly from their code.
It's kind of a hack, not "neat" but it works and gives an interesting functionality :).
Thank you for your help.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi,
I am interested on developing a way to manually locate parts of the code at a given memory location. The idea is giving a programmer an easy way to control memory placement of some parts of its code. Therefore, I came up with this:
As you can see, the idea was to add some dummy functions that help including assembler directives to locate partes of the code. I know it is kind of a hack, but it seemed to work at first. Previous C code gets compiled into this assembly code:
While it seems to work, there is actually a problem. Compiler rearranges functions and arrays as it considers. In this case, things are still almost in-place, but minimum changes impede this approach to work, like in this second version of the code:
With this minimum change (str1 and str2 are defined after printThings instead of previously), generated code puts str1 and str2 below main definition, leaving them in the relative area, instead of the absolute area, as wanted:
Sometimes, the problem is even worse. Next example defines only an array in a separate file, trying to locate it at 0x6000, using this "hack-method":
But the result includes an unexpected switch to
_CODE
area, just below dummy function:So, the questions are:
* Is there any way to make compiler generate code in the same order it finds it on the source file?
* Is there any other proper way or hack to force some code areas to be absolutelly located?
* Why does compiler rearrange code?
I already know the existence of the
__at
keyword, but it only applies to data (not functions / code) and would be less practical that just using a macro at the start of a section, for instance. Moreover, in the Z80 implementation, using__at
keyword at different code files does not produce expected results, as some elements get 'absolutelly' located with respect to where the file is placed in the code, and not with respect to memory, as it is expected.Thank you very much in advance :).
Last edit: Ronaldo 2016-02-16
Are you aware of the SDCC options
and linker options for segment placement?
Philipp
Thanks Philipp, and apologizes for taking so long to reply (did not receive any email notification or similar).
Yes, I am aware of --codeseg and --constseg, but that's not what I wanted to do. I'm creating a library for other programmers and wanted to give them control over code placement without changing compiler options (directly from their code).
I found a "hack" solution for the problem. If I use 2 consecutive dummy functions like this:
The first one generates a label and a RET and acts as "catcher" in the sense that it makes all previous data definitions go after the catcher but previous to the new area and org definitions. This adds 1 byte to the binary per use of this method, but works. I've encapsulated this solution into macros, and that gives other coders access to this functionality directly from their code.
It's kind of a hack, not "neat" but it works and gives an interesting functionality :).
Thank you for your help.