Package: objutils
Binary data stored in hex-files is in widespread use especially in embedded systems applications.objutilsgives you programmatic access to a wide array of formats and offers an practical API
to work with such data.Get the latest version fromGithubInstallationpipinstallobjutilsor runpythonsetup.pydevelopon your local installation.PrerequisitesPython >= 3.4FeaturesELF files could read, including symbols.Typified access (scalar and arrays) to binaray data.Supported HEX formatsobjutilssupports a bunch of HEX formats…Currentcodec / format nameihex (Intel HEX)shf (S Hexdump (rfc4194))srec (Motorola S-Records)titxt (Texas Instruments Text)Historicalcodec / format nameash (ASCII Space Hex)cosmac (RCA Cosmac)emon52 (Elektor EMON52)etek (Tektronix Extended Hexadecimal)fpc (Four Packed Code)mostec (MOS Technology)rca (RCA)sig (Signetics)tek (Tektronix Hexadecimal)codecis the first parameter to dump() / load() functions, e.g.:img=objutils.load("ihex","myHexFile.hex")# Load an Intel HEX file...objutils.dump("srec","mySRecFile.srec",img)# and save it as S-Records.First stepsIf you are interested, whatobjutilsprovides to you out-of-the-box, refer toScriptsdocumentation.In any case, you should work through the following tutorial:First import all classes and functions used in this tutorial.fromobjutilsimportImage,Section,dump,dumps,load,loadsEverything starts with hello world…sec0=Section(start_address=0x1000,data="Hello HEX world!")The constructor parameters toSectionreflect what they are about:
A continuous area of memory with an start address.datais not necessarily a string,array.array**s, **byte,bytearraywill also do,
or from an internal point of view: everything that is convertible tobytearraycould be used.Note:start_addressanddataare positional arguments, so there is no need to use them as keywords (just for the sake of illustration).Now let’s inspect our section.sec0.hexdump()0000100048656c6c6f2048455820776f726c6421|HelloHEXworld!|---------------16bytes---------------hexdump()gives us, what in the world of hackers is known as a canonical hexdump.HEX files usually consist of more than one section, so let’s create another one.sec1=Section(0x2000,range(1,17))sec1.hexdump()000020000102030405060708090a0b0c0d0e0f10|................|---------------16bytes---------------Now, let’s glue together our sections.img0=Image([sec0,sec1])print(img0)Section(address=0X00001000,length=16,data=b'Hello HEX world!')Section(address=0X00002000,length=16,data=b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10')Images are obviously a container for sections, and they are always involved if you are interacting with disk based HEX files.dump("srec","example0.srec",img0)The resulting file could be inspected from command line.$catexample0.srecS113100048656C6C6F2048455820776F726C64217AS11320000102030405060708090A0B0C0D0E0F1044And loaded again…img1=load("srec","example0.srec")print(img1)Section(address=0X00001000,length=16,data=b'Hello HEX world!')Section(address=0X00002000,length=16,data=b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10')This leads to the conversion idiom.img1=load("srec","example0.srec")dump("ihex","example0.hex",img1)Note: the formats above listed as historical are for one good reason historical: they are only 16bit wide, so if you want to convert,
say asrecfile for a 32bit MCU to them, you’re out of luck.OK, we’re starting another session.sec0=Section(0x100,range(1,9))sec1=Section(0x108,range(9,17))img0=Image([sec0,sec1])print(img0)Section(address=0X00000100,length=16,data=b'\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10')img0.hexdump()Section#0000-------------000001000102030405060708090a0b0c0d0e0f10|................|---------------16bytes---------------Two sections with consecutive address ranges concatenated to one, this may or may not what you are expected.For this reasonImagehas ajoinparameter.sec0=Section(0x100,range(1,9))sec1=Section(0x108,range(9,17))img0=Image([sec0,sec1],join=False)print(img0)Section(address=0X00000100,length=8,data=b'\x01\x02\x03\x04\x05\x06\x07\x08')Section(address=0X00000108,length=8,data=b'\t\n\x0b\x0c\r\x0e\x0f\x10')img0.hexdump()Section#0000-------------000001000102030405060708|........|---------------8bytes---------------Section#0001-------------00000108090a0b0c0d0e0f10|........|---------------8bytes---------------One feature that setsobjutilsapart from other libraries of this breed is typified access.We are starting with a new image.img0=Image([Section(0x1000,bytes(64))])print(img0)Section(address=0X00001000,length=64,data=b'\x00\x00\x00\x00\x00\x00\x00...00\x00\x00\x00\x00\x00\x00\x00')We are now writing a string to our image.img0=Image([Section(0x1000,bytes(64))])img0.write(0x1010,[0xff])img0.hexdump()Section#0000-------------0000100000000000000000000000000000000000|................|00001010ff000000000000000000000000000000|................|0000102000000000000000000000000000000000|................|0000103000000000000000000000000000000000|................|img0.write_string(0x1000,"Hello HEX world!")img0.hexdump()Section#0000-------------0000100048656c6c6f2048455820776f726c6421|HelloHEXworld!|0000101000000000000000000000000000000000|................|*0000103000000000000000000000000000000000|................|---------------64bytes---------------Notice the difference? In ourSectionexample above, the string passed as adataparameter
was just a bunch of bytes, but now it is a “real” C-string (there is a opposite function,read_string,
that scans for a terminatingNULLcharacter).Usewrite()andread()functions, if you want to access plain bytes.But there is also support for numerical types.img0=Image([Section(0x1000,bytes(64))])img0.write_numeric(0x1000,0x10203040,"uint32_be")img0.write_numeric(0x1004,0x50607080,"uint32_le")img0.hexdump()Section#0000-------------0000100010203040807060500000000000000000|.0@.p`P........|0000101000000000000000000000000000000000|................|*0000103000000000000000000000000000000000|................|---------------64bytes---------------The folling types are supported:uint8int8uint16int16uint32int32uint64int64float32float64In any case, endianess suffixes_beor_leare required.Arrays are also supported.img0=Image([Section(0x1000,bytes(64))])img0.write_numeric_array(0x1000,[0x1000,0x2000,0x3000,0x4000,0x5000,0x6000,0x7000,0x8000],"uint16_le")img0.hexdump()Section#0000-------------0000100000100020003000400050006000700080|....0.@.P.`.p..|0000101000000000000000000000000000000000|................|*0000103000000000000000000000000000000000|................|---------------64bytes---------------This concludes our tutorial for now, but there is more stuff to follow…DocumentationFor full documentation, including installation, tutorials and PDF documents, please seeReadthedocsBugs/RequestsPlease use theGitHub issue trackerto submit bugs or request featuresReferencesHereis an overview of some of the classic hex-file formats.AuthorsChristoph Schueler- Initial work and project lead.LicenseThis project is licensed under the GNU General Public License v2.0ContributionIf you contribute code to this project, you are implicitly allowing your code to be distributed under the GNU General Public License v2.0. You are also implicitly verifying that all code is your original work.