What OP needs is a disciplined approach to accomplishing this task.
He needs a good parser for the assembler source, so he knows he has an accurate representation of it. Beyond the pure parse part, he'll have
to emulate the assembler pretty completely, including all the complications, such as macros, conditional blocks, multiple location counters, absolute/relative/external symbols, etc. (Build a good parser by relying solely on regexes isn't going to work.)
He'll then need to compute first estimate of the control flow graph by inspecting the sequences of machine instructions and branches.
This may be harder to do than it looks; in big, complicated assembly codes people abuse entry points into procedures so that it is sometimes hard to tell what's an instruction, and what is data.
(Here's a trick I use in a big x86 application. I want to add sanity checking to my code in many places. The sanity tests look like this:
<test for some sane condition>
jf location+3 ; this branchs to a breakpoint in the middle of the next instruction
cmp al, 0xCC ; the immediate value is a BREAKPOINT opcode
They're compact, and a breakpoint occurs when some bad happens. But when analyzing this program for control flow, the "jmp false" sometimes branches into what appears to be the middle of an instruction. How will OP model that?)
The next complication are pointers to code. Assembler code often generates many pointers to other other instructions, and then hides those pointers in various places (the call instruction pushes them onto the data stack for the x86), retrieves them, and then does "jmp indirect". If you want to know where that jmp might go, you need to track the possible values a memory location might contain, which means you need to do a data flow analysis (how do values get there, and from where) and combine with call graph construction (can't get to that function? OK, then where it goes won't affect this code) to compute an answer that is reasonable.
Doing all this by ad hoc methods will end up producing inaccurate (useless) answers. OP needs to find a framework in which to build his parser, and implement good quality points-to analysis algorithms if he hopes to get a good result.
C isn't specifically designed to support this task. It can do it with enough additional sweat, but that's true for any programming language.
(Check my bio for such a framework. OP can use any framework that works for him).