Hacker News new | past | comments | ask | show | jobs | submit login
Is Python call-by-value or call-by-reference? Neither. (jeffknupp.com)
39 points by jknupp on Nov 14, 2012 | hide | past | favorite | 65 comments



Wrong. It's call-by-value, the confusion comes from what, in Python, is considered a value (and when a value is mutable, which is always (with a little ctypes magic), even the built-in number 4). And just like in Java, which also is always call-by-value, Python passes pointers-by-value under the hood which allows for some easy modification.

There is an easy test to see if a language supports call-by-reference or not:

    a = 3
    b = 4
    swap(a,b)
    print a, b # 4 3
C++ can do this, C can't, C# can't (if you think it can, then so can C), Python can't, Java can't. Therefore, all of those but C++ are call-by-value in all cases.

Edit: I hasten to add, the swap() function should be implemented "traditionally". i.e.:

    def swap(x, y):
      temp = x
      x = y
      y = temp


To say that because Python passes pointers-by-value under the hood (which is true for cpython, but not other implementations) is not useful. "Call by value" and "Call by reference" have reasonably precise definitions, and Python fits neither. See http://en.wikipedia.org/wiki/Call_by_sharing#Call_by_sharing for a discussion of the difference.


Re: call-by-sharing: "Although this term has widespread usage in the Python community, identical semantics in other languages such as Java and Visual Basic are often described as call-by-value, where the value is implied to be a reference to the object."

It's behaviorally call-by-value, where the value is always an object reference.

The difference is only mildly interesting, and the fervor with which you're arguing about it is wholly uninteresting, bordering on misleading. This is a semantic distinction with little to no use, and just serves to further confuse the rather simple and clear behavior.


afaik, this approach is from (or at least strongly championed at) comp.lang.python, and i would guess that their experience is that it is the most successful way of explaining python to new users there.

it's not so terrible - it works well enough for c.l.p, and anyone used to call by value with references/pointers is capable of working things out themselves.

really, it's largely a python (and c.l.p) cultural thing. you're berating some guy who's just a messenger for something that, in its context, doesn't do any harm (indeed, might help some newbies) (i don't have any skin in this game, but the guys on c.l.p do great work helping others; if this helps them it's fine by me).


You're right, it doesn't do any harm. But I think the way he's presenting it is harmful, as it's more confusing and not intended as explanation, but more as pointing out a distinction that isn't really present. He's very fervently defending a minor point of semantics, and I feel that's harmful.


Implementation details don't really matter: it's about how the language behaves (as is demonstrated by the SWAP litmus test). That implementations may do other things (generally for performance reasons, such as PyPy's function inlining) is irrelevant: those performance optimizations are not allowed to (noticeably) change semantics.


What do other Python implementations use? If it's something that indirectly keeps track of data location it's a pointer. The actual implementation of the pointer doesn't matter.

"Call-by-object-sharing" is better expressed as "call-by-object-pointer-value". But at this point it's just an argument over definitions. One either accepts that call-by-reference and call-by-value are the only two options along with the test above that includes C++, Ada, and Pascal as languages which support call-by-reference, or one doesn't.


One either accepts that call-by-reference and call-by-value are the only two options

I do not, there is also call by need and call by name. How does your test apply to Haskell? Incidentally call by sharing is much older than python. Wikipedia claims Liskov coined the term in 1974. I agree with you, call by value where the value happens to be a reference doesn't seem fundamentally different than call by value and probably doesn't need its own term.

http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sha...


To add to the historical point, Pascal was made in 1970 and supports both call-by-value and call-by-reference, so I get the feeling that Liskov was just muddying the waters. Considering that in modern usage call-by-sharing is relatively unheard of (sometimes even in Python circles), I really don't see what it has going for it.

Can Haskell pass the test? If it can't, it doesn't support call-by-reference.

You do bring up an interesting line of thought with call-by-need et al. I tend to just lump them under "lazy evaluation" and I don't really view them as impacting the value/reference dichotomy. The question there, then, is at the end of the day if/when an argument is evaluated (to whatever extent), does it match call-by-value or call-by-reference semantics? (And if the behavior is achieved with macro expansion, can it even rightfully be called a "call-by-X" behavior?) Clojure is adamantly call-by-value with its lazy evaluation, is there any particular reason why another language couldn't have the same lazy evaluation semantics as Clojure but support call-by-reference? pdw elsewhere in this thread suggests this whole "call-by-X" issue is pointless once you bring in lazy evaluation, I don't think that's a bad assessment.


The definition of call-by-value works fine for Python if you accept that object references are values in their own right, and that object variables contain those reference values.

If you don't accept that, then lots of other things become difficult to understand and explain as well. For instance, what do you call the thing that gets stored in a list? It's clearly not the object value itself, because that would preclude two lists from containing the same object.


This analysis is how I've always understood the distinction between call-by-value or reference.

I think the author of the article is a little confused about C++ as well, or perhaps just doesn't have a firm enough handle on it to be able to articulate the distinction between a location in memory and the value at a location in memory.


i am confused by your assertion that languages other than c++ can't support call by reference, there is a pretty clearly defined 'ref' keyword in c# that allows for exactly the behavior above.


swap(ref a, ref b) would be all it takes in C#. Or am I missing something? Huge difference between that and pointers in C.


The reason I would argue this isn't call-by-reference is because of the additional syntax needed from the caller side. Similarly with C you can do swap(&a, &b). In C++ you just need swap(a, b), it's up to the callee whether a and b are passed as references or not.


I understand, now. You're taking an object and getting a reference to it, then passing the _value_ of that reference into the function you're calling, so it's still call-by-value where the value happens to have a semantic meaning as a reference to an object.


yup yup this post is right!


A lot of comments here are talking about how it's "really" just call-by-value. I want to explain why this is unproductive.

First, let's acknowledge that the context we're discussing is explaining to someone new to Python how Python works with function arguments.

Now, if someone asks if lead-acid batteries work using chemistry, and you say "they use physics", then they will probably end up with a fairly inaccurate picture of how lead-acid batteries work. What you've told them is technically correct, but it isn't practically useful.

It is the same if someone asks how Python passes arguments to functions and you say "it's pass-by-value". You've told them something technically correct, but they're going to think inaccurate things like that passing an object to a function copies all of the object's properties like a struct in C.

Even if you say "it's pass-by-value but the values are not what you think", you haven't actually added to their understanding by that phrase. You're better off explaining conceptually how it works, describing it as "call-by-sharing", and then explaining what that means. It will signal their brain to allocate space for a new concept, and not to drag in erroneous ideas from existing concepts. After they understand how it works, you can explain that call-by-sharing is actually just a spoonful of sugar to help the call-by-value go down.

Here's the thing: words are there to help us communicate. If you use a word in a way that is technically correct but conveys the wrong idea to your listener, you're doing it wrong.

Here's the other thing: this is computer science. In computer science, as in all math, you often encounter a concept that is "really just" some other concept. When you come to that realization about a concept that you understand superficially, it can be transformative, taking you to a deeper level of comprehension. When someone asks you about the concept, you'll want to share that deep comprehension with them, so it's natural to want to jump right into it and explain it by connecting it to the general case. But they will not understand if you do that.

You can't teach someone addition by starting with ring theory, after all.


On the contrary, I think inventing a new class of of "call-by-X" function arguments makes it harder to explain Python to newcomers. I would clarify that I think I'm talking about seasoned programmers, and you probably mean somebody who's a fairly new to programming in general. It's a tough balance to strike, but I still think common semantics are best.

The concepts of call-by-value vs call-by-reference are simple and easy to distinguish once somebody has understood this basic concept in languages. I don't mean to disregard newcomers, though. And in-fact I think that it is doing a disservice to them to make python sound like it is radically different and more complicated than other languages. Instead I think a newcomer is best served by helping them grasp basic, common language concepts as they apply to python as well as other languages.

I really also need call out that there seem to be a lot of inaccuracies with regards to other languages than python on this thread and even some confusing terminology and analogies by the article's author. Specifically there seem to be a lot of misunderstandings about C (and even C++) flying around and being perpetuated here.

For example, you compared passing a python object to passing a struct in C. Passing a C struct to a function does _not_ copy all the fields of the struct. It passes a reference (pointer) to the function, which the function then uses to access the fields (or properties if you will) in the struct directly at their original location in memory.

You do get automatic copies of primitive numeric types when you pass them to functions in C. The reasoning and distinction is pretty simple: they fit in hardware registers.

But, a struct, an array, or a string (or character array) is always going to be passed as a pointer. When you pass it to a function, the only way you get a copy of it is if you explicitly copy the value to a new location in memory and point to it. You can of-course also pass a pointer to a numeric value to a function as well (as in func(int *var)) instead of the actual value (as in func(int var)), in which case the same semantics apply.


but it's not a question of opinion. it's a question of experience. the call-by-sharing approach comes, afaict, from comp.lang.python where they spend most of their time explaining things to newbies. and this is apparently what works best for them.

personally, i find it confusing and near useless. but then i don't need to read some blog entry to understand python's semantics. so this really isn't about me.

again: this is a cultural thing, from c.l.p. - it apparently works well for them.


>On the contrary, I think inventing a new class of of "call-by-X" function arguments makes it harder to explain Python to newcomers.

Then I think you may have forgotten what it's like to move to a call-by-sharing language for the first time.

>Passing a C struct to a function does _not_ copy all the fields of the struct. It passes a reference (pointer) to the function, which the function then uses to access the fields (or properties if you will) in the struct directly at their original location in memory.

I'm sorry, but everything you said there is wrong. Try it out for yourself: https://gist.github.com/4073329


Wow ok.. I'm going to try to be polite. I don't think _you_ tried it as you suggest I do:

first shot: ~ gcc -o foo -ggdb foo.c foo.c: In function ‘main’: foo.c:31: error: ‘flippedPoint’ undeclared (first use in this function) foo.c:31: error: (Each undeclared identifier is reported only once foo.c:31: error: for each function it appears in.)

Typo fixed: s/flippedPoint/secondPoint

what's the output?

    "{1, 2}{-1, -2}"

EDIT: Yours is actually an interesting example, and you're right, i responded to quick from the typo fix and didn't actually grok it.

But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.


[Double posting because I was out of my edit window by the time I saw your edit]

>But, actually we're both wrong... and right? The real answer turns out to be a bit more complicated. In your example the copies are made (automatically) in the caller (main) which actually passes a pointer to flipPoint. Try disassembling your executable. You'll see what I mean.

I'm really not sure that what the assembly code does is relevant. First off, once it's in assembly, the concepts of "caller" and "function" are gone completely. There are structures that correspond to what compilers typically emit when you define and call functions, but there is no "copy in the caller and pass a pointer to the function". There's just "copy this data on the stack, put the location into a register, and then jump to this location".

Furthermore, this is looking at implementation details, and what we're concerned here with are the abstract concepts of how these languages work. If you look at the assembly, you're seeing how your compiler decided to handle it. If you have optimization on, flipPoint is going to be inlined anyway. The spec doesn't really care how the compiler achieves the result as long as it does achieve the correct result. One compiler might have it copy before jumping and pass a pointer, but another compiler could just as easily pass a pointer before jumping and then have the copy made after the jump. You would not know the difference.

But the way C acts is as if the fields of the struct were being copied when they were passed to the function.


Yeah, I renamed something and then had to do an edit, but I guess you saw the original broken version. Sorry.

The output of {-1, -2} is because it returned the other point by value. The first point is unmodified, which is why it prints out {1, 2}. If the value was being passed as a reference, the output would be {-1, -2}{-1, -2}.

Edit: "If the value was being passed as a reference" is sort of a weird thing to say. What I meant, of course, was "if the struct was being passed as a reference".


Sure, but I think it's still possible to explain something well without being inaccurate.


I agree if you're starting with a blank slate. If someone asks "How does Python handle arguments", then you can just omit any mention of call-by-value until they understand the concept, and have total accuracy the whole time.

But if they come to you with "Is Python call-by-value or -reference?", then for the sake of getting them to break away from those contexts, I think your best bet is to say "neither", which is technically-but-not-practically slightly inaccurate.

You could try saying "It's technically call-by-value but you seriously need to forget everything about call-by-value in this context until I explain it to you," but depending on how their mind works, they may be looking for the connection to call-by-value the whole time you explain it (certainly that's what my mind would do if it were explained that way). And that's just a distraction.

So as long as you tell them at the end, "OK, so technically I lied earlier; this is call-by-value, but that's not how it's understood conceptually", I think the marginally inaccurate route is better.


How is this different from call-by-value, where all values are object references?


It's not, it's call-by-value-but-some-people-can't-accept-it


Isn't this by definition call by value? The reference / binding is passed by value. Changing the reference to point to something else will not make the other reference to point to the same too.


Call by value would mean that a copy of the value of the argument is passed to the function without involving the original value at all. To say the binding is passed by value is not useful, as all languages would then be considered "call by value", since _something_ needs to be passed into the function, and we can just call it a value.


This argument is as old as call-by-... definitions, but... What python holds in the variables are references to objects. Those are the values you're passing, so it's call by value using this reasoning.

Some languages do actually hold the value itself (struct for example) in the variable, so there you get a copy of the value (the struct contents). In python you get the copy of a reference (which again, is the value held in a variable).


That is correct: the object reference is copied into the caller's symbol table when calling. Hence, CBV.


not true. the program can be compiled to directly reference the variables themselves


Pedantically, sure, but I think the point is to explain it so that people actually understand. If you say "Python is call-by-value" to C programmer then they will probably have some serious misconceptions about what happens when you pass an object to a function.


> they will probably have some serious misconceptions about what happens when you pass an object to a function.

    p = Person()
The thing on the left is object reference, the thing on the right is object. When you do some_func(p) or some_func(Person()), you don't pass an object but an object reference.

There. No serious misconceptions.

C# and Java are doing just fine having the same model and explaining it the same way. And C programmers just need to think of `p = Person()` as `Person *p = new_person()`


>There. No serious misconceptions.

Well, yes, there might be. Because "object reference" sounds a lot like you're saying it's call-by-reference, and that's also confusing. it makes it sound like the output of this would be "overwritten":

  def some_func(x): x = "overwritten"
  p = Person()
  some_func(p)
  print p
In addition, my point was that using the term "call-by-value" is confusing, and since you didn't use that term in your explanation, it's all moot.


My point is writing a blog post saying python is neither call-by-value nor call-by-reference is made up shit and does nothing for someone who doesn't already understand it. Someone who doesn't already understand it will have to work through to get the gist of call-by-value and object references.

The blog post didn't simplify anything for someone who doesn't already understand it. So why not stick with terminology which is used by Java, C#, C among others?


>My point is writing a blog post saying python is neither call-by-value nor call-by-reference is made up shit

I guess so, in the sense that all of those terms are "made up shit". But they are useful for explaining the concepts.

>The blog post didn't simplify anything for someone who doesn't already understand it. So why not stick with terminology which is used by Java, C#, C among others?

Apparently, as others have pointed out here, the term "call-by-sharing" has largely come into popular use from people explaining how Python works in user groups. That's a strong indication that it actually is a pretty effective way to help newbies understand it.


I don't think they would be confused or get very many misconceptions, especially if they know how to mimic OOP in C. http://www.thejach.com/view/2010/1/oop_in_c_with_function_po... shows one way to do OOP in C (Zed's great C book shows another way for OOP that's prototypes-based like Javascript), one line of code is: `first_tank->fire_at(first_tank, second_tank);` Is it confusing that the second_tank object's health will decrease? Would they be confused over Python's `first_tank.fire_at(second_tank)`? In fact I think seeing that example of OOP would make another thing clear: the existence of 'self' in Python method arguments.

Additionally a C programmer has only ever heard of pass-by-value, so by introducing something new I'd think you would have a higher chance of confusing them. Now if you tell a C++ programmer that Python "isn't call-by-value", they'll immediately wonder how you can write a traditional swap() function (or more likely how to return-by-reference for efficiency), and you'll have to introduce them to new terminology like "call-by-shared-object", which it seems most people don't think is distinct from "call-by-object-pointer/'reference'-value" anyway.


I'm a C# developer who also programmed in Java in the past. C# and Java both pass pointers by value (which is what Python does too). This is a very important thing to learn when programming C# or Java. A method (or function) in any of these languages can either manipulate the object that the reference points to, or they can reassign the reference to a new object internally (which will leave the original object alone).


this is over complicating the model to avoid saying what for some reason people are terrified to say: that objects are just pointers. when you pass an object you are passing the value of a reference. it's not that scary


That's confusing the language specification with one of its implementations. In Jython, for example, objects are not "just pointers".


no, they are still just pointers. they might be pointers to something fancier than a struct of its instance variables and abstracted by java's object system but in the end it's still a pointer


I have the impression than anyone who has issues with this never experienced programming in assembly.


I have a C based mental model of what is happening. Can anyone comment on whether it is correct?

In C terms, I think of all objects (including primitives such as numbers) as a struct with a void* pointer that holds the actual data, and another field that describes how to interpret the data: struct Obj { void* data; ObjDesc descr; }

Whenever you do objA=objB you create an new struct Obj with objA.data == objB.data. The same things happens when you pass an object to a function: you create a copy of the Obj.

When you modify an Obj, two things can happen: if the Obj is immutable you change where void* data points to: n1 = 4 n2 = b1 n1 = 5 ==> n1.data != n2.data

On the other hand, if Obj is mutable, than you don't change void* data, you modify the memory pointed to by data: n1=[] n2=n1 n1.append(1) ==> n1.data == n2.data

Is this correct or is mental model going to bite me sometime?


This is really far off, actually.

I don't mean to criticize. I think the best advice is to read K&R C again. And, as some other posters have suggested, take a look and at least a passing understanding of the memory model and assembly code generated by C/C++ compilers.

You'll see, for instance, that type information is not stored as a field in a C struct at all, it's purely a distinction for the compiler to use. A C struct, indeed any type of data in C, is _just_data_ in memory. At the machine level, there's no such thing as a type. Just registers, memory, and instructions. The compiler uses type information to generate the right instructions to handle the type.

And to clarify, type metadata _as_actual_data_ can exist in higher level languages, but it's definitely not a C thing.


I was speaking of a model of how python does things, based on a C style implementation. Not an explanation of how C works.


That is more or less correct. It isn't exactly what happens, but the mental model is correct.


Python is a truly bizarre language in this regard. It's behavior is unusual and similar only to a few other less well known niche languages such as C# and Java.


I wish all this "call by x" terminology would just disappear. It's fine if you're discussing ALGOL-60 dialects, which by modern standards were all horribly confused about parameter passing (call by name, anyone?). It's just not helpful at all when discussing modern languages.

If we have to keep it, I vote for Kent Pitman's suggestion of "call by identity". (I can't find the reference right now.)


The usual phrase I've seen to describe this is "passes references by value". And it's the norm in almost all popular OOP languages since the mid-90s.


I like to think of this as "call-by-name". That's because every name in python is actually a lookup in a dictionary mapping strings to values. This is different from languages like C# and Java where some things such as class and function references can actually be thought of as "values". In python, everything that isn't a keyword or a literal is a name, thinking otherwise leads to gotchas.


The term call-by-name already exists and means something entirely different. It will blow your mind. http://www.cs.sfu.ca/~cameron/Teaching/383/PassByName.html



I genuinely can't tell if you're trolling by calling Java a "less well known niche language".

As for Python being bizarre, it's just call-by-value, as has been pointed out elsewhere. The only arguably bizarre part is that all values must be pointers to objects. But I target like that consistency. I prefer it to Java, where I always have to think about whether a variable is an object pointer or a primitive type.


As far as I can tell, he was being entirely sarcastic.


It didn't occur to me that here on HN one could actually get away with calling Java or C# a "niche language", since they are some of the most popular languages out there (though less so in the HN bubble, partly deservedly so I'd say, but still).


Python is strictly a call-by-ref language. The author of the blog and many commenter here seem confused. There are two causes:

1. Some objects are immutable.

This makes some calls seem to be call-by-value, but they are not. A simple look at the generated code makes this obvious. Integers, strings, tuples, ... are passed by reference. It's just that you can't mutate the object being passed.

2. The behaviour of the assignment operator is different from most non-functional language.

In Python, assignment never mutate values. It assign a new reference to the 'variable' (i.e. the scoped name). This explains clearly why in functions, you can't mutate an immutable object even though it is passed by reference: assignment merely rebind the argument name to a new value.

That is why when you want to mutate something in a function in Python, your only recourse is to call a function on that object:

  i = 4
  s = 'George'
  l = [ 'me', 'you']
  foo (i, s, l)

  def foo(a, b, c):
    a = 3
    b = 'Mark'
    c.append( 42 )
    c = [ 2, 1 ]

  print(i, s, l)
  # prints 4, 'George', ['me', 'you', 42]


While Python works by passing object references, it is not call-by-reference as that term is usually understood. Call-by-reference means that assignment within a function will be seen in the calling scope. That does not happen in Python.


Well, regardless of the call-by-x discussion, this is actually a really good explanation of scope and state in Python. Code like:

  def grow(array):
    array.append(1)

  array = []
  grow(array)
