+ Added fpcres

git-svn-id: trunk@954 -
This commit is contained in:
michael 2005-08-28 09:31:26 +00:00
parent 51d0c0ef2a
commit d570eabe53
10 changed files with 3159 additions and 93 deletions

7
.gitattributes vendored
View File

@ -6271,6 +6271,13 @@ utils/fpcm/fpcmpkg.pp svneol=native#text/plain
utils/fpcm/fpcmwr.pp svneol=native#text/plain
utils/fpcm/makefile.exm -text
utils/fpcm/readme.txt svneol=native#text/plain
utils/fpcres/Makefile svneol=native#text/plain
utils/fpcres/Makefile.fpc svneol=native#text/plain
utils/fpcres/elfbfd.pas svneol=native#text/plain
utils/fpcres/elfres.pas svneol=native#text/plain
utils/fpcres/elfresfix.pas svneol=native#text/plain
utils/fpcres/fpcres.lpi svneol=native#text/plain
utils/fpcres/fpcres.pas svneol=native#text/plain
utils/fpdoc/COPYING -text
utils/fpdoc/Makefile svneol=native#text/plain
utils/fpdoc/Makefile.fpc svneol=native#text/plain

View File

@ -1,8 +1,8 @@
#
# Don't edit, this file is generated by FPCMake Version 2.0.0 [2005/08/10]
# Don't edit, this file is generated by FPCMake Version 1.9.8 [2005/04/10]
#
default: all
MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-emx i386-watcom i386-netwlibc i386-wince m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos powerpc-linux powerpc-netbsd powerpc-macos powerpc-darwin powerpc-morphos sparc-linux sparc-netbsd sparc-solaris x86_64-linux x86_64-freebsd x86_64-win64 arm-linux arm-wince
MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-emx i386-watcom i386-netwlibc m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos powerpc-linux powerpc-netbsd powerpc-macos powerpc-darwin powerpc-morphos sparc-linux sparc-netbsd sparc-solaris x86_64-linux x86_64-freebsd arm-linux
BSDs = freebsd netbsd openbsd darwin
UNIXs = linux $(BSDs) solaris qnx
LIMIT83fs = go32v2 os2 emx watcom
@ -233,7 +233,7 @@ PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages/base $(FPCDIR)/packages/ext
override PACKAGE_NAME=utils
override PACKAGE_VERSION=2.0.0
ifeq ($(FULL_TARGET),i386-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),i386-go32v2)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
@ -277,11 +277,8 @@ endif
ifeq ($(FULL_TARGET),i386-netwlibc)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),i386-wince)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),m68k-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),m68k-freebsd)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
@ -302,7 +299,7 @@ ifeq ($(FULL_TARGET),m68k-palmos)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),powerpc-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),powerpc-netbsd)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
@ -317,7 +314,7 @@ ifeq ($(FULL_TARGET),powerpc-morphos)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),sparc-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),sparc-netbsd)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
@ -326,19 +323,13 @@ ifeq ($(FULL_TARGET),sparc-solaris)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),x86_64-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),x86_64-freebsd)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),x86_64-win64)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),arm-linux)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
endif
ifeq ($(FULL_TARGET),arm-wince)
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc
override TARGET_DIRS+=fpcm tply h2pas fprcp dxegen fpdoc fpcres
endif
ifeq ($(FULL_TARGET),i386-linux)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
@ -385,9 +376,6 @@ endif
ifeq ($(FULL_TARGET),i386-netwlibc)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),i386-wince)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),m68k-linux)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
@ -439,15 +427,9 @@ endif
ifeq ($(FULL_TARGET),x86_64-freebsd)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),x86_64-win64)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),arm-linux)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),arm-wince)
override TARGET_PROGRAMS+=ppdep ptop rstconv data2inc delp bin2obj postw32
endif
ifeq ($(FULL_TARGET),i386-linux)
override TARGET_RSTS+=rstconv
endif
@ -493,9 +475,6 @@ endif
ifeq ($(FULL_TARGET),i386-netwlibc)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),i386-wince)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),m68k-linux)
override TARGET_RSTS+=rstconv
endif
@ -547,15 +526,9 @@ endif
ifeq ($(FULL_TARGET),x86_64-freebsd)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),x86_64-win64)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),arm-linux)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),arm-wince)
override TARGET_RSTS+=rstconv
endif
ifeq ($(FULL_TARGET),i386-linux)
override CLEAN_UNITS+=ptopu
endif
@ -601,9 +574,6 @@ endif
ifeq ($(FULL_TARGET),i386-netwlibc)
override CLEAN_UNITS+=ptopu
endif
ifeq ($(FULL_TARGET),i386-wince)
override CLEAN_UNITS+=ptopu
endif
ifeq ($(FULL_TARGET),m68k-linux)
override CLEAN_UNITS+=ptopu
endif
@ -655,15 +625,9 @@ endif
ifeq ($(FULL_TARGET),x86_64-freebsd)
override CLEAN_UNITS+=ptopu
endif
ifeq ($(FULL_TARGET),x86_64-win64)
override CLEAN_UNITS+=ptopu
endif
ifeq ($(FULL_TARGET),arm-linux)
override CLEAN_UNITS+=ptopu
endif
ifeq ($(FULL_TARGET),arm-wince)
override CLEAN_UNITS+=ptopu
endif
override INSTALL_FPCPACKAGE=y
ifdef REQUIRE_UNITSDIR
override UNITSDIR+=$(REQUIRE_UNITSDIR)
@ -1562,14 +1526,6 @@ REQUIRE_PACKAGES_PASJPEG=1
REQUIRE_PACKAGES_NETDB=1
REQUIRE_PACKAGES_LIBASYNC=1
endif
ifeq ($(FULL_TARGET),i386-wince)
REQUIRE_PACKAGES_RTL=1
REQUIRE_PACKAGES_PASZLIB=1
REQUIRE_PACKAGES_FCL=1
REQUIRE_PACKAGES_PASJPEG=1
REQUIRE_PACKAGES_NETDB=1
REQUIRE_PACKAGES_LIBASYNC=1
endif
ifeq ($(FULL_TARGET),m68k-linux)
REQUIRE_PACKAGES_RTL=1
REQUIRE_PACKAGES_PASZLIB=1
@ -1757,14 +1713,6 @@ REQUIRE_PACKAGES_POSTGRES=1
REQUIRE_PACKAGES_MYSQL=1
REQUIRE_PACKAGES_SQLITE=1
endif
ifeq ($(FULL_TARGET),x86_64-win64)
REQUIRE_PACKAGES_RTL=1
REQUIRE_PACKAGES_PASZLIB=1
REQUIRE_PACKAGES_FCL=1
REQUIRE_PACKAGES_PASJPEG=1
REQUIRE_PACKAGES_NETDB=1
REQUIRE_PACKAGES_LIBASYNC=1
endif
ifeq ($(FULL_TARGET),arm-linux)
REQUIRE_PACKAGES_RTL=1
REQUIRE_PACKAGES_PASZLIB=1
@ -1778,14 +1726,6 @@ REQUIRE_PACKAGES_POSTGRES=1
REQUIRE_PACKAGES_MYSQL=1
REQUIRE_PACKAGES_SQLITE=1
endif
ifeq ($(FULL_TARGET),arm-wince)
REQUIRE_PACKAGES_RTL=1
REQUIRE_PACKAGES_PASZLIB=1
REQUIRE_PACKAGES_FCL=1
REQUIRE_PACKAGES_PASJPEG=1
REQUIRE_PACKAGES_NETDB=1
REQUIRE_PACKAGES_LIBASYNC=1
endif
ifdef REQUIRE_PACKAGES_RTL
PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR))))))
ifneq ($(PACKAGEDIR_RTL),)
@ -2121,7 +2061,7 @@ else
FPCCPUOPT:=
endif
endif
override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n
override FPCOPT+=-Xs $(FPCCPUOPT) -n
override FPCOPTDEF+=RELEASE
endif
ifdef STRIP
@ -2601,6 +2541,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifeq ($(FULL_TARGET),i386-go32v2)
TARGET_DIRS_FPCM=1
@ -2715,14 +2656,6 @@ TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
endif
ifeq ($(FULL_TARGET),i386-wince)
TARGET_DIRS_FPCM=1
TARGET_DIRS_TPLY=1
TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
endif
ifeq ($(FULL_TARGET),m68k-linux)
TARGET_DIRS_FPCM=1
TARGET_DIRS_TPLY=1
@ -2730,6 +2663,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifeq ($(FULL_TARGET),m68k-freebsd)
TARGET_DIRS_FPCM=1
@ -2786,6 +2720,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifeq ($(FULL_TARGET),powerpc-netbsd)
TARGET_DIRS_FPCM=1
@ -2826,6 +2761,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifeq ($(FULL_TARGET),sparc-netbsd)
TARGET_DIRS_FPCM=1
@ -2850,6 +2786,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifeq ($(FULL_TARGET),x86_64-freebsd)
TARGET_DIRS_FPCM=1
@ -2859,14 +2796,6 @@ TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
endif
ifeq ($(FULL_TARGET),x86_64-win64)
TARGET_DIRS_FPCM=1
TARGET_DIRS_TPLY=1
TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
endif
ifeq ($(FULL_TARGET),arm-linux)
TARGET_DIRS_FPCM=1
TARGET_DIRS_TPLY=1
@ -2874,14 +2803,7 @@ TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
endif
ifeq ($(FULL_TARGET),arm-wince)
TARGET_DIRS_FPCM=1
TARGET_DIRS_TPLY=1
TARGET_DIRS_H2PAS=1
TARGET_DIRS_FPRCP=1
TARGET_DIRS_DXEGEN=1
TARGET_DIRS_FPDOC=1
TARGET_DIRS_FPCRES=1
endif
ifdef TARGET_DIRS_FPCM
fpcm_all:
@ -3153,6 +3075,51 @@ fpdoc:
$(MAKE) -C fpdoc all
.PHONY: fpdoc_all fpdoc_debug fpdoc_smart fpdoc_release fpdoc_units fpdoc_examples fpdoc_shared fpdoc_install fpdoc_sourceinstall fpdoc_exampleinstall fpdoc_distinstall fpdoc_zipinstall fpdoc_zipsourceinstall fpdoc_zipexampleinstall fpdoc_zipdistinstall fpdoc_clean fpdoc_distclean fpdoc_cleanall fpdoc_info fpdoc_makefiles fpdoc
endif
ifdef TARGET_DIRS_FPCRES
fpcres_all:
$(MAKE) -C fpcres all
fpcres_debug:
$(MAKE) -C fpcres debug
fpcres_smart:
$(MAKE) -C fpcres smart
fpcres_release:
$(MAKE) -C fpcres release
fpcres_units:
$(MAKE) -C fpcres units
fpcres_examples:
$(MAKE) -C fpcres examples
fpcres_shared:
$(MAKE) -C fpcres shared
fpcres_install:
$(MAKE) -C fpcres install
fpcres_sourceinstall:
$(MAKE) -C fpcres sourceinstall
fpcres_exampleinstall:
$(MAKE) -C fpcres exampleinstall
fpcres_distinstall:
$(MAKE) -C fpcres distinstall
fpcres_zipinstall:
$(MAKE) -C fpcres zipinstall
fpcres_zipsourceinstall:
$(MAKE) -C fpcres zipsourceinstall
fpcres_zipexampleinstall:
$(MAKE) -C fpcres zipexampleinstall
fpcres_zipdistinstall:
$(MAKE) -C fpcres zipdistinstall
fpcres_clean:
$(MAKE) -C fpcres clean
fpcres_distclean:
$(MAKE) -C fpcres distclean
fpcres_cleanall:
$(MAKE) -C fpcres cleanall
fpcres_info:
$(MAKE) -C fpcres info
fpcres_makefiles:
$(MAKE) -C fpcres makefiles
fpcres:
$(MAKE) -C fpcres all
.PHONY: fpcres_all fpcres_debug fpcres_smart fpcres_release fpcres_units fpcres_examples fpcres_shared fpcres_install fpcres_sourceinstall fpcres_exampleinstall fpcres_distinstall fpcres_zipinstall fpcres_zipsourceinstall fpcres_zipexampleinstall fpcres_zipdistinstall fpcres_clean fpcres_distclean fpcres_cleanall fpcres_info fpcres_makefiles fpcres
endif
ifdef TARGET_DIRS_FPMC
fpmc_all:
$(MAKE) -C fpmc all

View File

@ -10,6 +10,7 @@ version=2.0.0
dirs=fpcm tply h2pas fprcp dxegen fpdoc
programs=ppdep ptop rstconv data2inc delp bin2obj postw32
dirs_win32=fpmc
dirs_linux=fpcres
rsts=rstconv
[require]

1519
utils/fpcres/Makefile Normal file

File diff suppressed because it is too large Load Diff

22
utils/fpcres/Makefile.fpc Normal file
View File

@ -0,0 +1,22 @@
#
# Makefile.fpc for FPCMake
#
[target]
programs=fpcres
rsts=fpcres fpcresfix elfres
[clean]
units=fpcresfix elfbfd elfres
[require]
packages=rtl
[install]
fpcpackage=y
[default]
fpcdir=../..
[rules]
fpcmake$(EXEEXT): fpcresfix.pas elfbfd.pas elfres.pas fpcres.pas

150
utils/fpcres/elfbfd.pas Normal file
View File

@ -0,0 +1,150 @@
{$ifdef fpc}
{$mode objfpc}
{$endif}
{$H+}
unit elfbfd;
{ELF Binary Format Description. 32/64 bit definitions }
interface
const
SHT_NULL = 0;
SHT_PROGBITS = 1;
SHT_SYMTAB = 2;
SHT_STRTAB = 3;
SHT_RELA = 4;
SHT_HASH = 5;
SHT_DYNAMIC = 6;
SHT_NOTE = 7;
SHT_NOBITS = 8;
SHT_REL = 9;
SHT_SHLIB = 10;
SHT_DYNSYM = 11;
SHF_WRITE = 1;
SHF_ALLOC = 2;
SHF_EXECINSTR = 4;
PT_NULL = 0;
PT_LOAD = 1;
PT_DYNAMIC = 2;
PT_INTERP = 3;
PT_NOTE = 4;
PT_SHLIB = 5;
PT_PHDR = 6;
PT_LOOS = $60000000;
PT_HIOS = $6fffffff;
PT_LOPROC = $70000000;
PT_HIPROC = $7fffffff;
Type
TElf32header = packed record
magic0123: longint;
file_class: byte;
data_encoding: byte;
file_version: byte;
padding: array[$07..$0F] of byte;
e_type: word;
e_machine: word;
e_version: longint;
e_entry: longint; { entrypoint }
e_phoff: longint; { program header offset }
e_shoff: longint; { sections header offset }
e_flags: longint;
e_ehsize: word; { elf header size in bytes }
e_phentsize: word; { size of an entry in the program header array }
e_phnum: word; { 0..e_phnum-1 of entrys }
e_shentsize: word; { size of an entry in sections header array }
e_shnum: word; { 0..e_shnum-1 of entrys }
e_shstrndx: word; { index of string section header }
end;
TElf64header = packed record
magic0123: longint;
file_class: byte;
data_encoding: byte;
file_version: byte;
padding: array[$07..$0F] of byte;
e_type: word;
e_machine: word;
e_version: longint;
e_entry: int64; { entrypoint }
e_phoff: int64; { program header offset }
e_shoff: int64; { sections header offset }
e_flags: longint;
e_ehsize: word; { elf header size in bytes }
e_phentsize: word; { size of an entry in the program header array }
e_phnum: word; { 0..e_phnum-1 of entrys }
e_shentsize: word; { size of an entry in sections header array }
e_shnum: word; { 0..e_shnum-1 of entrys }
e_shstrndx: word; { index of string section header }
end;
TElf32sechdr = packed record
sh_name: longint;
sh_type: longint;
sh_flags: longint;
sh_addr: longint;
sh_offset: longint;
sh_size: longint;
sh_link: longint;
sh_info: longint;
sh_addralign: longint;
sh_entsize: longint;
end;
TElf64sechdr = packed record
sh_name: longint;
sh_type: longint;
sh_flags: longint;
sh_addr: int64;
sh_offset: int64;
sh_size: int64;
sh_link: longint;
sh_info: longint;
sh_addralign: int64;
sh_entsize: int64;
end;
{ FPC resources }
TELF32ResourceSectionInfo = packed record
ptr: longint;
size: longint;
end;
TELF64ResourceSectionInfo = packed record
ptr: int64;
size: int64;
end;
TELF32ResourceInfo = packed record
reshash: longint; // always 32bit, contains an ELF hash of the resource entries name
restype: longint; // always 32bit, contains the resource type ID compatible with Windows RES IDs
ptr: longint; // Byte offset to the resource inside the resdata section.
name: longint; // Byte offset to the the resource name inside the ressym section.
size: longint; // The size of the resource entry
end;
TELF64ResourceInfo = packed record
reshash: longint; // always 32bit, contains an ELF hash of the resource entries name
restype: longint; // always 32bit, contains the resource type ID compatible with Windows RES IDs
ptr: int64; // Byte offset to the resource inside the resdata section.
name: int64; // Byte offset to the the resource name inside the ressym section.
size: int64; // The size of the resource entry
end;
TELF32ResourceSectionTable = packed record
version: integer;
resentries: integer;
ressym: TELF32ResourceSectionInfo;
reshash: TELF32ResourceSectionInfo;
resdata: TELF32ResourceSectionInfo;
resspare: TELF32ResourceSectionInfo;
resstr: TELF32ResourceSectionInfo;
end;
implementation
end.

