Add support for asm-level filtering through LOCAL_FILTER_ASM

Change-Id: I937e9f8e53debf8a4eb3b64151ed8738d75158ac
diff --git a/build/core/definitions.mk b/build/core/definitions.mk
index b52c999..d749dd9 100644
--- a/build/core/definitions.mk
+++ b/build/core/definitions.mk
@@ -174,6 +174,7 @@
     EXPORT_CPPFLAGS \
     EXPORT_LDLIBS \
     EXPORT_C_INCLUDES \
+    FILTER_ASM \
 
 # The following are generated by the build scripts themselves
 
@@ -785,6 +786,102 @@
 hide = @
 endif
 
+# This assumes that many variables have been pre-defined:
+# _SRC: source file
+# _OBJ: destination file
+# _CC: 'compiler' command
+# _FLAGS: 'compiler' flags
+# _TEXT: Display text (e.g. "Compile++ thumb", must be EXACTLY 15 chars long)
+#
+define ev-build-file
+$$(_OBJ): PRIVATE_SRC      := $$(_SRC)
+$$(_OBJ): PRIVATE_OBJ      := $$(_OBJ)
+$$(_OBJ): PRIVATE_MODULE   := $$(LOCAL_MODULE)
+$$(_OBJ): PRIVATE_TEXT     := "$$(_TEXT)"
+$$(_OBJ): PRIVATE_CC       := $$(_CC)
+$$(_OBJ): PRIVATE_CFLAGS   := $$(_FLAGS)
+$$(_OBJ): $$(_SRC) $$(LOCAL_MAKEFILE) $$(NDK_APP_APPLICATION_MK)
+	@mkdir -p $$(dir $$(PRIVATE_OBJ))
+	@echo "$$(PRIVATE_TEXT)  : $$(PRIVATE_MODULE) <= $$(notdir $$(PRIVATE_SRC))"
+	$(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) $$(PRIVATE_SRC) -o $$(PRIVATE_OBJ)
+endef
+
+# This assumes the same things than ev-build-file, but will handle
+# the definition of LOCAL_FILTER_ASM as well.
+define ev-build-source-file
+LOCAL_DEPENDENCY_DIRS += $$(dir $$(_OBJ))
+ifndef LOCAL_FILTER_ASM
+  # Trivial case: Directly generate an object file
+  $$(eval $$(call ev-build-file))
+  LOCAL_OBJECTS += $$(_OBJ)
+else
+  # This is where things get hairy, we first transform
+  # the source into an assembler file, send it to the
+  # filter, then generate a final object file from it.
+  #
+
+  # First, remember the original settings and compute
+  # the location of our temporary files.
+  #
+  _ORG_SRC := $$(_SRC)
+  _ORG_OBJ := $$(_OBJ)
+  _ORG_FLAGS := $$(_FLAGS)
+  _ORG_TEXT  := $$(_TEXT)
+
+  _OBJ_ASM_ORIGINAL := $$(patsubst %.o,%.s,$$(_ORG_OBJ))
+  _OBJ_ASM_FILTERED := $$(patsubst %.o,%.filtered.s,$$(_ORG_OBJ))
+
+  # If the source file is a plain assembler file, we're going to
+  # use it directly in our filter.
+  ifneq (,$$(filter %.s,$$(_SRC)))
+    _OBJ_ASM_ORIGINAL := $$(_SRC)
+  endif
+
+  $$(info SRC=$$(_SRC) OBJ=$$(_OBJ) OBJ_ORIGINAL=$$(_OBJ_ASM_ORIGINAL) OBJ_FILTERED=$$(_OBJ_ASM_FILTERED))
+
+  # We need to transform the source into an assembly file, instead of
+  # an object. The proper way to do that depends on the file extension.
+  #
+  # For C and C++ source files, simply replace the -c by an -S in the
+  # compilation command (this forces the compiler to generate an
+  # assembly file).
+  #
+  # For assembler templates (which end in .S), replace the -c with -E
+  # to send it to the preprocessor instead.
+  #
+  # Don't do anything for plain assembly files (which end in .s)
+  #
+  ifeq (,$$(filter %.s,$$(_SRC)))
+    _OBJ   := $$(_OBJ_ASM_ORIGINAL)
+    ifneq (,$$(filter %.S,$$(_SRC)))
+      _FLAGS := $$(patsubst -c,-E,$$(_ORG_FLAGS))
+    else
+      _FLAGS := $$(patsubst -c,-S,$$(_ORG_FLAGS))
+    endif
+    $$(eval $$(call ev-build-file))
+  endif
+
+  # Next, process the assembly file with the filter
+  $$(_OBJ_ASM_FILTERED): PRIVATE_SRC    := $$(_OBJ_ASM_ORIGINAL)
+  $$(_OBJ_ASM_FILTERED): PRIVATE_DST    := $$(_OBJ_ASM_FILTERED)
+  $$(_OBJ_ASM_FILTERED): PRIVATE_FILTER := $$(LOCAL_FILTER_ASM)
+  $$(_OBJ_ASM_FILTERED): PRIVATE_MODULE := $$(LOCAL_MODULE)
+  $$(_OBJ_ASM_FILTERED): $$(_OBJ_ASM_ORIGINAL)
+	@echo "AsmFilter      : $$(PRIVATE_MODULE) <= $$(notdir $$(PRIVATE_SRC))"
+	$(hide) $$(PRIVATE_FILTER) $$(PRIVATE_SRC) $$(PRIVATE_DST)
+
+  # Then, generate the final object, we need to keep assembler-specific
+  # flags which look like -Wa,<option>:
+  _SRC   := $$(_OBJ_ASM_FILTERED)
+  _OBJ   := $$(_ORG_OBJ)
+  _FLAGS := $$(filter -Wa%,$$(_ORG_FLAGS)) -c
+  _TEXT  := "Assembly     "
+  $$(eval $$(call ev-build-file))
+
+  LOCAL_OBJECTS += $$(_ORG_OBJ)
+endif
+endef
+
 # -----------------------------------------------------------------------------
 # Template  : ev-compile-c-source
 # Arguments : 1: single C source file name (relative to LOCAL_PATH)
@@ -798,30 +895,19 @@
 _SRC:=$$(LOCAL_PATH)/$(1)
 _OBJ:=$$(LOCAL_OBJS_DIR)/$(2)
 
-$$(_OBJ): PRIVATE_SRC      := $$(_SRC)
-$$(_OBJ): PRIVATE_OBJ      := $$(_OBJ)
-$$(_OBJ): PRIVATE_MODULE   := $$(LOCAL_MODULE)
-$$(_OBJ): PRIVATE_ARM_MODE := $$(LOCAL_ARM_MODE)
-$$(_OBJ): PRIVATE_ARM_TEXT := $$(call get-src-file-text,$1)
-$$(_OBJ): PRIVATE_CC       := $$($$(my)CC)
-$$(_OBJ): PRIVATE_CFLAGS   := $$($$(my)CFLAGS) \
-                              $$(call get-src-file-target-cflags,$(1)) \
-                              $$(LOCAL_C_INCLUDES:%=-I%) \
-                              -I$$(LOCAL_PATH) \
-                              $$(LOCAL_CFLAGS) \
-                              $$(NDK_APP_CFLAGS) \
-                              $$($(my)C_INCLUDES:%=-I%) \
+_FLAGS := $$($$(my)CFLAGS) \
+          $$(call get-src-file-target-cflags,$(1)) \
+          $$(LOCAL_C_INCLUDES:%=-I%) \
+          -I$$(LOCAL_PATH) \
+          $$(LOCAL_CFLAGS) \
+          $$(NDK_APP_CFLAGS) \
+          $$($(my)C_INCLUDES:%=-I%) \
+          -MMD -MP -MF $$(_OBJ).d -c \
 
-$$(_OBJ): $$(_SRC) $$(LOCAL_MAKEFILE) $$(NDK_APP_APPLICATION_MK)
-	@mkdir -p $$(dir $$(PRIVATE_OBJ))
-	@echo "Compile $$(PRIVATE_ARM_TEXT)  : $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC)"
-	$(hide) $$(PRIVATE_CC) $$(PRIVATE_CFLAGS) -c \
-	-MMD -MP -MF $$(PRIVATE_OBJ).d \
-	$$(PRIVATE_SRC) \
-	-o $$(PRIVATE_OBJ)
+_TEXT := "Compile $$(call get-src-file-text,$1)"
+_CC   := $$(TARGET_CC)
 
-LOCAL_OBJECTS         += $$(_OBJ)
-LOCAL_DEPENDENCY_DIRS += $$(dir $$(_OBJ))
+$$(eval $$(call ev-build-source-file))
 endef
 
 # -----------------------------------------------------------------------------
@@ -840,7 +926,7 @@
 # Usage     : $(call compile-s-source,<srcfile>)
 # Rationale : Setup everything required to build a single Assembly source file
 # -----------------------------------------------------------------------------
-compile-s-source = $(eval $(call ev-compile-c-source,$1,$(1:%.S=%.o)))
+compile-s-source = $(eval $(call ev-compile-c-source,$1,$(patsubst %.s,%.o,$(patsubst %.S,%.o,$1))))
 
 
 # -----------------------------------------------------------------------------
@@ -855,35 +941,23 @@
 define  ev-compile-cpp-source
 _SRC:=$$(LOCAL_PATH)/$(1)
 _OBJ:=$$(LOCAL_OBJS_DIR)/$(2)
+_FLAGS := $$($$(my)CXXFLAGS) \
+          $$(call get-src-file-target-cflags,$(1)) \
+          $$(LOCAL_C_INCLUDES:%=-I%) \
+          -I$$(LOCAL_PATH) \
+          $$(LOCAL_CFLAGS) \
+          $$(LOCAL_CPPFLAGS) \
+          $$(LOCAL_CXXFLAGS) \
+          $$(NDK_APP_CFLAGS) \
+          $$(NDK_APP_CPPFLAGS) \
+          $$(NDK_APP_CXXFLAGS) \
+          $$($(my)C_INCLUDES:%=-I%) \
+          -MMD -MP -MF $$(_OBJ).d -c \
 