leads to such needless complexity.


I highly recommend this site: http://pythontutor.com/ It'll parse and execute python code, including showing what variables are pointing to what obects.


Since you explained name binding anyway, a useful way to describe Python might just be "call-by-binding".


I'm not too familiar with Python, but the semantics of Python described here match every other language that I can think of (including C). Can anyone give me an example of a language that is actually call-by-reference?


C++ supports call-by-reference (and also call-by-value), here's an example of call-by-reference:

    #include <iostream>
    void swap(int &x, int &y) {
      int temp = x;
      x = y;
      y = temp;
    }
    int main() {
      int a = 3;
      int b = 4;
      std::cout << a; // 3
      std::cout << b; // 4
      swap(a, b);
      std::cout << a; // 4
      std::cout << b; // 3
    }


Perl.


Perhaps this is a digression, but there are some misunderstandings in this blog post about the memory model in his C++ example. Since the author goes to lengths to be precise and exact in terminology and his explanations, it would be good to clarify some things.

For the example code C++ given:

    string some_guy = "Fred";
    // ...
    some_guy = "George";
Here is the author's explanation:

    In the above, the variable some_guy refers to a location in
    memory, and the value 'Fred' is inserted in that location (indeed,
    we can take the address of some_guy to determine the portion of
    memory to which it refers). Later, the contents of the memory
    location referred to by some_guy are changed to 'George'. The
    previous value no longer exists; it was overwritten. This likely
    matches your intuitive understanding (even if you don't program in
    C++).
