You can (ab)use the _ReturnAddress intrinsic if you're building with Visual Studio... but I don't think it gets you what you want, at least not directly.
The problem in general (as I understand it) is that your original source code may not look like the actual generated machine code. For example, any of the following can make your code look different in disassembly than it does in the original source:
- Inlined functions
- Outlined functions (rarer but still happens)
- Loop unrolling
- Vectorization
- Dead code elimination
- Optimizations that try to maximize code locality
- etc.
Because of this, generating a couple of labels in source and pulling their addresses may actually produce inconsistent or unpredictable results. It's actually pretty hard to know if your original source sufficiently resembles your machine code to do tricks like you're doing with the x86 assembly thing.
If you've ever stepped through an optimized program you've probably noticed that the current statement jumps around in weird ways; this is an indicator that the machine code is not 100% mimicking the source code - and that's a good thing. It means the optimizer is doing its job. Unfortunately, it also means that tricks to detect weirdness in the machine code have to be based on the machine code itself, not on the source-level code.
A common tactic is to use debug metadata (e.g. PDB files or DWARF on Unixy platforms) to statically analyze your compiled program, and generate CRCs or other sanity checks that can be embedded back into the program without recompiling it. Depending on what your needs are and how patient you are with doing weird linker hacks, that may or may not be a suitable approach here.