2. Functions can be expression functions which can be set in the code specification or used in expressions. Procedures can be written only in packages' bodies.
3. Procedures can be set to no-return state: that kind of procedure doesn't end in the normal way, but, for example, only by raising an exception.
4. Procedures can be null procedures, empty. That not the same as abstract subprograms from other programming languages.
Also, the difference is, in my opinion, more visible in the safe subset of Ada, SPARK, where still exists the rule which forbids side effects on functions.