There are several incorrect statements here.

A. "the variable some_guy refers to a location in memory, and the value 'Fred' is inserted in that location" Not true. The variable some_guy refers to a location in memory, but that location contains a pointer to a region of memory with the value "Fred". More on this in a bit.

B. "indeed, we can take the address of some_guy to determine the portion of memory to which it refers". Again, not true in the way the author probably intended. The address of 'some_guy' will be the address on the stack where the variable is located. The value at that address on the stack will be a pointer to a separate region of memory containing "Fred".

C. "Later, the contents of the memory location referred to by some_guy are changed to 'George'." To be precise, the contents of the memory location referred to by some_guy are changed to a new pointer to a different region of memory containing "George".

D. "the previous value no longer exists; it was overwritten." The values "Fred" and "George" exist through the entire lifetime of the program. They are string constants, which are compiled in to the data section of the program binary. The author is correct on one point: the value of 'some_guy' is overwritten during the reassignment. However, the value in this case is simply a pointer, not a string.

We can verify my claims experimentally. On my system (Ubuntu 11.04 32-bit, g++ 4.5.2), I wrote the following test program:

    //a.cpp
    #include <string>
    using namespace std;
    int main()
    {
      string some_guy = "Fred";
      some_guy = "George";
      return 0;
    }
Compile like this: $ g++ -O0 a.cpp -o a