-$$(_OBJ): PRIVATE_SRC      := $$(_SRC)
-$$(_OBJ): PRIVATE_OBJ      := $$(_OBJ)
-$$(_OBJ): PRIVATE_MODULE   := $$(LOCAL_MODULE)
-$$(_OBJ): PRIVATE_ARM_MODE := $$(LOCAL_ARM_MODE)
-$$(_OBJ): PRIVATE_ARM_TEXT := $$(call get-src-file-text,$1)
-$$(_OBJ): PRIVATE_CXX      := $$($$(my)CXX)
-$$(_OBJ): PRIVATE_CXXFLAGS := $$($$(my)CXXFLAGS) \
-                              $$(call get-src-file-target-cflags,$(1)) \
-                              $$(LOCAL_C_INCLUDES:%=-I%) \
-                              -I$$(LOCAL_PATH) \
-                              $$(LOCAL_CFLAGS) \
-                              $$(LOCAL_CPPFLAGS) \
-                              $$(LOCAL_CXXFLAGS) \
-                              $$(NDK_APP_CFLAGS) \
-                              $$(NDK_APP_CPPFLAGS) \
-                              $$(NDK_APP_CXXFLAGS) \
-                              $$($(my)C_INCLUDES:%=-I%) \
+_CC   := $$($$(my)CXX)
+_TEXT := "Compile++ $$(call get-src-file-text,$1)"
 
-$$(_OBJ): $$(_SRC) $$(LOCAL_MAKEFILE) $$(NDK_APP_APPLICATION_MK)
-	@mkdir -p $$(dir $$(PRIVATE_OBJ))
-	@echo "Compile++ $$(PRIVATE_ARM_TEXT): $$(PRIVATE_MODULE) <= $$(PRIVATE_SRC)"
-	$(hide) $$(PRIVATE_CXX) $$(PRIVATE_CXXFLAGS) -c \
-	-MMD -MP -MF $$(PRIVATE_OBJ).d \
-	$$(PRIVATE_SRC) \
-	-o $$(PRIVATE_OBJ)
-
-LOCAL_OBJECTS         += $$(_OBJ)
-LOCAL_DEPENDENCY_DIRS += $$(dir $$(_OBJ))
+$$(eval $$(call ev-build-source-file))
 endef
 
 # -----------------------------------------------------------------------------
diff --git a/docs/ANDROID-MK.TXT b/docs/ANDROID-MK.TXT
index fd162dc..d4a0b34 100644
--- a/docs/ANDROID-MK.TXT
+++ b/docs/ANDROID-MK.TXT
@@ -649,3 +649,34 @@
     There, libbar.so will be built with a -llog at the end of the linker
     command to indicate that it depends on the system logging library,
     because it depends on 'foo'.
+
+LOCAL_FILTER_ASM
+    Define this variable to a shell command that will be used to filter
+    the assembly files from, or generated from, your LOCAL_SRC_FILES.
+
+    When it is defined, the following happens:
+
+      - Any C or C++ source file is generated into a temporary assembly
+        file (instead of being compiled into an object file).
+
+      - Any temporary assembly file, and any assembly file listed in
+        LOCAL_SRC_FILES is sent through the LOCAL_FILTER_ASM command
+        to generate _another_ temporary assembly file.
+
+      - These filtered assembly files are compiled into object file.
+
+    In other words, If you have:
+
+      LOCAL_SRC_FILES  := foo.c bar.S
+      LOCAL_FILTER_ASM := myasmfilter
+
+    foo.c --1--> $OBJS_DIR/foo.S.original --2--> $OBJS_DIR/foo.S --3--> $OBJS_DIR/foo.o
+    bar.S                                 --2--> $OBJS_DIR/bar.S --3--> $OBJS_DIR/bar.o
+
+    Were "1" corresponds to the compiler, "2" to the filter, and "3" to the
+    assembler. The filter must be a standalone shell command that takes the
+    name of the input file as its first argument, and the name of the output
+    file as the second one, as in:
+
+        myasmfilter $OBJS_DIR/foo.S.original $OBJS_DIR/foo.S
+        myasmfilter bar.S $OBJS_DIR/bar.S
diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT
index 47c88c6..f392084 100644
--- a/docs/CHANGES.TXT
+++ b/docs/CHANGES.TXT
@@ -57,6 +57,10 @@
 
   When doing a "ndk-build -j<number>", with <number> bigger than 1.
 
+- Add support for assembly-level source filtering. See the description of
+  LOCAL_FILTER_ASM in docs/ANDROID-MK.TXT for more details. This can be useful
+  for certain kinds of obfuscation tasks.
+
 OTHER FIXES & CHANGES:
 
 - The path to system headers is now included last in the compilation command