I am writing some x64 assembly for the GNU assembler. I've been trying to read about the .seh_* directives, but I'm not finding much information about them. The gas docs don't mention them at all.
But as I understand it, if my code might be in the stack during an SEH unwind operation, I am expected to use these. And since my code does stack manipulations and calls other functions, SEH is a possibility, so I should be using these.
Mostly I think I've got it right:
.seh_proc FCT
FCT:
push %rbp
.seh_pushreg %rbp
mov %rsp, %rbp
.seh_setframe %rbp, 0
push %r14
.seh_pushreg %r14
lea -(iOffset + iBytes)(%rsp), %rsp
.seh_stackalloc iOffset + iBytes
andq $-16, %rsp <---- But what about this?
.seh_endprologue
etc...
But there's one bit that's not clear. I've got this instruction:
andq $-16, %rsp
How on earth do I tell SEH that I'm performing stack alignment? This might adjust the stack by anywhere from 15 bytes (very unlikely) to 8 bytes (very likely), to 0 bytes (certainly possible). Since the actual amount may not be determined until runtime, I'm stuck.
I suppose I can skip the .seh instruction, but if 8 bytes of stack do get reserved there, I've probably trashed the unwind, haven't I? Doesn't that defeat the entire purpose here?
Alternately I can omit the alignment. But if I call other functions (say memcpy), aren't I supposed to align the stack? According to MS:
The stack will always be maintained 16-byte aligned, except within the prolog
Maybe I can 'reason' my way thru this? If the guy that called me did things right (if...), then the stack was aligned when he did the call, so now I'm off by 8 bytes (the return address) plus whatever I do in my prolog. Can I depend on this? Seems fragile.
I've tried looking at other code, but I'm not sure I trust what I'm seeing. I doubt gas reports errors from misusing .seh_*. You would probably only ever see a problem during an actual exception (and maybe not always even then).
If I'm going to do this, I'd like to do it right. It seems like stack alignment would be a common thing, so someone must have a solution here. I'm just not seeing it.
Looking at some code output by gcc, I think I know the answer. I was on the right track with my 'reason' approach.
When a function is called, the stack temporarily becomes unaligned (due to the call), but is almost immediately re-aligned via pushq %rbp. After that, adjustments to the stack (for local variables or stack space for parameters to called functions, etc) are always made using multiples of 16. So by the end of the prolog, the stack is always properly aligned again, and stays that way until the next call.
Which means that while andq $-16, %rsp can be used to align the stack, I shouldn't need to if I write my prolog correctly.
CAVEAT: Leaf functions (ie functions that don't call other functions) do not need to align the stack (https://msdn.microsoft.com/en-us/library/67fa79wz.aspx).
Related
On most x86 Assembly (NASM especifically) code samples I see around (even on the ones generated by GCC) I see what's called "setup of stack frame". Like this:
main:
/*setting the stack frame*/
push ebp
mov ebp,esp
...
code goes here
...
/*removing the stack frame*/
mov esp, ebp
pop ebp
I have 3 questions about this practice:
If my code doesn't touch the stack then setting/removing the stack frame as above is completely useless, right?
Even if my code uses the stack, as long as pop everything I push (leaving the stack as it was essentially) then again setting up a stack frame is completely useless, right?
As I see it the only purpose of this would be to save the value of ESP so that I can play around with it on my code without worrying about messing things up, and once I am done I simply restore its original value. Is this the purpose of the stack frame setup or am I missing something?
Thanks
Well, in fact, you don't need stack frames.
Stack frames are convenient when you save registers and store local variables in stack - to make writing and debugging easier: you just set ebp to a fixed point in stack and address all stack data using ebp. And it's easier to restores esp at the end.
Also, debuggers often expect stack frames to be present, otherwise you can get inaccurate stack call for example.
So, the answer to 1 is yes, the answer to 2 and 3 is above.
You are essentially correct.
Stack frames do have certain benefits, though, even when you don't need a fixed stack reference to access parameters and locals. In particular having them there allows for accurate stack walking for generating stack traces for debugging purposes.
This is done by convention. C language functions use stack frames to access parameters that are sent to functions, and to set up dynamic local variables. That is why they do it in the sample code that you are looking at. Of course if you want to do it your way, you can, but you won't be able to invoke your code from C etc.
EDIT: I am also pretty sure that there are compilers that implement different calling conventions that optimize that and maybe do not create a frame at all. So basically, you are right. Stack frames are not necessary.
I am debugging an exe (x86) in WinDbg because it is crashing on my computer, the devs provide no support and it's closed source.
So far I found out that it crashes because a null pointer is passed to ntdll!RtlEnterCriticalSection.
I'm trying to find the source of that null pointer and I've reached a point (my "current point") where I have absolutely no idea where it was called from. I tried searching the area of the last few addresses on the stack, but there were no calls, jumps or returns at all there.
The only thing I have is the last dll loaded before the crash, which is apparently also long (at least a few thousand instructions) before my current point.
I can't just set a few thousand break points, so I thought single step exceptions could help (I could at least print eip on every instruction, I don't care if that would take days).
But I can't get the CPU to fire the exception! After loading the exe, I enter the following in the debugger:
sxe ld:<dll name>
g
sxe sse
sxe wos
r tf=1
g
The debugger breaks for the loaded dll where I want it to, but after the second g, the program just runs for a few seconds before hitting the crash point, not raising any single step exception at all.
If I do the same without the first two lines (so I'm at the start point of the program), it works. I know that tf is set to zero every time a SSE is fired, but why doesn't it fire at all later in the program?
Am I missing something? Or is there any other way I could find the source of that null pointer?
g is not the command for single stepping, it means "go" and only breaks on breakpoints or exceptions.
To do single stepping, use p. Since you don't have the source code, you cannot do instruction-stepping on source code level, meaning that you have to do it on assembly level. (Assembler instruction stepping should be default, it not enable it with l-t.) Depending on how far you need to go, this takes time.
Above only answers the question as it is. The open question is, like pointed out in the comments already, what will you do to mitigate that bug? You can't simply create a new critical section nor do you know which existing critical section should be used in that place.
I've noticed that the jackson API obfuscates an infinite recursion by wrapping, and displaying a "chain" that hints at the recursion, i.e. something along the lines of this:
ArrayList[0]->"fieldX"->"..".
I'm wondering what the advantage of doing this is? I recently had alot of trouble with an infinite recursion bug which would be quite easy to trace if the explicit calls were made available.
I suspect it has to do with the fact that, maybe jackson's introspection of the methods is happening in a separate thread, or is done in a way that loses the explicit stack calls.
Jackson does indeed catch this, since more often than not displaying data structure that causes it is much more useful than raw stack trace. Raw stack trace can show you where things happen, but oftentimes not why they happen.
However: one thing Jackson probably should do is to chain the original exception as root cause, to also allow you to inspect it. Looks like this is not yet done, but it should be very easy to add.
I will go ahead and file RFE for this.
I am working on a very simple decompiler for MIPS architecture and as I progress I have to define lots of rules for code analysis, for example "if this opcode is lui and next opcode is addiu then return var = value" or "if this opcode is bne and it's referring to address before current - create loop definition in parsing tree". The problem - there are tons of such rules and I can't find a good way to define them. I've tried writing separated functions for every rule, defining nice OOP base logic classes and extending them to create rules, even tried regular expressions on disasmed code(to my surprise this works better than expected) but no matter what I've tried, my code soon became to big and to hard to read no matter how well I am trying to document and structure it.
This brings me to conclusion, that I am trying to solve this task by using wrong tools(not to mention being too stupid for such complex task :) ), but I have no real idea what should I try. Currently I have two untested ideas, one is using some kind of DSL(I have absolutely no experience in this, so I can be totally wrong), and another is writing some kind of binary regexp-like tools for opcode matching.
I hope someone can point me in correct direction, thx.
I would guess that some of your rules are too low-level, and that's why they're becoming unmanageable.
Recognising lui followed by addiu as a 32-bit constant load certainly seems very reasonable; but trying to derive control flow from branch instructions at the individual opcode level seems rather more suspect - I think you want to be working with basic blocks there.
Cifuentes' Reverse Compilation Techniques is a reference which keeps cropping up in discussions of decompilation that I've seen; from a fairly brief skim, it seems like it would be well worth spending some time reading in detail for your project.
Some of the x86-specific stuff won't be relevant - in particular, the step which translates x86 to a low-level intermediate representation is probably not necessary for MIPS (MIPS is essentially just one basic operation per opcode already) - but otherwise much of the content looks like it should be very useful.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I just came across an idea in The Structure And Interpretation of Computer Programs:
Data is just dumb code, and code is just smart data
I fail to understand what it means. Can some one help me to understand it better?
This is one of the fundamental lessons of SICP and one of the most powerful ideas of computer science. It works like this:
What we think of as "code" doesn't actually have the power to do anything by itself. Code defines a program only within a context of interpretation -- outside of that context, it is just a stream of characters. (Really a stream of bits, which is really a stream of electrical impulses. But let's keep it simple.) The meaning of code is defined by the system within which you run it -- and this system just treats your code as data that tells it what you wanted to do. C source code is interpreted by a C compiler as data describing an object file you want it to create. An object file is treated by the loader as data describing some machine instructions you want to queue up for execution. Machine instructions are interpreted by the CPU as data defining the sequence of state transitions it should undergo.
Interpreted languages often contain mechanisms for treating data as code, which means you can pass code into a function in some form and then execute it -- or even generate code at run time:
#!/usr/bin/perl
# Note that the above line explicitly defines the interpretive context for the
# rest of this file. Without the context of a Perl interpreter, this script
# doesn't do anything.
sub foo {
my ($expression) = #_;
# $expression is just a string that happens to be valid Perl
print "$expression = " . eval("$expression") . "\n";
}
foo("1 + 1 + 2 + 3 + 5 + 8"); # sum of first six Fibonacci numbers
foo(join(' + ', map { $_ * $_ } (1..10))); # sum of first ten squares
Some languages like scheme have a concept of "first-class functions", which means that you can treat a function as data and pass it around without evaluating it until you really want to.
The upshot is that the division between "code" and "data" is pretty much arbitrary, a function of perspective only. The lower the level of abstraction, the "smarter" the code has to be: it has to contain more information about how it should be executed. On the other hand, the more information the interpreter supplies, the more dumb the code can be, until it starts to look like data with no smarts at all.
One of the most powerful ways to write code is as a simple description of what you need: Data which will be turned into code describing how to get you what you need by the interpretive context. We call this "declarative programming".
For a concrete example, consider HTML. HTML does not describe a Turing-complete programming language. It is merely structured data. Its structure contains some smarts that let it control the behavior of its interpretive context -- but not a lot of smarts. On the other hand, it contains more smarts than the paragraphs of text that appear on an average web page: Those are pretty dumb data.
In the context of security: Due to buffer overflows, what you thought of as data and thus harmless (such as an image) can become executed as code and p0wn your machine.
In the context of software development: Many developers are very afraid of "hardcoding" things and very keen on extracting parameters that might have to change into configuration files. This is often based on the idea that config files are just "data" and thus can be changed easily (perhapy by customers) without raising the issues (compilation, deployment, testing) that changing anything in the code would.
What these developers don't realize is that since this "data" influences the behaviour of the program, it really is code; it could break the program and the only reason not to require complete testing after such a change is that, if done correctly, the configurable values have a very specific, well-documented effect and any invalid value or a broken file structure will be caught by the program.
However, what all too often happens is that the config file structure becomes a programming language in its own right, complete with control flow and everything - one that's badly documented, has a quirky syntax and parser and which only the most experienced developers in the team can touch without breaking the application completely.
So, in a language like Scheme, even code is treated as first class data. You can treat functions and lambda expressions much like you treat other code, say passing them into other functions and lambda expressions. I recommend continuing with the text as this will all become quite clear.
This is something you should come to understand from writing in a compiler.
One common step in compilers is to transform the program into an abstract syntax tree. Representation will often be like trees such as [+, 2, 3] where + is the root, and 2, 3 are the children.
Lisp languages simply treats this as its data. So there is no separation between data and code which are both lists that look like AST trees.
Code is definitely data, but data is definitely not always code. Let's take a basic example - customer name. It's nothing to do with code, it's a functional (essential), as opposed to a technical (accidental) aspect of an application.
You could probably say that any technical/accidental data is code and that functional/essential data is not.