Now, we can disassemble the "main" function to see exactly what is going on in the executable:

   $ objdump -d a
   a:     file format elf32-i386
   ...
   08048614 <main>:
    8048614:	55                   	push   %ebp
    8048615:	89 e5                	mov    %esp,%ebp
    8048617:	83 e4 f0             	and    $0xfffffff0,%esp
    804861a:	53                   	push   %ebx
    804861b:	83 ec 2c             	sub    $0x2c,%esp
    804861e:	8d 44 24 1f          	lea    0x1f(%esp),%eax
    8048622:	89 04 24             	mov    %eax,(%esp)
    8048625:	e8 06 ff ff ff       	call   8048530 <_ZNSaIcEC1Ev@plt>
    804862a:	8d 44 24 1f          	lea    0x1f(%esp),%eax
    804862e:	89 44 24 08          	mov    %eax,0x8(%esp)
    8048632:	c7 44 24 04 80 87 04 	movl   $0x8048780,0x4(%esp)
    8048639:	08 
    804863a:	8d 44 24 18          	lea    0x18(%esp),%eax
    804863e:	89 04 24             	mov    %eax,(%esp)
    8048641:	e8 ca fe ff ff       	call   8048510 <_ZNSsC1EPKcRKSaIcE@plt>
    8048646:	8d 44 24 1f          	lea    0x1f(%esp),%eax
    804864a:	89 04 24             	mov    %eax,(%esp)
    804864d:	e8 ce fe ff ff       	call   8048520 <_ZNSaIcED1Ev@plt>
    8048652:	c7 44 24 04 85 87 04 	movl   $0x8048785,0x4(%esp)
    ...
In this case, we are interested in the following two lines:

    8048632:	c7 44 24 04 80 87 04 	movl   $0x8048780,0x4(%esp)
and

    8048652:	c7 44 24 04 85 87 04 	movl   $0x8048785,0x4(%esp)
0x4(%esp) is the address on the stack of our 'some_guy' variable. We are moving an "immediate" (constant) value into that location. What does that immediate refer to? Again, let's find out experimentally:

    $ objdump -s -j .rodata a
    a:     file format elf32-i386
    Contents of section .rodata:
     8048778 03000000 01000200 46726564 0047656f  ........Fred.Geo
     8048788 72676500 00000000                    rge.....
Notice that the address of "Fred" is 0x8048778 + 8 = 0x8048780, which is exactly the immediate value from the disassembled main function.

This means that our variable "some_guy" really is a pointer, and nothing more. The strings "Fred" and "George" are statically allocated in the data section of the binary, meaning they stick around indefinitely.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: