1 # Capstone Disassembly Engine 2 # By Nguyen Anh Quynh <aquynh (at] gmail.com>, 2013-2014 3 4 include config.mk 5 include pkgconfig.mk # package version 6 include functions.mk 7 8 # Verbose output? 9 V ?= 0 10 11 ifeq ($(PKG_EXTRA),) 12 PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR) 13 else 14 PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA) 15 endif 16 17 ifeq ($(CROSS),) 18 CC ?= cc 19 AR ?= ar 20 RANLIB ?= ranlib 21 STRIP ?= strip 22 else 23 CC = $(CROSS)gcc 24 AR = $(CROSS)ar 25 RANLIB = $(CROSS)ranlib 26 STRIP = $(CROSS)strip 27 endif 28 29 ifneq (,$(findstring yes,$(CAPSTONE_DIET))) 30 CFLAGS ?= -Os 31 CFLAGS += -DCAPSTONE_DIET 32 else 33 CFLAGS ?= -O3 34 endif 35 36 ifneq (,$(findstring yes,$(CAPSTONE_X86_ATT_DISABLE))) 37 CFLAGS += -DCAPSTONE_X86_ATT_DISABLE 38 endif 39 40 CFLAGS += -fPIC -Wall -Iinclude 41 42 ifeq ($(CAPSTONE_USE_SYS_DYN_MEM),yes) 43 CFLAGS += -DCAPSTONE_USE_SYS_DYN_MEM 44 endif 45 46 ifeq ($(CAPSTONE_HAS_OSXKERNEL), yes) 47 CFLAGS += -DCAPSTONE_HAS_OSXKERNEL 48 SDKROOT ?= $(shell xcodebuild -version -sdk macosx Path) 49 CFLAGS += -mmacosx-version-min=10.5 \ 50 -isysroot$(SDKROOT) \ 51 -I$(SDKROOT)/System/Library/Frameworks/Kernel.framework/Headers \ 52 -mkernel \ 53 -fno-builtin 54 endif 55 56 CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) 57 LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) 58 59 PREFIX ?= /usr 60 DESTDIR ?= 61 ifndef BUILDDIR 62 BLDIR = . 63 OBJDIR = . 64 else 65 BLDIR = $(abspath $(BUILDDIR)) 66 OBJDIR = $(BLDIR)/obj 67 endif 68 INCDIR = $(DESTDIR)$(PREFIX)/include 69 70 UNAME_S := $(shell uname -s) 71 72 LIBDIRARCH ?= lib 73 # Uncomment the below line to installs x86_64 libs to lib64/ directory. 74 # Or better, pass 'LIBDIRARCH=lib64' to 'make install/uninstall' via 'make.sh'. 75 #LIBDIRARCH ?= lib64 76 LIBDIR = $(DESTDIR)$(PREFIX)/$(LIBDIRARCH) 77 BINDIR = $(DESTDIR)$(PREFIX)/bin 78 79 LIBDATADIR = $(LIBDIR) 80 81 # Don't redefine $LIBDATADIR when global environment variable 82 # USE_GENERIC_LIBDATADIR is set. This is used by the pkgsrc framework. 83 84 ifndef USE_GENERIC_LIBDATADIR 85 ifeq ($(UNAME_S), FreeBSD) 86 LIBDATADIR = $(DESTDIR)$(PREFIX)/libdata 87 endif 88 ifeq ($(UNAME_S), DragonFly) 89 LIBDATADIR = $(DESTDIR)$(PREFIX)/libdata 90 endif 91 endif 92 93 INSTALL_BIN ?= install 94 INSTALL_DATA ?= $(INSTALL_BIN) -m0644 95 INSTALL_LIB ?= $(INSTALL_BIN) -m0755 96 97 LIBNAME = capstone 98 99 100 DEP_ARM = 101 DEP_ARM += arch/ARM/ARMGenAsmWriter.inc 102 DEP_ARM += arch/ARM/ARMGenDisassemblerTables.inc 103 DEP_ARM += arch/ARM/ARMGenInstrInfo.inc 104 DEP_ARM += arch/ARM/ARMGenRegisterInfo.inc 105 DEP_ARM += arch/ARM/ARMGenSubtargetInfo.inc 106 107 LIBOBJ_ARM = 108 ifneq (,$(findstring arm,$(CAPSTONE_ARCHS))) 109 CFLAGS += -DCAPSTONE_HAS_ARM 110 LIBOBJ_ARM += $(OBJDIR)/arch/ARM/ARMDisassembler.o 111 LIBOBJ_ARM += $(OBJDIR)/arch/ARM/ARMInstPrinter.o 112 LIBOBJ_ARM += $(OBJDIR)/arch/ARM/ARMMapping.o 113 LIBOBJ_ARM += $(OBJDIR)/arch/ARM/ARMModule.o 114 endif 115 116 DEP_ARM64 = 117 DEP_ARM64 += arch/AArch64/AArch64GenAsmWriter.inc 118 DEP_ARM64 += arch/AArch64/AArch64GenInstrInfo.inc 119 DEP_ARM64 += arch/AArch64/AArch64GenSubtargetInfo.inc 120 DEP_ARM64 += arch/AArch64/AArch64GenDisassemblerTables.inc 121 DEP_ARM64 += arch/AArch64/AArch64GenRegisterInfo.inc 122 123 LIBOBJ_ARM64 = 124 ifneq (,$(findstring aarch64,$(CAPSTONE_ARCHS))) 125 CFLAGS += -DCAPSTONE_HAS_ARM64 126 LIBOBJ_ARM64 += $(OBJDIR)/arch/AArch64/AArch64BaseInfo.o 127 LIBOBJ_ARM64 += $(OBJDIR)/arch/AArch64/AArch64Disassembler.o 128 LIBOBJ_ARM64 += $(OBJDIR)/arch/AArch64/AArch64InstPrinter.o 129 LIBOBJ_ARM64 += $(OBJDIR)/arch/AArch64/AArch64Mapping.o 130 LIBOBJ_ARM64 += $(OBJDIR)/arch/AArch64/AArch64Module.o 131 endif 132 133 134 DEP_MIPS = 135 DEP_MIPS += arch/Mips/MipsGenAsmWriter.inc 136 DEP_MIPS += arch/Mips/MipsGenDisassemblerTables.inc 137 DEP_MIPS += arch/Mips/MipsGenInstrInfo.inc 138 DEP_MIPS += arch/Mips/MipsGenRegisterInfo.inc 139 DEP_MIPS += arch/Mips/MipsGenSubtargetInfo.inc 140 141 LIBOBJ_MIPS = 142 ifneq (,$(findstring mips,$(CAPSTONE_ARCHS))) 143 CFLAGS += -DCAPSTONE_HAS_MIPS 144 LIBOBJ_MIPS += $(OBJDIR)/arch/Mips/MipsDisassembler.o 145 LIBOBJ_MIPS += $(OBJDIR)/arch/Mips/MipsInstPrinter.o 146 LIBOBJ_MIPS += $(OBJDIR)/arch/Mips/MipsMapping.o 147 LIBOBJ_MIPS += $(OBJDIR)/arch/Mips/MipsModule.o 148 endif 149 150 151 DEP_PPC = 152 DEP_PPC += arch/PowerPC/PPCGenAsmWriter.inc 153 DEP_PPC += arch/PowerPC/PPCGenInstrInfo.inc 154 DEP_PPC += arch/PowerPC/PPCGenSubtargetInfo.inc 155 DEP_PPC += arch/PowerPC/PPCGenDisassemblerTables.inc 156 DEP_PPC += arch/PowerPC/PPCGenRegisterInfo.inc 157 158 LIBOBJ_PPC = 159 ifneq (,$(findstring powerpc,$(CAPSTONE_ARCHS))) 160 CFLAGS += -DCAPSTONE_HAS_POWERPC 161 LIBOBJ_PPC += $(OBJDIR)/arch/PowerPC/PPCDisassembler.o 162 LIBOBJ_PPC += $(OBJDIR)/arch/PowerPC/PPCInstPrinter.o 163 LIBOBJ_PPC += $(OBJDIR)/arch/PowerPC/PPCMapping.o 164 LIBOBJ_PPC += $(OBJDIR)/arch/PowerPC/PPCModule.o 165 endif 166 167 168 DEP_SPARC = 169 DEP_SPARC += arch/Sparc/SparcGenAsmWriter.inc 170 DEP_SPARC += arch/Sparc/SparcGenInstrInfo.inc 171 DEP_SPARC += arch/Sparc/SparcGenSubtargetInfo.inc 172 DEP_SPARC += arch/Sparc/SparcGenDisassemblerTables.inc 173 DEP_SPARC += arch/Sparc/SparcGenRegisterInfo.inc 174 175 LIBOBJ_SPARC = 176 ifneq (,$(findstring sparc,$(CAPSTONE_ARCHS))) 177 CFLAGS += -DCAPSTONE_HAS_SPARC 178 LIBOBJ_SPARC += $(OBJDIR)/arch/Sparc/SparcDisassembler.o 179 LIBOBJ_SPARC += $(OBJDIR)/arch/Sparc/SparcInstPrinter.o 180 LIBOBJ_SPARC += $(OBJDIR)/arch/Sparc/SparcMapping.o 181 LIBOBJ_SPARC += $(OBJDIR)/arch/Sparc/SparcModule.o 182 endif 183 184 185 DEP_SYSZ = 186 DEP_SYSZ += arch/SystemZ/SystemZGenAsmWriter.inc 187 DEP_SYSZ += arch/SystemZ/SystemZGenInstrInfo.inc 188 DEP_SYSZ += arch/SystemZ/SystemZGenSubtargetInfo.inc 189 DEP_SYSZ += arch/SystemZ/SystemZGenDisassemblerTables.inc 190 DEP_SYSZ += arch/SystemZ/SystemZGenRegisterInfo.inc 191 192 LIBOBJ_SYSZ = 193 ifneq (,$(findstring systemz,$(CAPSTONE_ARCHS))) 194 CFLAGS += -DCAPSTONE_HAS_SYSZ 195 LIBOBJ_SYSZ += $(OBJDIR)/arch/SystemZ/SystemZDisassembler.o 196 LIBOBJ_SYSZ += $(OBJDIR)/arch/SystemZ/SystemZInstPrinter.o 197 LIBOBJ_SYSZ += $(OBJDIR)/arch/SystemZ/SystemZMapping.o 198 LIBOBJ_SYSZ += $(OBJDIR)/arch/SystemZ/SystemZModule.o 199 LIBOBJ_SYSZ += $(OBJDIR)/arch/SystemZ/SystemZMCTargetDesc.o 200 endif 201 202 203 # by default, we compile full X86 instruction sets 204 X86_REDUCE = 205 ifneq (,$(findstring yes,$(CAPSTONE_X86_REDUCE))) 206 X86_REDUCE = _reduce 207 CFLAGS += -DCAPSTONE_X86_REDUCE -Os 208 endif 209 210 DEP_X86 = 211 DEP_X86 += arch/X86/X86GenAsmWriter$(X86_REDUCE).inc 212 DEP_X86 += arch/X86/X86GenAsmWriter1$(X86_REDUCE).inc 213 DEP_X86 += arch/X86/X86GenDisassemblerTables$(X86_REDUCE).inc 214 DEP_X86 += arch/X86/X86GenInstrInfo$(X86_REDUCE).inc 215 DEP_X86 += arch/X86/X86GenRegisterInfo.inc 216 217 LIBOBJ_X86 = 218 ifneq (,$(findstring x86,$(CAPSTONE_ARCHS))) 219 CFLAGS += -DCAPSTONE_HAS_X86 220 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86DisassemblerDecoder.o 221 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86Disassembler.o 222 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86IntelInstPrinter.o 223 # assembly syntax is irrelevant in Diet mode, when this info is suppressed 224 ifeq (,$(findstring yes,$(CAPSTONE_DIET))) 225 ifeq (,$(findstring yes,$(CAPSTONE_X86_ATT_DISABLE))) 226 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86ATTInstPrinter.o 227 endif 228 endif 229 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86Mapping.o 230 LIBOBJ_X86 += $(OBJDIR)/arch/X86/X86Module.o 231 endif 232 233 234 DEP_XCORE = 235 DEP_XCORE += arch/XCore/XCoreGenAsmWriter.inc 236 DEP_XCORE += arch/XCore/XCoreGenInstrInfo.inc 237 DEP_XCORE += arch/XCore/XCoreGenDisassemblerTables.inc 238 DEP_XCORE += arch/XCore/XCoreGenRegisterInfo.inc 239 240 LIBOBJ_XCORE = 241 ifneq (,$(findstring xcore,$(CAPSTONE_ARCHS))) 242 CFLAGS += -DCAPSTONE_HAS_XCORE 243 LIBOBJ_XCORE += $(OBJDIR)/arch/XCore/XCoreDisassembler.o 244 LIBOBJ_XCORE += $(OBJDIR)/arch/XCore/XCoreInstPrinter.o 245 LIBOBJ_XCORE += $(OBJDIR)/arch/XCore/XCoreMapping.o 246 LIBOBJ_XCORE += $(OBJDIR)/arch/XCore/XCoreModule.o 247 endif 248 249 250 LIBOBJ = 251 LIBOBJ += $(OBJDIR)/cs.o $(OBJDIR)/utils.o $(OBJDIR)/SStream.o $(OBJDIR)/MCInstrDesc.o $(OBJDIR)/MCRegisterInfo.o 252 LIBOBJ += $(LIBOBJ_ARM) $(LIBOBJ_ARM64) $(LIBOBJ_MIPS) $(LIBOBJ_PPC) $(LIBOBJ_SPARC) $(LIBOBJ_SYSZ) $(LIBOBJ_X86) $(LIBOBJ_XCORE) 253 LIBOBJ += $(OBJDIR)/MCInst.o 254 255 256 PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig 257 API_MAJOR=$(shell echo `grep -e CS_API_MAJOR include/capstone.h | grep -v = | awk '{print $$3}'` | awk '{print $$1}') 258 VERSION_EXT = 259 260 IS_APPLE := $(shell $(CC) -dM -E - < /dev/null | grep -cm 1 -e __apple_build_version__ -e __APPLE_CC__) 261 ifeq ($(IS_APPLE),1) 262 EXT = dylib 263 VERSION_EXT = $(API_MAJOR).$(EXT) 264 $(LIBNAME)_LDFLAGS += -dynamiclib -install_name lib$(LIBNAME).$(VERSION_EXT) -current_version $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA) -compatibility_version $(PKG_MAJOR).$(PKG_MINOR) 265 AR_EXT = a 266 # Homebrew wants to make sure its formula does not disable FORTIFY_SOURCE 267 # However, this is not really necessary because 'CAPSTONE_USE_SYS_DYN_MEM=yes' by default 268 ifneq ($(HOMEBREW_CAPSTONE),1) 269 ifneq ($(CAPSTONE_USE_SYS_DYN_MEM),yes) 270 # remove string check because OSX kernel complains about missing symbols 271 CFLAGS += -D_FORTIFY_SOURCE=0 272 endif 273 endif 274 else 275 $(LIBNAME)_LDFLAGS += -shared 276 # Cygwin? 277 IS_CYGWIN := $(shell $(CC) -dumpmachine | grep -i cygwin | wc -l) 278 ifeq ($(IS_CYGWIN),1) 279 EXT = dll 280 AR_EXT = lib 281 # Cygwin doesn't like -fPIC 282 CFLAGS := $(CFLAGS:-fPIC=) 283 # On Windows we need the shared library to be executable 284 else 285 # mingw? 286 IS_MINGW := $(shell $(CC) --version | grep -i mingw | wc -l) 287 ifeq ($(IS_MINGW),1) 288 EXT = dll 289 AR_EXT = lib 290 # mingw doesn't like -fPIC either 291 CFLAGS := $(CFLAGS:-fPIC=) 292 # On Windows we need the shared library to be executable 293 else 294 # Linux, *BSD 295 EXT = so 296 VERSION_EXT = $(EXT).$(API_MAJOR) 297 AR_EXT = a 298 $(LIBNAME)_LDFLAGS += -Wl,-soname,lib$(LIBNAME).$(VERSION_EXT) 299 endif 300 endif 301 endif 302 303 ifeq ($(CAPSTONE_SHARED),yes) 304 ifeq ($(IS_MINGW),1) 305 LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) 306 else ifeq ($(IS_CYGWIN),1) 307 LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) 308 else # *nix 309 LIBRARY = $(BLDIR)/lib$(LIBNAME).$(EXT) 310 CFLAGS += -fvisibility=hidden 311 endif 312 endif 313 314 ifeq ($(CAPSTONE_STATIC),yes) 315 ifeq ($(IS_MINGW),1) 316 ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT) 317 else ifeq ($(IS_CYGWIN),1) 318 ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT) 319 else 320 ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT) 321 endif 322 endif 323 324 PKGCFGF = $(BLDIR)/$(LIBNAME).pc 325 326 .PHONY: all clean install uninstall dist 327 328 all: $(LIBRARY) $(ARCHIVE) $(PKGCFGF) 329 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY))) 330 @V=$(V) CC=$(CC) $(MAKE) -C cstool 331 ifndef BUILDDIR 332 cd tests && $(MAKE) 333 else 334 cd tests && $(MAKE) BUILDDIR=$(BLDIR) 335 endif 336 $(call install-library,$(BLDIR)/tests/) 337 endif 338 339 ifeq ($(CAPSTONE_SHARED),yes) 340 $(LIBRARY): $(LIBOBJ) 341 ifeq ($(V),0) 342 $(call log,LINK,$(@:$(BLDIR)/%=%)) 343 @$(create-library) 344 else 345 $(create-library) 346 endif 347 endif 348 349 $(LIBOBJ): *.h include/*.h config.mk 350 351 $(LIBOBJ_ARM): $(DEP_ARM) 352 $(LIBOBJ_ARM64): $(DEP_ARM64) 353 $(LIBOBJ_MIPS): $(DEP_MIPS) 354 $(LIBOBJ_PPC): $(DEP_PPC) 355 $(LIBOBJ_SPARC): $(DEP_SPARC) 356 $(LIBOBJ_SYSZ): $(DEP_SYSZ) 357 $(LIBOBJ_X86): $(DEP_X86) 358 $(LIBOBJ_XCORE): $(DEP_XCORE) 359 360 ifeq ($(CAPSTONE_STATIC),yes) 361 $(ARCHIVE): $(LIBOBJ) 362 @rm -f $(ARCHIVE) 363 ifeq ($(V),0) 364 $(call log,AR,$(@:$(BLDIR)/%=%)) 365 @$(create-archive) 366 else 367 $(create-archive) 368 endif 369 endif 370 371 $(PKGCFGF): 372 ifeq ($(V),0) 373 $(call log,GEN,$(@:$(BLDIR)/%=%)) 374 @$(generate-pkgcfg) 375 else 376 $(generate-pkgcfg) 377 endif 378 379 install: $(PKGCFGF) $(ARCHIVE) $(LIBRARY) 380 mkdir -p $(LIBDIR) 381 $(call install-library,$(LIBDIR)) 382 ifeq ($(CAPSTONE_STATIC),yes) 383 $(INSTALL_DATA) $(ARCHIVE) $(LIBDIR) 384 endif 385 mkdir -p $(INCDIR)/$(LIBNAME) 386 $(INSTALL_DATA) include/*.h $(INCDIR)/$(LIBNAME) 387 mkdir -p $(PKGCFGDIR) 388 $(INSTALL_DATA) $(PKGCFGF) $(PKGCFGDIR)/ 389 mkdir -p $(BINDIR) 390 $(INSTALL_LIB) cstool/cstool $(BINDIR) 391 392 uninstall: 393 rm -rf $(INCDIR)/$(LIBNAME) 394 rm -f $(LIBDIR)/lib$(LIBNAME).* 395 rm -f $(PKGCFGDIR)/$(LIBNAME).pc 396 rm -f $(BINDIR)/cstool 397 398 clean: 399 rm -f $(LIBOBJ) 400 rm -f $(BLDIR)/lib$(LIBNAME).* $(BLDIR)/$(LIBNAME).pc 401 rm -f $(PKGCFGF) 402 $(MAKE) -C cstool clean 403 404 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY))) 405 cd tests && $(MAKE) clean 406 rm -f $(BLDIR)/tests/lib$(LIBNAME).$(EXT) 407 endif 408 409 ifdef BUILDDIR 410 rm -rf $(BUILDDIR) 411 endif 412 413 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY))) 414 cd bindings/python && $(MAKE) clean 415 cd bindings/java && $(MAKE) clean 416 cd bindings/ocaml && $(MAKE) clean 417 endif 418 419 420 TAG ?= HEAD 421 ifeq ($(TAG), HEAD) 422 DIST_VERSION = latest 423 else 424 DIST_VERSION = $(TAG) 425 endif 426 427 dist: 428 git archive --format=tar.gz --prefix=capstone-$(DIST_VERSION)/ $(TAG) > capstone-$(DIST_VERSION).tgz 429 git archive --format=zip --prefix=capstone-$(DIST_VERSION)/ $(TAG) > capstone-$(DIST_VERSION).zip 430 431 432 TESTS = test_basic test_detail test_arm test_arm64 test_mips test_ppc test_sparc 433 TESTS += test_systemz test_x86 test_xcore test_iter 434 TESTS += test_basic.static test_detail.static test_arm.static test_arm64.static 435 TESTS += test_mips.static test_ppc.static test_sparc.static 436 TESTS += test_systemz.static test_x86.static test_xcore.static 437 TESTS += test_skipdata test_skipdata.static test_iter.static 438 check: 439 @for t in $(TESTS); do \ 440 echo Check $$t ... ; \ 441 LD_LIBRARY_PATH=./tests ./tests/$$t > /dev/null && echo OK || echo FAILED; \ 442 done 443 444 $(OBJDIR)/%.o: %.c 445 @mkdir -p $(@D) 446 ifeq ($(V),0) 447 $(call log,CC,$(@:$(OBJDIR)/%=%)) 448 @$(compile) 449 else 450 $(compile) 451 endif 452 453 454 ifeq ($(CAPSTONE_SHARED),yes) 455 define install-library 456 $(INSTALL_LIB) $(LIBRARY) $1 457 $(if $(VERSION_EXT), 458 cd $1 && \ 459 mv lib$(LIBNAME).$(EXT) lib$(LIBNAME).$(VERSION_EXT) && \ 460 ln -s lib$(LIBNAME).$(VERSION_EXT) lib$(LIBNAME).$(EXT)) 461 endef 462 else 463 define install-library 464 endef 465 endif 466 467 468 define create-archive 469 $(AR) q $(ARCHIVE) $(LIBOBJ) 470 $(RANLIB) $(ARCHIVE) 471 endef 472 473 474 define create-library 475 $(CC) $(LDFLAGS) $($(LIBNAME)_LDFLAGS) $(LIBOBJ) -o $(LIBRARY) 476 endef 477 478 479 define generate-pkgcfg 480 echo 'Name: capstone' > $(PKGCFGF) 481 echo 'Description: Capstone disassembly engine' >> $(PKGCFGF) 482 echo 'Version: $(PKG_VERSION)' >> $(PKGCFGF) 483 echo 'libdir=$(LIBDIR)' >> $(PKGCFGF) 484 echo 'includedir=$(INCDIR)/capstone' >> $(PKGCFGF) 485 echo 'archive=$${libdir}/libcapstone.a' >> $(PKGCFGF) 486 echo 'Libs: -L$${libdir} -lcapstone' >> $(PKGCFGF) 487 echo 'Cflags: -I$${includedir}' >> $(PKGCFGF) 488 endef 489