692
utils/fpcres/elfres.pas Normal file
View File

@ -0,0 +1,692 @@
{ *********************************************************************** }
{ }
{ fpcres2elf - Free Pascal Resource to ELF object compiler }
{ Part of the Free Pascal and CrossFPC distributions }
{ }
{ Copyright (C) 2005 Simon Kissel }
{ }
{ See the file COPYING.FPC, included in the FPC distribution, }
{ for details about the copyright. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ *********************************************************************** }
{
This unit will compile an ELF object file out of a supplied .res resource
file. Optionally, Delphi/Kylix dfm/xfm form files are also accepted as
input. These will automatically be converted into resources internally.
fpcres2elf builds with Delphi, Kylix and FPC.
Currently this only works on 32Bit targets, but support for 64Bit targets
is in the works. Support for big endian systems is completely missing,
though.
Format used for the various resource sections:
fpc.resptrs: This section is contained in resptrs.o and always linked to the executable by
FPC. It containes an exported label fpcrespointers, which is used at runtime
to find the resptrs section in memory. The resptrs contains pointers to all the
sections and their sizes. These are updated in a post-precessing step by the
compiler and by the external resource embedder when applied to an ELF file.
This section always is 128 Bytes long and initially filled with zeros.
The first integer (32/64 Bit) value in this section contains the version
number of the resource system. Currently this value is 1.
The second integer (32/64 Bit) value in this section contains the number of
resources.
After this follows a version-defined number of TFPCResourceSectionInfo entries.
fpc.ressym: Contains the resource names. This simply is a stream of zero-terminated strings.
Only textual names are supported, numeric IDs get autoconverted to #ID's.
The reshash table has got a byte index into ressym to quickly get that data if needed
fpc.reshash: n TFPCResourceInfo records. (number of entries is defined in fpc.resptrs)
fpc.resdata: Contains the plain resource data stream. A byte index into the data stream
is given for each resource entry in TResourceInfo
fpc.resspare: An empty section which is resized to make room if the size of any of the previous
sections gets changed. NOT USED IN VERSION 1 (SIZE WILL BE 0)
fpc.resstr: This section is completely seperated from the rest and contains a block of
resourcestrings in internal FPC format.
resptr TFPCResourceSectionInfo list for FPC resources version 1:
Index Pointer to
0 ressym
1 reshash
2 resdata
3 resspare
4 resstr
5 reserved for future extension (stabs)
6 reserved for future extension
}
{$ifdef fpc}
{$mode objfpc}
{$endif}
{$H+}
unit elfres;
interface
uses
elfbfd,
SysUtils,
Classes;
const fpcres2elf_version=1;
// Do not change the following consts, they are dummy tables to generate an .o that makes ld happy
const shstrtab = #0+'.symtab'+#0+'.strtab'+#0+'.shstrtab'+#0+'.text'+#0+'.data'+#0+
'.bss'+#0+'fpc.ressym'+#0+'fpc.resstr'+#0+'fpc.reshash'+#0+
'fpc.resdata'+#0+'fpc.resspare'+#0+#0;
symtab = #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$01#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$02#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$03#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$04#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$05#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$06#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$07#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$03#$00#$08#$00;
strtab = #$00#$00; // this actually is just one byte long
zeros = #$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00;
fake = 'fakefakefakefakefakefakefakefake';
// header of a windows 32 bit .res file (16 bytes)
reshdr = #$00#$00#$00#$00#$20#$00#$00#$00#$FF#$FF#$00#$00#$FF#$FF#$00#$00+
#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00;
FilerSignature: array[1..4] of Char = 'TPF0';
SDefaultExtension = '.or';
Type
{ TElfResCreator }
TElfResCreator = Class(TObject)
private
FDestFileName: String;
FExtension: string;
FSourceFileName: String;
FOverwrite: Boolean;
FVerbose: Boolean;
FVersion: Integer;
Protected
FSectionStream: TMemoryStream;
FDataStream: TMemoryStream;
FSymStream: TMemoryStream;
FHashStream: TMemoryStream;
sectionheader_ofs: integer;
shstrtab_ofs: integer;
CurrentResource:integer;
resheader: string;
Signature: byte;
Procedure AllocateData; virtual;
Procedure FreeData; virtual;
Procedure DoAlign(const a: integer);
Public
Constructor Create;
Procedure Convert(Const Source,Destination : String);
Procedure ConvertStreams(Source,Dest : TStream);
Procedure DoConvertStreams(Source,Dest : TStream); virtual;Abstract;
Property Verbose : Boolean Read FVerbose Write FVerbose;
Property SourceFileName : String Read FSourceFileName;
Property DestFileName : String Read FDestFileName;
Property Overwrite : Boolean Read FOverwrite Write FOverWrite;
Property Version : Integer Read FVersion Write FVersion;
Property Extension : string Read FExtension Write FExtension;
end;
{ TElf32ResCreator }
TElf32ResCreator = Class(TElfResCreator)
Private
ResourceEntries: array of TELF32ResourceInfo;
Protected
Procedure AllocateData; override;
Procedure FreeData; override;
public
procedure LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
procedure LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
procedure LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
Procedure DoConvertStreams(Source,Dest : TStream); override;
end;
{ TElf64Creator }
TElf64ResCreator = Class(TElfResCreator)
Procedure DoConvertStreams(Source,Dest : TStream); override;
end;
EElfResError = Class(Exception);
implementation
resourcestring
SErrUnrecognizedFormat = 'Unrecognized file format for input file "%s"';
Procedure DoError (Msg : String);
begin
Raise EElfResError.Create(Msg);
end;
Procedure DoErrorFmt (Msg : String; Args : Array of const);
begin
Raise EElfResError.CreateFmt(Msg,Args);
end;
function HashELF(const S : string) : longint;
{Note: this hash function is described in "Practical Algorithms For
Programmers" by Andrew Binstock and John Rex, Addison Wesley,
with modifications in Dr Dobbs Journal, April 1996}
var
G : longint;
i : integer;
begin
Result := 0;
for i := 1 to length(S) do begin
Result := (Result shl 4) + ord(S[i]);
G := Result and $F0000000;
if (G <> 0) then
Result := Result xor (G shr 24);
Result := Result and (not G);
end;
end;
{ TElfResCreator }
procedure TElfResCreator.AllocateData;
begin
FSectionStream:=TMemoryStream.Create;
FDataStream:=TMemoryStream.Create;
FSymStream:=TMemoryStream.Create;
FHashStream:=TMemoryStream.Create;
end;
procedure TElfResCreator.FreeData;
begin
FreeAndNil(FSectionStream);
FreeAndNil(FDataStream);
FreeAndNil(FSymStream);
FreeAndNil(FHashStream);
end;
constructor TElfResCreator.Create;
begin
FVersion:=fpcres2elf_version;
FOverwrite:=True;
FVerbose:=False;
FExtension:=SDefaultExtension;
end;
// fill the memorystream so it is aligned, max supported align is 16
procedure TElfResCreator.DoAlign(const a: integer);
var i: integer;
begin
i:=(4 - (FSectionStream.position MOD a)) MOD a;
if (i>0) then FSectionStream.Write(zeros,i);
end;
procedure TElfResCreator.Convert(const Source, Destination: String);
Var
Src,Dest : TFileStream;
begin
FSourceFileName:=Source;
FDestFileName:=Destination;
if FDestFileName='' then
FDestFileName:=ChangeFileExt(Source,FExtension);
Src:=TFileStream.Create(FSourceFileName,fmOpenRead or fmShareDenyWrite);
try
Dest:=TFileStream.Create(FDestFileName,fmCreate or fmShareDenyWrite);
Try
ConvertStreams(Src,Dest);
Finally
Dest.Free;
end;
Finally
Src.Free;
end;
end;
procedure TElfResCreator.ConvertStreams(Source, Dest: TStream);
begin
AllocateData;
Try
DoConvertStreams(Source,Dest);
Finally
FreeData;
end;
end;
{ ---------------------------------------------------------------------
TElf32ResCreator
---------------------------------------------------------------------}
procedure TElf32ResCreator.AllocateData;
begin
inherited AllocateData;
// reserve space for 1024 resource entries for now
SetLength(ResourceEntries,1024);
CurrentResource:=0;
end;
procedure TElf32ResCreator.FreeData;
begin
inherited FreeData;
SetLength(ResourceEntries,0);
end;
procedure TElf32ResCreator.LoadRESEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
var l:longint;
w:word;
ws:WideString;
wc:WideChar;
name:string;
i: integer;
headersize:integer;
headerstart:integer;
begin
headerstart:=rs.Position;
resinfo.ptr:=DataStream.Position;
rs.Read(resinfo.size,4);
rs.Read(headersize,4);
rs.Read(l,4); // Type
if (l AND $0000FFFF)=$0000FFFF then
begin // Type is stored as ID
resinfo.restype:=(l AND $FFFF0000) shr 16; // kill the marker, we always use IDs
end
else
begin
// we don't support text IDs for now, skip until we have reached the end
// of the widestring, and set rcdata (10) in this case.
repeat
rs.Read(w,2);
until w=0;
resinfo.restype:=10;
end;
rs.Read(l,4); // Name
if (l AND $0000FFFF)=$0000FFFF then
begin // Name is stored as ID.
l:=(l AND $FFFF0000) shr 16; // kill the marker
// We don't want to support integer names, we'll instead convert them to a #id string
// which is more common.
name:='#'+inttostr(l);
end
else
begin
// Ok, it's a widestring ID
ws:=widechar(l AND $0000FFFF);
ws:=ws+widechar((l AND $FFFF0000) shr 16);
// get the rest of it
repeat
rs.Read(wc,2);
if wc<>#0 then ws:=ws+wc;
until wc=#0;
// convert to ANSI
name:=ws;
end;
// create a hash of the name
resinfo.reshash:=HashELF(name);
// save the name plus a trailing #0 to the SymStream, also save
// the position of this name in the SymStream
resinfo.name:=SymStream.Position;
name:=name+#0;
SymStream.Write(name[1],length(name));
// We don't care about the rest of the header
rs.Seek(headersize-(rs.position-headerstart),soFromCurrent);
// Now copy over the resource data into our internal memory stream
DataStream.CopyFrom(rs,resinfo.size);
// Align the resource stream on a dword boundary
i:=(4 - (rs.Position MOD 4)) MOD 4;
if (i>0) then rs.Seek(i,soFromCurrent);
// Align the data stream on a dword boundary
i:=(4 - (DataStream.Position MOD 4)) MOD 4;
if (i>0) then DataStream.Write(zeros,i);
end;
procedure TElf32ResCreator.LoadBinaryDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
var name: string;
i: integer;
begin
resinfo.ptr:=0;
resinfo.restype:=10; // RCDATA
// Skip the header
rs.Position:=3;
// Read the name
setlength(name,64); // Component names can be 64 chars at max
rs.Read(name[1],64);
// Find end of name
i:=pos(#0,name);
name:=copy(name,1,i-1);
// Seek to after the name and skip other crap
rs.Position:=i+9;
resinfo.size:=rs.Size-rs.Position;
// ...this is followed by the data.
// create a hash of the name
resinfo.reshash:=HashELF(name);
// save the name plus a trailing #0 to the SymStream, also save
// the position of this name in the SymStream
resinfo.name:=SymStream.Position;
name:=name+#0;
SymStream.Write(name[1],length(name));
// Now copy over the resource data into our internal memory stream
DataStream.CopyFrom(rs,resinfo.size);
// Align the data stream on a dword boundary
i:=(4 - (DataStream.Position MOD 4)) MOD 4;
if (i>0) then DataStream.Write(zeros,i);
end;
procedure TElf32ResCreator.LoadTextDFMEntry(const rs:TStream; const DataStream:TMemoryStream; const SymStream:TMemoryStream; var resinfo:TELF32ResourceInfo);
var ms:TMemoryStream;
begin
ms:=nil;
try
ms:=TMemoryStream.Create;
ObjectTextToResource(rs,ms);
LoadBinaryDFMEntry(ms, DataStream, SymStream, resinfo);
finally
ms.free;
end;
end;
procedure TElf32ResCreator.DoConvertStreams(Source, Dest: TStream);
Var
I : Integer;
ElfHeader: TElf32Header;
SectionHeader: TElf32sechdr;
ressym: TELF32ResourceSectionInfo;
resstr: TELF32ResourceSectionInfo;
reshash: TELF32ResourceSectionInfo;
resdata: TELF32ResourceSectionInfo;
resspare: TELF32ResourceSectionInfo;
begin
// Read and check the header of the input file. First check if it's a 32bit resource
// file...
SetLength(resheader,32);
Source.Read(resheader[1],32);
if (resheader<>reshdr) then
begin
// ...not a 32Bit resource file. Now let's see if it's a text or binary dfm/xfm/lfm file.
Source.Position:=0;
Source.Read(Signature,1);
if (Signature=$FF) then
begin
Source.Position:=0;
LoadBinaryDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
end
else if char(Signature) in ['o','O','i','I',' ',#13,#11,#9] then
begin
Source.Position:=0;
LoadTextDFMEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
end
else
DoErrorFmt(SErrUnrecognizedFormat,[SourceFileName]);
inc(CurrentResource,1);
end
else // ...yes, it's a resource file.
while Source.Position<Source.Size do
begin
// Load Resource info, and copy the resource data into the DataStream
LoadRESEntry(Source, FDataStream, FSymStream, ResourceEntries[CurrentResource]);
inc(CurrentResource,1);
// if we hit the current limit of allocated ResourceEntries in the
// array, allocate some more space
if (CurrentResource>=length(ResourceEntries)) then
setlength(ResourceEntries,length(ResourceEntries)+1024);
end;
// downsize the ResourceEntries to the really needed size
SetLength(ResourceEntries,CurrentResource);
// Write the symbol table - ressym
ressym.ptr:=FSectionStream.Position+sizeof(TElf32Header);
FSymStream.Position:=0;
FSectionStream.CopyFrom(FSymStream,FSymStream.Size);
doalign(4);
// resstr
resstr.ptr:=FSectionStream.Position+sizeof(TElf32Header);
resstr.size:=0;
// TODO: Load string data here
doalign(4);
// Now write the ResourceInfos.
reshash.ptr:=FSectionStream.Position+sizeof(TElf32Header);
for i:=0 to high(ResourceEntries) do
begin
FSectionStream.Write(ResourceEntries[i],sizeof(TELF32ResourceInfo));
end;
doalign(4);
// Next write the resource data stream
resdata.ptr:=FSectionStream.Position+sizeof(TElf32Header);
FDataStream.Position:=0;
FSectionStream.CopyFrom(FDataStream,FDataStream.Size);
doalign(4);
// resspare
resspare.ptr:=FSectionStream.Position+sizeof(TElf32Header);
// don't write anything, this is an empty section
// shstrtab - this is not aligned
shstrtab_ofs:=FSectionStream.Position+sizeof(TElf32Header);
FSectionStream.Write(shstrtab,length(shstrtab));
// Write 12 section headers. The headers itself don't need to be aligned,
// as their size can be divided by 4. As shstrtab is uneven and not aligned,
// we however need to align the start of the section header table
doalign(4);
sectionheader_ofs:=FSectionStream.Position+sizeof(TElf32Header);;
// empty one
fillchar(SectionHeader,sizeof(SectionHeader),0);
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .text
SectionHeader.sh_name:=$1B;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=6; // AX
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
SectionHeader.sh_size:=0; // yep, pretty empty it is
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .data
SectionHeader.sh_name:=$21;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=3; // WA
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
SectionHeader.sh_size:=0; // yep, pretty empty it is
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .bss
SectionHeader.sh_name:=$27;
SectionHeader.sh_type:=8; // NOBITS
SectionHeader.sh_flags:=3; // WA
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=sizeof(TElf32Header); // after header, dummy as size is 0
SectionHeader.sh_size:=0; // yep, pretty empty it is
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// fpc.ressym
SectionHeader.sh_name:=$2C;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=2; // A
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=ressym.ptr; // directly after header
SectionHeader.sh_size:=FSymStream.Size;
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// fpc.resstr
SectionHeader.sh_name:=$37;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=2; // A
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=resstr.ptr;
SectionHeader.sh_size:=0; // currently empty
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// fpc.reshash
SectionHeader.sh_name:=$42;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=2; // A
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=reshash.ptr;
SectionHeader.sh_size:=length(ResourceEntries)*sizeof(TELF32ResourceInfo)+4;
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// fpc.resdata
SectionHeader.sh_name:=$4e;
SectionHeader.sh_type:=1; // PROGBITS
SectionHeader.sh_flags:=2; // A
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=resdata.ptr;
SectionHeader.sh_size:=FDataStream.Size;
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// fpc.resspare
// Not used in V1
SectionHeader.sh_name:=$5a;
SectionHeader.sh_type:=8; // NOBITS
SectionHeader.sh_flags:=2; // A
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=resspare.ptr; // fake, as it's empty, should be equal to shstrtab's offset
SectionHeader.sh_size:=0; //DataStream.Size; // Leave as much room as we currently have in resdata section
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .shstrtab
SectionHeader.sh_name:=$11;
SectionHeader.sh_type:=3; // STRTAB
SectionHeader.sh_flags:=0;
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=shstrtab_ofs; // $3E
SectionHeader.sh_size:=$67;
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=1; // alignment
SectionHeader.sh_entsize:=0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .symtab
SectionHeader.sh_name:=$01;
SectionHeader.sh_type:=2; // SYMTAB
SectionHeader.sh_flags:=0;
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=FSectionStream.Position+sizeof(TElf32Header)+sizeOf(SectionHeader)+sizeOf(SectionHeader); // will come directly after this and the next section. $0288;
SectionHeader.sh_size:=$90;
SectionHeader.sh_link:=$0B;
SectionHeader.sh_info:=$09;
SectionHeader.sh_addralign:=4; // alignment
SectionHeader.sh_entsize:=$10;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// .strtab
SectionHeader.sh_name:=$09;
SectionHeader.sh_type:=3; // STRTAB
SectionHeader.sh_flags:=0;
SectionHeader.sh_addr:=0;
SectionHeader.sh_offset:=FSectionStream.Position+sizeof(TElf32Header)+sizeOf(SectionHeader)+$90; // will come after this sectionheader and the $90 bytes symtab - $0318; end of file
SectionHeader.sh_size:=1;
SectionHeader.sh_link:=0;
SectionHeader.sh_info:=0;
SectionHeader.sh_addralign:=1; // alignment
SectionHeader.sh_entsize:=$0;
FSectionStream.Write(SectionHeader,sizeOf(SectionHeader));
// now write the symbol table
FSectionStream.Write(symtab,length(symtab));
// We don't need to align it, as it's $90 in size
// now write the string table, it's just a single byte
FSectionStream.Write(strtab,1);
// Ok, we are done, now let's really write something to disk...
// First write the ELF header
fillchar(ElfHeader,sizeof(ElfHeader),0);
ElfHeader.magic0123:=$464c457f; { = #127'ELF' }
ElfHeader.file_class:=1;
ElfHeader.data_encoding:=1;
ElfHeader.file_version:=1;
ElfHeader.e_type:=1;
ElfHeader.e_machine:=3;
ElfHeader.e_version:=1;
ElfHeader.e_shoff:=sectionheader_ofs;
ElfHeader.e_shstrndx:=9;
ElfHeader.e_shnum:=12;
ElfHeader.e_ehsize:=sizeof(TElf32header);
ElfHeader.e_shentsize:=sizeof(TElf32sechdr);
Dest.Write(ElfHeader,sizeof(TElf32header));
// And now let's dump our whole memorystream into it.
Dest.CopyFrom(FSectionStream,0);
end;
{ TElf64Creator }
procedure TElf64ResCreator.DoConvertStreams(Source, Dest: TStream);
begin
DoError('64 bits resources not yet supported')
end;
end.

260
utils/fpcres/elfresfix.pas Normal file
View File

@ -0,0 +1,260 @@
{ *********************************************************************** }
{ }
{ elfresfix - Free Pascal Resource to ELF object compiler - fixup tool }
{ Part of the Free Pascal and CrossFPC distributions }
{ }
{ Copyright (C) 2005 Simon Kissel }
{ }
{ See the file COPYING.FPC, included in the FPC distribution, }
{ for details about the copyright. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ *********************************************************************** }
{
This tool will update the fpc.resptrs section of an ELF executable to point
to the various resource sections in the file. This is done so that the FPC
RTL at runtime is able to get pointers to these sections.
This tool is automatically run on any fpc compiled ELF executable that
contains ELF resources.
fpcresfix builds with Delphi, Kylix and FPC.
Currently this only works on 32Bit targets, but support for 64Bit targets
is in the works. Support for big endian systems is completely missing,
though.
}
{$ifdef fpc}
{$mode objfpc}
{$endif}
{$h+}
unit elfresfix;
interface
uses
SysUtils, Classes, elfbfd;
Type
TLogEvent = Procedure(Const Msg : String) of object;
{ TElfResourceFixer }
TElfResourceFixer = Class(TObject)
private
FFileName: String;
FOnVerbose: TLogEvent;
FVerbose: Boolean;
Procedure DoVerbose(Msg : String);
public
Procedure FixFile(AFileName : String);
Procedure DoFixStream(Stream : TStream); virtual; abstract;
Property Verbose : Boolean read FVerbose write FVerbose;
Property FileName : String Read FFileName;
Property Onverbose : TLogEvent Read FOnVerbose Write FOnVerbose;
end;
{ TElf32ResourceFixer }
TElf32ResourceFixer = Class(TElfResourceFixer)
Procedure DoFixStream(Stream : TStream); override;
end;
{ TElf64ResourceFixer }
TElf64ResourceFixer = Class(TElfResourceFixer)
Procedure DoFixStream(Stream : TStream); override;
end;
EElfResFixError = Class(Exception);
Implementation
ResourceString
SCheckingHeader = 'Checking ELF Header... ';
SReadingSectionHeaders = 'Reading Section Headers...';
SHeaderOK = 'ELF Header is OK';
SCheckingHeaderTable = 'Checking Section Header table...';
SStrTabFound = 'Found strtab...';
SProcessingSection = 'Processing section: ';
SUpdatingResptrs = 'Updating resptrs section...';
SFileFixed = 'File fixed successfully!';
SNothingToFix = 'There was nothing to fix in this file.';
SErrUnsupportedHeaderSize = 'Unsupported Section Header size.';
SErrInvalidELFHeader = 'Not a valid linux ELF binary.';
SErrResPtrsNotFound = 'Unable to find resptrs section.';
Procedure DoError (Msg : String);
begin
Raise EElfResFixError.Create(Msg);
end;
Procedure DoErrorFmt (Msg : String; Args : Array of const);
begin
Raise EElfResFixError.CreateFmt(Msg,Args);
end;
{ TElfResourceFixer }
procedure TElfResourceFixer.DoVerbose(Msg: String);
begin
If FVerbose and Assigned(FOnVerbose) then
FOnVerbose(Msg);
end;
procedure TElfResourceFixer.FixFile(AFileName: String);
Var
F : TStream;
begin
FFileName:=AFileName;
F:=TFileStream.Create(AFilename,fmOpenReadWrite or fmShareDenyWrite);
Try
DoFixStream(F);
Finally
F.Free;
end;
end;
{ TElf32ResourceFixer }
procedure TElf32ResourceFixer.DoFixStream(Stream: TStream);
var
ElfHeader:TElf32header;
ResourceSectionTable: TElf32ResourceSectionTable;
SectionHeaders: array of TElf32sechdr;
i:integer;
sn:string;
SectionHeaderOffset:integer;
fixed: boolean;
strtab:string;
SectionName: string;
ResPtrsSection: integer;
begin
Fixed:=False;
Stream.Read(ElfHeader,sizeof(TElf32header));
DoVerbose(SCheckingHeader);
if (ElfHeader.magic0123<>$464C457F) then
DoError(SErrInvalidELFheader);
if ElfHeader.e_shentsize=sizeof(TElf32sechdr) then
DoVerbose(SHeaderOK)
else
DoError(SErrUnSupportedHeaderSize);
DoVerbose(SReadingSectionHeaders);
setlength(SectionHeaders,ElfHeader.e_shnum);
SectionHeaderOffset:=ElfHeader.e_shoff;
Stream.Position:=SectionHeaderOffset;
for i:=0 to ElfHeader.e_shnum-1 do
begin
Stream.Read(SectionHeaders[i],sizeof(TElf32sechdr));
end;
DoVerbose(SCheckingHeaderTable);
// Get the section header strtab
i:=ElfHeader.e_shstrndx;
if SectionHeaders[i].sh_type=SHT_STRTAB then
begin
DoVerbose(SStrTabFound);
// read the strtab
Stream.Position:=SectionHeaders[i].sh_offset;
setlength(strtab,SectionHeaders[i].sh_size);
Stream.Read(strtab[1],SectionHeaders[i].sh_size);
end
else
begin
writeln('Error: Unable to find strtab.');
halt(5);
end;
ResPtrsSection:=-1;
ResourceSectionTable.version:=66;
// Next cycle through all sections to gather pointers to all the resource
// sections, and note the index of the resptrs section
for i:=0 to ElfHeader.e_shnum-1 do
begin
SectionName:=copy(strtab,SectionHeaders[i].sh_name+1,32);
SectionName:=copy(SectionName,1,pos(#0,SectionName)-1);
DoVerbose(SProcessingSection+SectionName);
sn:=Copy(SectionName,1,4);
// FPC section ?
if (sn='fpc.') then
begin
sn:=SectionName;
Delete(SN,1,4);
if SN='resptrs' then
begin
ResPtrsSection:=i;
end
else if sn='ressym' then
begin
ResourceSectionTable.ressym.ptr:=SectionHeaders[i].sh_addr;
ResourceSectionTable.ressym.size:=SectionHeaders[i].sh_size;
end
else if sn='reshash' then
begin
ResourceSectionTable.reshash.ptr:=SectionHeaders[i].sh_addr;
ResourceSectionTable.reshash.size:=SectionHeaders[i].sh_size;
ResourceSectionTable.resentries:=SectionHeaders[i].sh_size DIV sizeof(TELF32ResourceInfo);
end
else if sn='resdata' then
begin
ResourceSectionTable.resdata.ptr:=SectionHeaders[i].sh_addr;
ResourceSectionTable.resdata.size:=SectionHeaders[i].sh_size;
end
else if sn='resspare' then
begin
ResourceSectionTable.resspare.ptr:=SectionHeaders[i].sh_addr;
ResourceSectionTable.resspare.size:=SectionHeaders[i].sh_size;
end
else if SectionName='resstr' then
begin
ResourceSectionTable.resstr.ptr:=SectionHeaders[i].sh_addr;
ResourceSectionTable.resstr.size:=SectionHeaders[i].sh_size;
end;
end
end;
// Ok, we now have pointers to all resource sections and also
// know the number of resources.
// Now update the resptrs table
if ResPtrsSection>-1 then
begin
Doverbose(SUpdatingResPtrs);
Stream.Position:=SectionHeaders[ResPtrsSection].sh_offset;
Stream.Write(ResourceSectionTable,sizeof(TELF32ResourceSectionTable));
fixed:=true;
end
else
DoError(SErrREsptrsNotFound);
if fixed then
DoVerbose(SFileFixed)
else
writeln(SNothingToFix);
end;
{ TElf64ResourceFixer }
procedure TElf64ResourceFixer.DoFixStream(Stream: TStream);
begin
DoError('64-bit resources not yet supported');
end;
end.

171
utils/fpcres/fpcres.lpi Normal file
View File

@ -0,0 +1,171 @@
<?xml version="1.0"?>
<CONFIG>
<ProjectOptions>
<PathDelim Value="/"/>
<Version Value="5"/>
<General>
<Flags>
<MainUnitHasUsesSectionForAllUnits Value="False"/>
<MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/>
</Flags>
<MainUnit Value="0"/>
<ActiveEditorIndexAtStart Value="0"/>
<IconPath Value="./"/>
<TargetFileExt Value=""/>
</General>
<JumpHistory Count="18" HistoryIndex="17">
<Position1>
<Filename Value="fpcres.pas"/>
<Caret Line="175" Column="14" TopLine="138"/>
</Position1>
<Position2>
<Filename Value="fpcres.pas"/>
<Caret Line="144" Column="11" TopLine="122"/>
</Position2>
<Position3>
<Filename Value="fpcres.pas"/>
<Caret Line="143" Column="5" TopLine="122"/>
</Position3>
<Position4>
<Filename Value="fpcres.pas"/>
<Caret Line="148" Column="29" TopLine="126"/>
</Position4>
<Position5>
<Filename Value="fpcres.pas"/>
<Caret Line="152" Column="5" TopLine="130"/>
</Position5>
<Position6>
<Filename Value="fpcres.pas"/>
<Caret Line="162" Column="8" TopLine="140"/>
</Position6>
<Position7>
<Filename Value="fpcres.pas"/>
<Caret Line="162" Column="8" TopLine="140"/>
</Position7>
<Position8>
<Filename Value="fpcres.pas"/>
<Caret Line="163" Column="3" TopLine="141"/>
</Position8>
<Position9>
<Filename Value="fpcres.pas"/>
<Caret Line="162" Column="34" TopLine="141"/>
</Position9>
<Position10>
<Filename Value="fpcres.pas"/>
<Caret Line="170" Column="25" TopLine="148"/>
</Position10>
<Position11>
<Filename Value="fpcres.pas"/>
<Caret Line="170" Column="25" TopLine="148"/>
</Position11>
<Position12>
<Filename Value="fpcres.pas"/>
<Caret Line="170" Column="25" TopLine="148"/>
</Position12>
<Position13>
<Filename Value="fpcres.pas"/>
<Caret Line="148" Column="17" TopLine="148"/>
</Position13>
<Position14>
<Filename Value="fpcres.pas"/>
<Caret Line="67" Column="16" TopLine="67"/>
</Position14>
<Position15>
<Filename Value="fpcres.pas"/>
<Caret Line="70" Column="1" TopLine="28"/>
</Position15>
<Position16>
<Filename Value="fpcres.pas"/>
<Caret Line="233" Column="27" TopLine="190"/>
</Position16>
<Position17>
<Filename Value="fpcres.pas"/>
<Caret Line="143" Column="5" TopLine="121"/>
</Position17>
<Position18>
<Filename Value="fpcres.pas"/>
<Caret Line="137" Column="1" TopLine="137"/>
</Position18>
</JumpHistory>
<Units Count="5">
<Unit0>
<CursorPos X="18" Y="4"/>
<EditorIndex Value="0"/>
<Filename Value="fpcres.pas"/>
<IsPartOfProject Value="True"/>
<Loaded Value="True"/>
<TopLine Value="1"/>
<UnitName Value="fpcres"/>
<UsageCount Value="32"/>
</Unit0>
<Unit1>
<CursorPos X="1" Y="235"/>
<EditorIndex Value="1"/>
<Filename Value="elfres.pas"/>
<IsPartOfProject Value="True"/>
<Loaded Value="True"/>
<TopLine Value="206"/>
<UnitName Value="elfres"/>
<UsageCount Value="32"/>
</Unit1>
<Unit2>
<CursorPos X="1" Y="1"/>
<Filename Value="/home/michael/cmdline.pp"/>
<TopLine Value="1"/>
<UsageCount Value="10"/>
</Unit2>
<Unit3>
<CursorPos X="1" Y="1"/>
<EditorIndex Value="3"/>
<Filename Value="elfbfd.pas"/>
<IsPartOfProject Value="True"/>
<Loaded Value="True"/>
<TopLine Value="1"/>
<UnitName Value="elfbfd"/>
<UsageCount Value="25"/>
</Unit3>
<Unit4>
<CursorPos X="1" Y="121"/>
<EditorIndex Value="2"/>
<Filename Value="elfresfix.pas"/>
<IsPartOfProject Value="True"/>
<Loaded Value="True"/>
<TopLine Value="109"/>
<UnitName Value="elfresfix"/>
<UsageCount Value="25"/>
</Unit4>
</Units>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<local>
<FormatVersion Value="1"/>
<LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
</local>
</RunParams>
</ProjectOptions>
<CompilerOptions>
<Version Value="5"/>
<CodeGeneration>
<Generate Value="Faster"/>
</CodeGeneration>
<Other>
<CompilerPath Value="$(CompPath)"/>
</Other>
</CompilerOptions>
<Debugging>
<Exceptions Count="2">
<Item1>
<Name Value="ECodetoolError"/>
</Item1>
<Item2>
<Name Value="EFOpenError"/>
</Item2>
</Exceptions>
</Debugging>
</CONFIG>

277
utils/fpcres/fpcres.pas Normal file
View File

@ -0,0 +1,277 @@
{$ifdef fpc}
{$mode objfpc}
{$endif}
{$apptype console}
{$H+}
program fpcres;
uses
Classes, SysUtils, elfres, elfresfix;
resourcestring
SError = 'Error:';
SErrUnknownParam = 'Unknown command-line parameter : %s';
SErrNeedArgument = 'Option at pos %d (%s) needs an argument.';
SErrNoInputFile = 'No input filename was specified';
SErrNoOutputFile = 'Outputfile is not allowed when multiple input files are given';
SErrOutputFileIllegal = 'Outputfile not allowed when fixing headers.';
SUsage010 = 'fpcres - Free Pascal Resource to ELF object compiler';
SUsage020 = 'Part of the Free Pascal and CrossFPC distributions';
SUsage030 = 'Copyright (C) 2005 Simon Kissel';
SUsage040 = '--------------------------------------------------------';
SUsage050 = 'Usage: fpcres [options] -i inputfile [-i inputfile] [-o outputfile]';
SUsage055 = ' where options are one or more of:';
SUsage060 = ' -i --input=inputfile';
SUsage065 = ' A file in windows .res resource format, ';
SUsage070 = ' or a Delphi/Kylix form file in dfm/xfm ';
SUsage080 = ' format (binary or text).';
SUSage085 = ' More than one inputfile may be specified.';
SUsage090 = ' -o --output=outputfile';
SUsage095 = ' Name of the object file to generate. If ';
SUsage100 = ' omitted, the name of the input file will';
SUsage110 = ' be used, with .or as extension.';
SUSage115 = ' (not allowed with multiple input files.)';
SUsage116 = ' -e --extension=ext';
SUsage117 = ' use ext as the extension for output filenames';
SUsage120 = ' -h --help show this help message.';
SUsage130 = ' -f --fixheader fix resource block header.';
SUsage140 = ' -6 --64bit Use 64-bit elf resources.';
SUsage150 = ' -v --verbose be verbose.';
Type
TRunMode = (rmCreateElfRes,rmFixHeader);
Var
RunMode : TRunMode;
InputFiles : TStringList;
OutputFileName : String;
Use64bit : Boolean;
BeVerbose : Boolean;
UseExt : String;
Procedure Usage(ExitStatus : Word);
begin
Writeln(SUsage010);
Writeln(SUsage020);
Writeln(SUsage030);
Writeln(SUsage040);
Writeln(SUsage050);
Writeln(SUsage055);
Writeln(SUsage060);
Writeln(SUsage065);
Writeln(SUsage070);
Writeln(SUsage080);
Writeln(SUSage085);
Writeln(SUsage090);
Writeln(SUsage095);
Writeln(SUsage100);
Writeln(SUsage110);
Writeln(SUSage115);
Writeln(SUSage116);
Writeln(SUSage117);
Writeln(SUsage120);
Writeln(SUsage130);
Writeln(SUsage140);
Writeln(SUsage150);
Halt(ExitStatus);
end;
Procedure DoError(Msg : String; Args : Array of const);
begin
Writeln(SError,' ',Format(Msg,Args));
Usage(1);
end;
Procedure AnalyzeParams;
Function CheckOption(Index : Integer;Short,Long : String): Boolean;
var
O : String;
begin
O:=Paramstr(Index);
Result:=(O='-'+short) or (copy(O,1,Length(Long)+3)=('--'+long+'='));
end;
Function OptionArg(Var Index : Integer) : String;
Var
P : Integer;
begin
if (Length(ParamStr(Index))>1) and (Paramstr(Index)[2]<>'-') then
begin
If Index<ParamCount then
begin
Inc(Index);
Result:=Paramstr(Index);
end
else
DoError(SErrNeedArgument,[Index,ParamStr(Index)]);
end
else If length(ParamStr(Index))>2 then
begin
P:=Pos('=',Paramstr(Index));
If (P=0) then
DoError(SErrNeedArgument,[Index,ParamStr(Index)])
else
begin
Result:=Paramstr(Index);
Delete(Result,1,P);
end;
end;
end;
Var
I : Integer;
P : String;
begin
RunMode:=rmCreateElfres;
Use64bit:=False;
BeVerbose:=False;
I:=0;
While (I<ParamCount) do
begin
Inc(I);
// Values.
If Checkoption(I,'o','output') then
OutPutFileName:=OptionArg(I)
else if Checkoption(I,'i','input') then
InputFiles.Add(OptionArg(I))
else If Checkoption(I,'e','extension') then
UseExt:=OptionArg(I)
else if CheckOption(I,'f','fixheader') then
RunMode:=rmFixHeader
else if CheckOption(I,'6','64bit') then
Use64bit:=True
else if CheckOption(I,'h','help') then
Usage(0)
else if CheckOption(I,'v','verbose') then
BeVerbose:=True
else
begin
P:=ParamStr(I);
if (Length(P)>0) and (P[1]<>'-') then
begin
if (I=ParamCount) then
OutputFileName:=P
else
InputFiles.Add(P)
end
else
begin
DoError(SErrUnknownParam,[P]);
Usage(1);
end;
end;
end;
If (InputFiles.Count=0) then
DoError(SErrNoInputFile,[]);
If (InputFiles.Count>1) and (OutputFileName<>'') then
DoError(SErrNoOutputFile,[]);
If (RunMode=rmFixHeader) and (OutputFileName<>'') then
DoError(SErrOutputFileIllegal,[])
end;
Type
TLogger = Class(TObject)
Procedure Log(Const Msg : String);
end;
Procedure TLogger.Log(Const Msg : string);
begin
Writeln(Msg);
end;
Procedure FixHeader(AFileName : String);
Var
F : TElfResourceFixer;
O : TLogger;
begin
if Use64bit then
F:=TElf64ResourceFixer.Create
else
F:=TElf32ResourceFixer.Create;
try
F.Verbose:=BeVerbose;
if BeVerbose then
begin
O:=TLogger.Create;
F.OnVerbose:={$ifdef fpc}@{$endif}O.Log;
end
else
O:=Nil;
Try
F.FixFile(AFileName);
Finally
O.Free;
end;
Finally
F.Free;
end;
end;
Procedure CreateRes(AFileName : String);
Var
C : TElfResCreator;
begin
If Use64Bit then
C:=TElf64ResCreator.Create
else
C:=TElf32ResCreator.Create;
With C do
Try
Verbose:=BeVerbose;
If (UseExt<>'') then
Extension:=UseExt;
Convert(AFileName,OutputFileName);
Finally
Free;
end;
end;
Procedure Run;
Var
I : Integer;
begin
Try
Case RunMode of
rmFixHeader:
For I:=0 to InputFiles.Count-1 do
FixHeader(InputFiles[i]);
rmCreateElfRes:
For I:=0 to InputFiles.Count-1 do
CreateRes(InputFiles[i]);
end;
except
On E : Exception do
begin
Writeln(SError,' ',E.Message);
Halt(1);
end;
end;
end;
begin
InputFiles:=TStringList.Create;
Try
AnalyzeParams;
Run;
Finally
FreeAndNil(InputFiles);
end;
end.