New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Building Crypto on ESP8266 - compile errors #807
Comments
Further to above, if the line is changed: so it complies, then the following error occurs:
|
Ok, it looks like in the error case, the issue is that ESP8266 has to store strings in flash unless you access them in a special way - there's a hack for And yes... the other issue you have is probably also related to that. On ESP8266, unless you add special hacks, all constant data is put in RAM. The best solution for now would be to make sure you add |
Thanks. The jserror %s hack now compiles. I tried added the ifndef around the other functions, however still ran out of space. |
You could try also looking at |
Hi, I encountered the same issue and sent a pr with a fix (#810). @wilberforce did you find out how to make it fit? |
@urish Sorry, no. I tried what Gordon suggested with "ifndef":"ESP8266" but it was not enough. I think we need to exclude functions as I thing we are running out of rom space. |
@tve any inputs on this one? |
I'm considering writing a JavaScript module, based on the sha1.js code that @jumjum has published in the forums. It could be a standalone require("crypto") to use on boards where sha1 is not in firmware. This way a separate firmware would not be require and it's only about 1k. In my use case for web sockets, the module is used during negotiation so could be unloaded once the socket is established. |
If you save this in a projects folder in your web ide, the ws module find this module and uses it: https://raw.githubusercontent.com/wilberforce/EspruinoDocs/master/modules/crypto.min.js I'll post to the Forum with an example: |
thanks @wilberforce ! In my case, I would like to achieve TLS connections, but I am sure that crypto.js can be useful for other people :) |
@urish |
No, I think you're out of luck there. In it's default (standards-compliant) mode, mbedtls needs at least 16kB RAM, which is going to mean very little left for Espruino. If you want TLS, get a Pico and attach an ESP8266 to it. The Pico has enough RAM to handle it. |
@wilberforce @gfwilliams thanks for the feedback! I know that the Espressif SDK does have TLS support (I use it with NodeMCU). Do you know whether there was any work done on using their TLS support with Espruino? |
No, there wasn't any work done. IMO it's worth seeing if mbedtls can be tweaked to fit, because then the same code will be used for all Espruino platforms. If not we're going to end up with a bunch of code that's just left to rot, and that won't get the bugfixes and improvements that the main mbedtls-based code gets. |
Just had a quick look at this, and it seems that mbedtls will compile just fine, but as-is there's not enough memory. You can modify |
@gfwilliams I was also looking at the optimisations that @tve had done moving strings to flash, and wondering how much scope there was to free up more ram? |
|
@tve thanks. I tired to build using the top strings, but using a recent git pull with the standard Makefile, I can no longer build... Sorry can't paste here, the error is here: https://gitter.im/espruino/Espruino?at=56de471268ddef776469772f It appears that the user1 elf is bigger than 480k and won't fit in the iram1_0_seg _section ? |
Seems like it is possible to fit mbedtls into the ESP8266, as it has been done in esp-open-rtos |
@tve
The file size is 0 - what am I doing wrong? |
@wilberforce use xtensa-lx106-elf-objdump -h filename.o to check the used named in my case it is .rodata.str1.1 and not .rodata.str1.4, so change the Makefile
|
Great! Thanks. here is the output: Top 20 from ./topstrings: |
In jsinteractive - there is the load banner, and quite a few calls to jsiConsolePrint which I don't think is using the FLASH_STR #define, so quite a few of these strings could go into flash memory |
@wilberforce @gfwilliams gfwilliams I have spent some time on it and after reducing the number of js variables from 1400 to 1000 (inside However, make complains about:
Two questions:
|
@urish http://forum.espruino.com/comments/12848811/ This might be small enough. However, I think you will run out of available RAM as the TLS stuff uses quite large buffers - bigger than the ESP8266 will have available (16K or so from memory). You might be able to compile with a smaller buffer size, perhaps 1K - and see if your https:// server will still connect to this. One way of testing this might be to use the linux install, and try the smaller packet size with this first. Is it https:// requests you want to do? You could use a proxy service, or use a pico and esp8266-01, as you won't have the memory limitation then |
Yeah, you may run out of memory fot HTTPS (at least without tweaking the config.h to use non-standard (lower than normal) buffer sizes) - however I got the impression you might have just wanted Crypto for the SHA1 and other features - in which case I'd imagine you're fine. Strange about the high usage from jsinteractive.c - if jsiConsolePrintf could be tweaked with a define the same way the errors have, you might be able to save quite bit of RAM. |
Just to add, are you building with As I understand it, you could use more flash, but it would require some linker tweaks and effectively stops you being able to do firmware updates over the air. |
@gfwilliams building with For those who need crypto - I managed to compile a firmware just with crypto (without SSL), and the image size seems to fit (haven't tested it yet on the real device, though) In my case - I want SSL indeed (for HTTPS and secure MQTT), and my use case is presenting the ESP8266 as an IoT capable device on tech talks I am giving. Currently, I use NodeMCU, but most of my audience is not familiar with Lua, so being able to use Espruino can be a game changer in my case. |
I'm not sure exactly. @tve might have some ideas, or I think it's just a matter of googling. You need to spread the firmware over user1 and user2 areas. Having said that, you could add the SAVE_ON_FLASH define in the Makefile, and remove the debugger and command completion defines if they were in there. It might save you a bit of space. Also you can edit |
good work :) |
Now need to guess which one is missing - heap or js vars |
Looks like at least one is required in the or.. I think the forum post mentions these options...
To use https:// you should not need to use the cert options... did you try:
|
Looks like heap: https://github.com/espruino/Espruino/search?utf8=%E2%9C%93&q=SOCKET_ERR_MEM
507 int err = code; |
Yup, seems like it is heap - less js vars, and now we are getting |
Well, after playing with esp-open-rtos for a while, it seems like |
@gfwilliams is there a way to allocate a big buffer off the js-vars space? |
@urish all the memory needed for TLS comes straight out of the JsVars space already - so you need to increase the amount of variables as much as possible. If you want to change that, you'll have to modify |
@gfwilliams thanks for the response! I will look into it further, some more questions that come into my head:
Where can I find information how to move those strings into the Flash so they won't consume any RAM? Thanks! |
But actually without much success, so I'm not 100% sure what's going on there. There should be a bunch of stuff on the net about moving ESP8266 stuff from RAM into flash though |
@tve already did a whole bunch here: 294f3ff It involves #define to wrap the strings. |
Yikes . The oid.c is full of strings! Are you sure you need it for tls v 1.2? Might be worth looking into the switches you need for a minimum build, I reference a minimum config.h above that might be worth a shot.. |
Actually you should note that some of this stuff works by first copying the string from flash into RAM - but you don't need to do that (and probably shouldn't in the case of the crypto). It'd be better to read directly from flash |
following on what @gfwilliams is saying, here are the macro's that pack into iRom, and then read from it: |
Progress report - So far, the only module that I was able to disable without impacting the ability to establish TLS connection is I tried to move the big tables into the ROM by adding static const oid_x520_attr_t oid_x520_attr_type[] __attribute__((section(".irom.literal")) =
{
{
{ ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" },
"CN",
},
...
} But this seems to have no affect on the size in topstrings (whereas commenting the entire struct content definitely reduces the size of the module in topstrings). Am I doing it right? |
check object file with xtensa-lx106-elf-objdump -h path/name_of_object_file.o for a line with .irom.literal to make sure that it will be stored in flash |
here is the definition of the macro: Line 49 in b61d388
#define FLASH_STR(name, x) static char name[] __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x It also aligns of 4 byte boundarys which is required to read from flash. and here is example use in the simple case:
I think in this case you are declaring arrays of strings, so this would need to be modified.... Also here is using an array of strings, but there has got to be a better way!
|
Looks like this is done a cunning way with arduino build: lfaustini wrote:how can I push the WString.cpp.o into the .irom0.text section? So this ld file moves stuff into flash, without having to use macros. I think it works on functions too.... Looks promising.. |
You could try it. I wonder if that's program code only though - He's talking about WString.o - not WStrings in general :) The issue is that accesses to flash need to word-only and word-aligned. Just dumping a string into ROM will be fine until you go to access a character from it. Hence the macros. Until the compiler is smart enough to auto-generate only word accesses for stuff in ROM, you will have no choice but to manually modify code. |
This technique installs an exception handler that catches the mis-aligned reads, and corrects them. https://github.com/cesanta/smart.js/blob/master/smartjs/platforms/esp8266/user/esp_flash_bytes.c It looks a lot simpler that having to copy all the ROM strings from iRom to ram before use... |
What is the performance impact of this, though? |
I have no idea - convenience vs performance? |
well, the performance already isn't all that great. At some point it just sucks. You're gonna have to use some macro to put the strings into flash anyhow, is there that much to be gained by not having a macro that does the copy? How many bytes of strings are left? How many of those could possibly be moved to flash? |
Top 20 from ./topstrings: If the constants in jswrapper were aligned on 4 byte boundaries we could keep the reference tables in flash... That would save a heap of space". The non- string tables might be any easy target, as they are generated - these are not showing in the top strings that you have kindly written. |
we will probably also be able to get mbedTLS working on the ESP :-) |
Assuming we could catch unaligned accesses, we could just copy all the const data to flash and remove the
I guess it depends how you look at it. It's not great, so would people notice if it got a bit worse? :) The main complaint at the moment actually seems to be lack of RAM, which this might help with. If someone has some free time/inclination, maybe they could try this just dump everything into ROM, removing all the ESP8266-specific flash copying/etc, and using that exception handler. The only way to know for sure is to do some benchmarks and see how much it hits performance. If it's loads then I think it'd be a bad idea, but if it's a few percent I think it's a hit worth taking. From my point of view, it'd be nice to remove the slightly iffy preprocessor stuff around print statements, and I think if you're printing/making error messages then you don't really care about performance either. The one thing I think could hit performance is the symbol table, but then a few very simple ESP8266-specific tweaks in Perhaps some of the mbedTLS stuff could end up being quite slow, but then if it's a choice of having it slow or not fitting it in at all, I think it's worth having it in. |
@gfwilliams has merged the build with sha crypto for the esp8266 - so now the standard build will support web sockets: |
In aes.c there is a save-to-rom macro, however in the esp8266 case the tables still end up in ram. There is still not enough heap space for the buffers, so unless more code is moved from ram to irom, TLS support for https can't work without reducing jsvars. My initial aim of supporting web sockets via SHA1 is done, so closing issue. |
Adding the the Makefile:
The issue appears to be the flash_str #define:
I tried changing:
#define FLASH_STR(name, x) static char name[] __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x
to
#define FLASH_STR(name, x) static char * name __attribute__((section(".irom.literal"))) __attribute__((aligned(4))) = x
libs/network/esp8266/jswrap_esp8266_network.c:151:3: error: initializer element is not constant
__wr0, __wr1, __wr2, __wr3, __wr4, __wr5, __wr6, __wr7, __wr8, __wr9, __wr10,
^
libs/network/esp8266/jswrap_esp8266_network.c:151:3: error: (near initialization for 'wifiReasons[0]')
However then it fails here:
What is the best way to solve this?
The text was updated successfully, but these errors were encountered: